278 lines
6.6 KiB
Go
278 lines
6.6 KiB
Go
package ecs
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
|
|
"time"
|
|
)
|
|
|
|
type ClientWrapper struct {
|
|
*ecs.Client
|
|
}
|
|
|
|
const (
|
|
InstanceStatusRunning = "Running"
|
|
InstanceStatusStarting = "Starting"
|
|
InstanceStatusStopped = "Stopped"
|
|
InstanceStatusStopping = "Stopping"
|
|
)
|
|
|
|
const (
|
|
ImageStatusWaiting = "Waiting"
|
|
ImageStatusCreating = "Creating"
|
|
ImageStatusCreateFailed = "CreateFailed"
|
|
ImageStatusAvailable = "Available"
|
|
)
|
|
|
|
var ImageStatusQueried = fmt.Sprintf("%s,%s,%s,%s", ImageStatusWaiting, ImageStatusCreating, ImageStatusCreateFailed, ImageStatusAvailable)
|
|
|
|
const (
|
|
SnapshotStatusAll = "all"
|
|
SnapshotStatusProgressing = "progressing"
|
|
SnapshotStatusAccomplished = "accomplished"
|
|
SnapshotStatusFailed = "failed"
|
|
)
|
|
|
|
const (
|
|
DiskStatusInUse = "In_use"
|
|
DiskStatusAvailable = "Available"
|
|
DiskStatusAttaching = "Attaching"
|
|
DiskStatusDetaching = "Detaching"
|
|
DiskStatusCreating = "Creating"
|
|
DiskStatusReIniting = "ReIniting"
|
|
)
|
|
|
|
const (
|
|
VpcStatusPending = "Pending"
|
|
VpcStatusAvailable = "Available"
|
|
)
|
|
|
|
const (
|
|
VSwitchStatusPending = "Pending"
|
|
VSwitchStatusAvailable = "Available"
|
|
)
|
|
|
|
const (
|
|
EipStatusAssociating = "Associating"
|
|
EipStatusUnassociating = "Unassociating"
|
|
EipStatusInUse = "InUse"
|
|
EipStatusAvailable = "Available"
|
|
)
|
|
|
|
const (
|
|
ImageOwnerSystem = "system"
|
|
ImageOwnerSelf = "self"
|
|
ImageOwnerOthers = "others"
|
|
ImageOwnerMarketplace = "marketplace"
|
|
)
|
|
|
|
const (
|
|
IOOptimizedNone = "none"
|
|
IOOptimizedOptimized = "optimized"
|
|
)
|
|
|
|
const (
|
|
InstanceNetworkClassic = "classic"
|
|
InstanceNetworkVpc = "vpc"
|
|
)
|
|
|
|
const (
|
|
DiskTypeSystem = "system"
|
|
DiskTypeData = "data"
|
|
)
|
|
|
|
const (
|
|
TagResourceImage = "image"
|
|
TagResourceInstance = "instance"
|
|
TagResourceSnapshot = "snapshot"
|
|
TagResourceDisk = "disk"
|
|
)
|
|
|
|
const (
|
|
IpProtocolAll = "all"
|
|
IpProtocolTCP = "tcp"
|
|
IpProtocolUDP = "udp"
|
|
IpProtocolICMP = "icmp"
|
|
IpProtocolGRE = "gre"
|
|
)
|
|
|
|
const (
|
|
NicTypeInternet = "internet"
|
|
NicTypeIntranet = "intranet"
|
|
)
|
|
|
|
const (
|
|
DefaultPortRange = "-1/-1"
|
|
DefaultCidrIp = "0.0.0.0/0"
|
|
DefaultCidrBlock = "172.16.0.0/24"
|
|
)
|
|
|
|
const (
|
|
defaultRetryInterval = 5 * time.Second
|
|
defaultRetryTimes = 12
|
|
shortRetryTimes = 36
|
|
mediumRetryTimes = 360
|
|
longRetryTimes = 720
|
|
)
|
|
|
|
type WaitForExpectEvalResult struct {
|
|
evalPass bool
|
|
stopRetry bool
|
|
}
|
|
|
|
var (
|
|
WaitForExpectSuccess = WaitForExpectEvalResult{
|
|
evalPass: true,
|
|
stopRetry: true,
|
|
}
|
|
|
|
WaitForExpectToRetry = WaitForExpectEvalResult{
|
|
evalPass: false,
|
|
stopRetry: false,
|
|
}
|
|
|
|
WaitForExpectFailToStop = WaitForExpectEvalResult{
|
|
evalPass: false,
|
|
stopRetry: true,
|
|
}
|
|
)
|
|
|
|
type WaitForExpectArgs struct {
|
|
RequestFunc func() (responses.AcsResponse, error)
|
|
EvalFunc func(response responses.AcsResponse, err error) WaitForExpectEvalResult
|
|
RetryInterval time.Duration
|
|
RetryTimes int
|
|
RetryTimeout time.Duration
|
|
}
|
|
|
|
func (c *ClientWrapper) WaitForExpected(args *WaitForExpectArgs) (responses.AcsResponse, error) {
|
|
if args.RetryInterval <= 0 {
|
|
args.RetryInterval = defaultRetryInterval
|
|
}
|
|
if args.RetryTimes <= 0 {
|
|
args.RetryTimes = defaultRetryTimes
|
|
}
|
|
|
|
var timeoutPoint time.Time
|
|
if args.RetryTimeout > 0 {
|
|
timeoutPoint = time.Now().Add(args.RetryTimeout)
|
|
}
|
|
|
|
var lastError error
|
|
|
|
for i := 0; ; i++ {
|
|
if args.RetryTimeout > 0 && time.Now().After(timeoutPoint) {
|
|
break
|
|
}
|
|
|
|
if args.RetryTimeout <= 0 && i >= args.RetryTimes {
|
|
break
|
|
}
|
|
|
|
response, err := args.RequestFunc()
|
|
lastError = err
|
|
|
|
evalResult := args.EvalFunc(response, err)
|
|
if evalResult.evalPass {
|
|
return response, nil
|
|
}
|
|
if evalResult.stopRetry {
|
|
return nil, err
|
|
}
|
|
|
|
time.Sleep(args.RetryInterval)
|
|
}
|
|
|
|
if args.RetryTimeout > 0 {
|
|
return nil, fmt.Errorf("evaluate failed after %d seconds timeout with %d seconds retry interval: %s", int(args.RetryTimeout.Seconds()), int(args.RetryInterval.Seconds()), lastError)
|
|
}
|
|
|
|
return nil, fmt.Errorf("evaluate failed after %d times retry with %d seconds retry interval: %s", args.RetryTimes, int(args.RetryInterval.Seconds()), lastError)
|
|
}
|
|
|
|
func (c *ClientWrapper) WaitForInstanceStatus(regionId string, instanceId string, expectedStatus string) (responses.AcsResponse, error) {
|
|
return c.WaitForExpected(&WaitForExpectArgs{
|
|
RequestFunc: func() (responses.AcsResponse, error) {
|
|
request := ecs.CreateDescribeInstancesRequest()
|
|
request.RegionId = regionId
|
|
request.InstanceIds = fmt.Sprintf("[\"%s\"]", instanceId)
|
|
return c.DescribeInstances(request)
|
|
},
|
|
EvalFunc: func(response responses.AcsResponse, err error) WaitForExpectEvalResult {
|
|
if err != nil {
|
|
return WaitForExpectToRetry
|
|
}
|
|
|
|
instancesResponse := response.(*ecs.DescribeInstancesResponse)
|
|
instances := instancesResponse.Instances.Instance
|
|
for _, instance := range instances {
|
|
if instance.Status == expectedStatus {
|
|
return WaitForExpectSuccess
|
|
}
|
|
}
|
|
return WaitForExpectToRetry
|
|
},
|
|
RetryTimes: mediumRetryTimes,
|
|
})
|
|
}
|
|
|
|
func (c *ClientWrapper) WaitForImageStatus(regionId string, imageId string, expectedStatus string, timeout time.Duration) (responses.AcsResponse, error) {
|
|
return c.WaitForExpected(&WaitForExpectArgs{
|
|
RequestFunc: func() (responses.AcsResponse, error) {
|
|
request := ecs.CreateDescribeImagesRequest()
|
|
request.RegionId = regionId
|
|
request.ImageId = imageId
|
|
request.Status = ImageStatusQueried
|
|
return c.DescribeImages(request)
|
|
},
|
|
EvalFunc: func(response responses.AcsResponse, err error) WaitForExpectEvalResult {
|
|
if err != nil {
|
|
return WaitForExpectToRetry
|
|
}
|
|
|
|
imagesResponse := response.(*ecs.DescribeImagesResponse)
|
|
images := imagesResponse.Images.Image
|
|
for _, image := range images {
|
|
if image.Status == expectedStatus {
|
|
return WaitForExpectSuccess
|
|
}
|
|
}
|
|
|
|
return WaitForExpectToRetry
|
|
},
|
|
RetryTimeout: timeout,
|
|
})
|
|
}
|
|
|
|
type EvalErrorType bool
|
|
|
|
const (
|
|
EvalRetryErrorType = EvalErrorType(true)
|
|
EvalNotRetryErrorType = EvalErrorType(false)
|
|
)
|
|
|
|
func (c *ClientWrapper) EvalCouldRetryResponse(evalErrors []string, evalErrorType EvalErrorType) func(response responses.AcsResponse, err error) WaitForExpectEvalResult {
|
|
return func(response responses.AcsResponse, err error) WaitForExpectEvalResult {
|
|
if err == nil {
|
|
return WaitForExpectSuccess
|
|
}
|
|
|
|
e, ok := err.(errors.Error)
|
|
if !ok {
|
|
return WaitForExpectToRetry
|
|
}
|
|
|
|
if evalErrorType == EvalRetryErrorType && !ContainsInArray(evalErrors, e.ErrorCode()) {
|
|
return WaitForExpectFailToStop
|
|
}
|
|
|
|
if evalErrorType == EvalNotRetryErrorType && ContainsInArray(evalErrors, e.ErrorCode()) {
|
|
return WaitForExpectFailToStop
|
|
}
|
|
|
|
return WaitForExpectToRetry
|
|
}
|
|
}
|