207 lines
6.0 KiB
Go
207 lines
6.0 KiB
Go
package ecs
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
|
|
"github.com/hashicorp/packer/common/uuid"
|
|
"github.com/hashicorp/packer/helper/multistep"
|
|
"github.com/hashicorp/packer/packer"
|
|
)
|
|
|
|
type stepConfigAlicloudVSwitch struct {
|
|
VSwitchId string
|
|
ZoneId string
|
|
isCreate bool
|
|
CidrBlock string
|
|
VSwitchName string
|
|
}
|
|
|
|
var createVSwitchRetryErrors = []string{
|
|
"TOKEN_PROCESSING",
|
|
}
|
|
|
|
var deleteVSwitchRetryErrors = []string{
|
|
"IncorrectVSwitchStatus",
|
|
"DependencyViolation",
|
|
"DependencyViolation.HaVip",
|
|
"IncorrectRouteEntryStatus",
|
|
"TaskConflict",
|
|
}
|
|
|
|
func (s *stepConfigAlicloudVSwitch) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
|
client := state.Get("client").(*ClientWrapper)
|
|
ui := state.Get("ui").(packer.Ui)
|
|
vpcId := state.Get("vpcid").(string)
|
|
config := state.Get("config").(*Config)
|
|
|
|
if len(s.VSwitchId) != 0 {
|
|
describeVSwitchesRequest := ecs.CreateDescribeVSwitchesRequest()
|
|
describeVSwitchesRequest.VpcId = vpcId
|
|
describeVSwitchesRequest.VSwitchId = s.VSwitchId
|
|
describeVSwitchesRequest.ZoneId = s.ZoneId
|
|
|
|
vswitchesResponse, err := client.DescribeVSwitches(describeVSwitchesRequest)
|
|
if err != nil {
|
|
return halt(state, err, "Failed querying vswitch")
|
|
}
|
|
|
|
vswitch := vswitchesResponse.VSwitches.VSwitch
|
|
if len(vswitch) > 0 {
|
|
state.Put("vswitchid", vswitch[0].VSwitchId)
|
|
s.isCreate = false
|
|
return multistep.ActionContinue
|
|
}
|
|
|
|
s.isCreate = false
|
|
return halt(state, fmt.Errorf("The specified vswitch {%s} doesn't exist.", s.VSwitchId), "")
|
|
}
|
|
|
|
if s.ZoneId == "" {
|
|
describeZonesRequest := ecs.CreateDescribeZonesRequest()
|
|
describeZonesRequest.RegionId = config.AlicloudRegion
|
|
|
|
zonesResponse, err := client.DescribeZones(describeZonesRequest)
|
|
if err != nil {
|
|
return halt(state, err, "Query for available zones failed")
|
|
}
|
|
|
|
var instanceTypes []string
|
|
zones := zonesResponse.Zones.Zone
|
|
for _, zone := range zones {
|
|
isVSwitchSupported := false
|
|
for _, resourceType := range zone.AvailableResourceCreation.ResourceTypes {
|
|
if resourceType == "VSwitch" {
|
|
isVSwitchSupported = true
|
|
}
|
|
}
|
|
|
|
if isVSwitchSupported {
|
|
for _, instanceType := range zone.AvailableInstanceTypes.InstanceTypes {
|
|
if instanceType == config.InstanceType {
|
|
s.ZoneId = zone.ZoneId
|
|
break
|
|
}
|
|
instanceTypes = append(instanceTypes, instanceType)
|
|
}
|
|
}
|
|
}
|
|
|
|
if s.ZoneId == "" {
|
|
if len(instanceTypes) > 0 {
|
|
ui.Say(fmt.Sprintf("The instance type %s isn't available in this region."+
|
|
"\n You can either change the instance to one of following: %v \n"+
|
|
"or choose another region.", config.InstanceType, instanceTypes))
|
|
|
|
state.Put("error", fmt.Errorf("The instance type %s isn't available in this region."+
|
|
"\n You can either change the instance to one of following: %v \n"+
|
|
"or choose another region.", config.InstanceType, instanceTypes))
|
|
return multistep.ActionHalt
|
|
} else {
|
|
ui.Say(fmt.Sprintf("The instance type %s isn't available in this region."+
|
|
"\n You can change to other regions.", config.InstanceType))
|
|
|
|
state.Put("error", fmt.Errorf("The instance type %s isn't available in this region."+
|
|
"\n You can change to other regions.", config.InstanceType))
|
|
return multistep.ActionHalt
|
|
}
|
|
}
|
|
}
|
|
|
|
if config.CidrBlock == "" {
|
|
s.CidrBlock = DefaultCidrBlock //use the default CirdBlock
|
|
}
|
|
|
|
ui.Say("Creating vswitch...")
|
|
|
|
createVSwitchRequest := s.buildCreateVSwitchRequest(state)
|
|
createVSwitchResponse, err := client.WaitForExpected(&WaitForExpectArgs{
|
|
RequestFunc: func() (responses.AcsResponse, error) {
|
|
return client.CreateVSwitch(createVSwitchRequest)
|
|
},
|
|
EvalFunc: client.EvalCouldRetryResponse(createVSwitchRetryErrors, EvalRetryErrorType),
|
|
})
|
|
if err != nil {
|
|
return halt(state, err, "Error Creating vswitch")
|
|
}
|
|
|
|
vSwitchId := createVSwitchResponse.(*ecs.CreateVSwitchResponse).VSwitchId
|
|
|
|
describeVSwitchesRequest := ecs.CreateDescribeVSwitchesRequest()
|
|
describeVSwitchesRequest.VpcId = vpcId
|
|
describeVSwitchesRequest.VSwitchId = vSwitchId
|
|
|
|
_, err = client.WaitForExpected(&WaitForExpectArgs{
|
|
RequestFunc: func() (responses.AcsResponse, error) {
|
|
return client.DescribeVSwitches(describeVSwitchesRequest)
|
|
},
|
|
EvalFunc: func(response responses.AcsResponse, err error) WaitForExpectEvalResult {
|
|
if err != nil {
|
|
return WaitForExpectToRetry
|
|
}
|
|
|
|
vSwitchesResponse := response.(*ecs.DescribeVSwitchesResponse)
|
|
vSwitches := vSwitchesResponse.VSwitches.VSwitch
|
|
if len(vSwitches) > 0 {
|
|
for _, vSwitch := range vSwitches {
|
|
if vSwitch.Status == VSwitchStatusAvailable {
|
|
return WaitForExpectSuccess
|
|
}
|
|
}
|
|
}
|
|
|
|
return WaitForExpectToRetry
|
|
},
|
|
RetryTimes: shortRetryTimes,
|
|
})
|
|
|
|
if err != nil {
|
|
return halt(state, err, "Timeout waiting for vswitch to become available")
|
|
}
|
|
|
|
ui.Message(fmt.Sprintf("Created vswitch: %s", vSwitchId))
|
|
state.Put("vswitchid", vSwitchId)
|
|
s.isCreate = true
|
|
s.VSwitchId = vSwitchId
|
|
return multistep.ActionContinue
|
|
}
|
|
|
|
func (s *stepConfigAlicloudVSwitch) Cleanup(state multistep.StateBag) {
|
|
if !s.isCreate {
|
|
return
|
|
}
|
|
|
|
cleanUpMessage(state, "vSwitch")
|
|
|
|
client := state.Get("client").(*ClientWrapper)
|
|
ui := state.Get("ui").(packer.Ui)
|
|
|
|
_, err := client.WaitForExpected(&WaitForExpectArgs{
|
|
RequestFunc: func() (responses.AcsResponse, error) {
|
|
request := ecs.CreateDeleteVSwitchRequest()
|
|
request.VSwitchId = s.VSwitchId
|
|
return client.DeleteVSwitch(request)
|
|
},
|
|
EvalFunc: client.EvalCouldRetryResponse(deleteVSwitchRetryErrors, EvalRetryErrorType),
|
|
RetryTimes: shortRetryTimes,
|
|
})
|
|
|
|
if err != nil {
|
|
ui.Error(fmt.Sprintf("Error deleting vswitch, it may still be around: %s", err))
|
|
}
|
|
}
|
|
|
|
func (s *stepConfigAlicloudVSwitch) buildCreateVSwitchRequest(state multistep.StateBag) *ecs.CreateVSwitchRequest {
|
|
vpcId := state.Get("vpcid").(string)
|
|
|
|
request := ecs.CreateCreateVSwitchRequest()
|
|
request.ClientToken = uuid.TimeOrderedUUID()
|
|
request.CidrBlock = s.CidrBlock
|
|
request.ZoneId = s.ZoneId
|
|
request.VpcId = vpcId
|
|
request.VSwitchName = s.VSwitchName
|
|
|
|
return request
|
|
}
|