yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/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 aliyun 16 17 import ( 18 "fmt" 19 "strconv" 20 "strings" 21 "time" 22 23 "yunion.io/x/log" 24 ) 25 26 type TaskStatusType string 27 28 type TaskActionType string 29 30 const ( 31 ImportImageTask = TaskActionType("ImportImage") 32 ExportImageTask = TaskActionType("ExportImage") 33 34 // Finished:已完成 35 // Processing:运行中 36 // Waiting:多任务排队中 37 // Deleted:已取消 38 // Paused:暂停 39 // Failed:失败 40 TaskStatusFinished = TaskStatusType("Finished") 41 TaskStatusProcessing = TaskStatusType("Processing") 42 TaskStatusWaiting = TaskStatusType("Waiting") 43 TaskStatusDeleted = TaskStatusType("Deleted") 44 TaskStatusPaused = TaskStatusType("Paused") 45 TaskStatusFailed = TaskStatusType("Failed") 46 ) 47 48 type STask struct { 49 TaskId string 50 TaskStatus TaskStatusType 51 TaskAction string 52 SupportCancel bool 53 FinishedTime time.Time 54 CreationTime time.Time 55 } 56 57 func (self *SRegion) WaitTaskStatus(action TaskActionType, taskId string, targetStatus TaskStatusType, interval time.Duration, timeout time.Duration, min, max int8, progress func(float32)) error { 58 start := time.Now() 59 for time.Now().Sub(start) < timeout { 60 status, percent, err := self.GetTaskStatus(action, taskId) 61 if err != nil { 62 return err 63 } 64 if progress != nil { 65 progress(float32(min) + float32(float64(max-min)*float64(percent)/100)) 66 } 67 if status == targetStatus { 68 progress(float32(max)) 69 return nil 70 } 71 time.Sleep(interval) 72 } 73 return fmt.Errorf("timeout for waitting task %s(%s) after %f minutes", taskId, action, timeout.Minutes()) 74 } 75 76 func (self *SRegion) waitTaskStatus(action TaskActionType, taskId string, targetStatus TaskStatusType, interval time.Duration, timeout time.Duration) error { 77 return self.WaitTaskStatus(action, taskId, targetStatus, interval, timeout, 0, 0, nil) 78 } 79 80 func (self *SRegion) GetTaskStatus(action TaskActionType, taskId string) (TaskStatusType, int8, error) { 81 task, err := self.GetTask(taskId) 82 if err != nil { 83 return "", 0, err 84 } 85 progress, _ := strconv.Atoi(strings.TrimSuffix(task.TaskProcess, "%")) 86 return task.TaskStatus, int8(progress), nil 87 } 88 89 func (self *SRegion) GetTasks(action TaskActionType, taskId []string, taskStatus TaskStatusType, offset int, limit int) ([]STask, int, error) { 90 if limit > 50 || limit <= 0 { 91 limit = 50 92 } 93 94 params := make(map[string]string) 95 params["RegionId"] = self.RegionId 96 params["PageSize"] = fmt.Sprintf("%d", limit) 97 params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) 98 99 params["TaskAction"] = string(action) 100 if taskId != nil && len(taskId) > 0 { 101 params["TaskIds"] = strings.Join(taskId, ",") 102 } 103 if len(taskStatus) > 0 { 104 params["TaskStatus"] = string(taskStatus) 105 } 106 107 body, err := self.ecsRequest("DescribeTasks", params) 108 if err != nil { 109 log.Errorf("GetTasks fail %s", err) 110 return nil, 0, err 111 } 112 113 log.Infof("%s", body) 114 tasks := make([]STask, 0) 115 err = body.Unmarshal(&tasks, "TaskSet", "Task") 116 if err != nil { 117 log.Errorf("Unmarshal task fail %s", err) 118 return nil, 0, err 119 } 120 total, _ := body.Int("TotalCount") 121 return tasks, int(total), nil 122 } 123 124 type STaskError struct { 125 ErrorCode string 126 ErrorMsg string 127 OperationStatus string 128 } 129 130 type STaskDetail struct { 131 CreationTime time.Time 132 FailedCount int 133 FinishedTime time.Time 134 RegionId string 135 OperationProgressSet map[string][]STaskError 136 RequestId string 137 SuccessCount int 138 SupportCancel bool 139 TaskAction string 140 TaskId string 141 TaskProcess string 142 TaskStatus TaskStatusType 143 TotalCount int 144 } 145 146 func (self *SRegion) GetTask(taskId string) (*STaskDetail, error) { 147 params := map[string]string{ 148 "RegionId": self.RegionId, 149 "TaskId": taskId, 150 } 151 body, err := self.ecsRequest("DescribeTaskAttribute", params) 152 if err != nil { 153 return nil, err 154 } 155 log.Infof("%s", body) 156 detail := &STaskDetail{} 157 return detail, body.Unmarshal(detail) 158 } 159 160 func (self *SRegion) CancelTask(taskId string) error { 161 params := map[string]string{ 162 "RegionId": self.RegionId, 163 "TaskId": taskId, 164 } 165 _, err := self.ecsRequest("CancelTask", params) 166 return err 167 } 168 169 func (region *SRegion) CancelImageImportTasks() error { 170 tasks, _, _ := region.GetTasks(ImportImageTask, []string{}, TaskStatusProcessing, 0, 50) 171 for i := 0; i < len(tasks); i++ { 172 task, err := region.GetTask(tasks[i].TaskId) 173 if err != nil { 174 log.Errorf("failed get task %s %s error: %v", tasks[i].CreationTime, tasks[i].TaskId, err) 175 } 176 if task != nil { 177 log.Debugf("task info: %s(%s) cancelable %t process %s", task.TaskId, task.CreationTime, task.SupportCancel, task.TaskProcess) 178 } else { 179 log.Debugf("task info: %s(%s) cancelable %t", tasks[i].TaskId, tasks[i].CreationTime, tasks[i].SupportCancel) 180 } 181 if tasks[i].SupportCancel { 182 err := region.CancelTask(tasks[i].TaskId) 183 if err != nil { 184 return fmt.Errorf("failed to cancel task %s error: %v", tasks[i].TaskId, err) 185 } 186 } 187 } 188 return nil 189 }