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  }