yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/apsara/task.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package apsara 16 17 import ( 18 "fmt" 19 "strings" 20 "time" 21 22 "yunion.io/x/log" 23 ) 24 25 type TaskStatusType string 26 27 type TaskActionType string 28 29 const ( 30 ImportImageTask = TaskActionType("ImportImage") 31 ExportImageTask = TaskActionType("ExportImage") 32 33 // Finished:已完成 34 // Processing:运行中 35 // Waiting:多任务排队中 36 // Deleted:已取消 37 // Paused:暂停 38 // Failed:失败 39 TaskStatusFinished = TaskStatusType("Finished") 40 TaskStatusProcessing = TaskStatusType("Processing") 41 TaskStatusWaiting = TaskStatusType("Waiting") 42 TaskStatusDeleted = TaskStatusType("Deleted") 43 TaskStatusPaused = TaskStatusType("Paused") 44 TaskStatusFailed = TaskStatusType("Failed") 45 ) 46 47 type STask struct { 48 TaskId string 49 TaskStatus TaskStatusType 50 TaskAction string 51 SupportCancel bool 52 FinishedTime time.Time 53 CreationTime time.Time 54 } 55 56 func (self *SRegion) waitTaskStatus(action TaskActionType, taskId string, targetStatus TaskStatusType, interval time.Duration, timeout time.Duration) error { 57 start := time.Now() 58 for time.Now().Sub(start) < timeout { 59 status, err := self.GetTaskStatus(action, taskId) 60 if err != nil { 61 return err 62 } 63 if status == targetStatus { 64 return nil 65 } 66 time.Sleep(interval) 67 } 68 return fmt.Errorf("timeout for waitting task %s(%s) after %f minutes", taskId, action, timeout.Minutes()) 69 } 70 71 func (self *SRegion) GetTaskStatus(action TaskActionType, taskId string) (TaskStatusType, error) { 72 task, err := self.GetTask(taskId) 73 if err != nil { 74 return "", err 75 } 76 return task.TaskStatus, nil 77 } 78 79 func (self *SRegion) GetTasks(action TaskActionType, taskId []string, taskStatus TaskStatusType, offset int, limit int) ([]STask, int, error) { 80 if limit > 50 || limit <= 0 { 81 limit = 50 82 } 83 84 params := make(map[string]string) 85 params["RegionId"] = self.RegionId 86 params["PageSize"] = fmt.Sprintf("%d", limit) 87 params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) 88 89 params["TaskAction"] = string(action) 90 if taskId != nil && len(taskId) > 0 { 91 params["TaskIds"] = strings.Join(taskId, ",") 92 } 93 if len(taskStatus) > 0 { 94 params["TaskStatus"] = string(taskStatus) 95 } 96 97 body, err := self.ecsRequest("DescribeTasks", params) 98 if err != nil { 99 log.Errorf("GetTasks fail %s", err) 100 return nil, 0, err 101 } 102 103 log.Infof("%s", body) 104 tasks := make([]STask, 0) 105 err = body.Unmarshal(&tasks, "TaskSet", "Task") 106 if err != nil { 107 log.Errorf("Unmarshal task fail %s", err) 108 return nil, 0, err 109 } 110 total, _ := body.Int("TotalCount") 111 return tasks, int(total), nil 112 } 113 114 type STaskError struct { 115 ErrorCode string 116 ErrorMsg string 117 OperationStatus string 118 } 119 120 type STaskDetail struct { 121 CreationTime time.Time 122 FailedCount int 123 FinishedTime time.Time 124 RegionId string 125 OperationProgressSet map[string][]STaskError 126 RequestId string 127 SuccessCount int 128 SupportCancel bool 129 TaskAction string 130 TaskId string 131 TaskProcess string 132 TaskStatus TaskStatusType 133 TotalCount int 134 } 135 136 func (self *SRegion) GetTask(taskId string) (*STaskDetail, error) { 137 params := map[string]string{ 138 "RegionId": self.RegionId, 139 "TaskId": taskId, 140 } 141 body, err := self.ecsRequest("DescribeTaskAttribute", params) 142 if err != nil { 143 return nil, err 144 } 145 log.Infof("%s", body) 146 detail := &STaskDetail{} 147 return detail, body.Unmarshal(detail) 148 } 149 150 func (self *SRegion) CancelTask(taskId string) error { 151 params := map[string]string{ 152 "RegionId": self.RegionId, 153 "TaskId": taskId, 154 } 155 _, err := self.ecsRequest("CancelTask", params) 156 return err 157 } 158 159 func (region *SRegion) CancelImageImportTasks() error { 160 tasks, _, _ := region.GetTasks(ImportImageTask, []string{}, TaskStatusProcessing, 0, 50) 161 for i := 0; i < len(tasks); i++ { 162 task, err := region.GetTask(tasks[i].TaskId) 163 if err != nil { 164 log.Errorf("failed get task %s %s error: %v", tasks[i].CreationTime, tasks[i].TaskId, err) 165 } 166 if task != nil { 167 log.Debugf("task info: %s(%s) cancelable %t process %s", task.TaskId, task.CreationTime, task.SupportCancel, task.TaskProcess) 168 } else { 169 log.Debugf("task info: %s(%s) cancelable %t", tasks[i].TaskId, tasks[i].CreationTime, tasks[i].SupportCancel) 170 } 171 if tasks[i].SupportCancel { 172 err := region.CancelTask(tasks[i].TaskId) 173 if err != nil { 174 return fmt.Errorf("failed to cancel task %s error: %v", tasks[i].TaskId, err) 175 } 176 } 177 } 178 return nil 179 }