package ecs import ( "context" "errors" "fmt" "time" "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/ecs" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" ) type stepConfigAlicloudVSwitch struct { VSwitchId string ZoneId string isCreate bool CidrBlock string VSwitchName string } func (s *stepConfigAlicloudVSwitch) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*ecs.Client) ui := state.Get("ui").(packer.Ui) vpcId := state.Get("vpcid").(string) config := state.Get("config").(*Config) if len(s.VSwitchId) != 0 { vswitchs, _, err := client.DescribeVSwitches(&ecs.DescribeVSwitchesArgs{ VpcId: vpcId, VSwitchId: s.VSwitchId, ZoneId: s.ZoneId, }) if err != nil { ui.Say(fmt.Sprintf("Failed querying vswitch: %s", err)) state.Put("error", err) return multistep.ActionHalt } if len(vswitchs) > 0 { vswitch := vswitchs[0] state.Put("vswitchid", vswitch.VSwitchId) s.isCreate = false return multistep.ActionContinue } s.isCreate = false message := fmt.Sprintf("The specified vswitch {%s} doesn't exist.", s.VSwitchId) state.Put("error", errors.New(message)) ui.Say(message) return multistep.ActionHalt } if s.ZoneId == "" { zones, err := client.DescribeZones(common.Region(config.AlicloudRegion)) if err != nil { ui.Say(fmt.Sprintf("Query for available zones failed: %s", err)) state.Put("error", err) return multistep.ActionHalt } var instanceTypes []string for _, zone := range zones { isVSwitchSupported := false for _, resourceType := range zone.AvailableResourceCreation.ResourceTypes { if resourceType == ecs.ResourceTypeVSwitch { 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 = "172.16.0.0/24" //use the default CirdBlock } ui.Say("Creating vswitch...") vswitchId, err := client.CreateVSwitch(&ecs.CreateVSwitchArgs{ CidrBlock: s.CidrBlock, ZoneId: s.ZoneId, VpcId: vpcId, VSwitchName: s.VSwitchName, }) if err != nil { state.Put("error", err) ui.Say(fmt.Sprintf("Create vswitch failed %v", err)) return multistep.ActionHalt } if err := client.WaitForVSwitchAvailable(vpcId, s.VSwitchId, ALICLOUD_DEFAULT_TIMEOUT); err != nil { state.Put("error", err) ui.Error(fmt.Sprintf("Timeout waiting for vswitch to become available: %v", err)) return multistep.ActionHalt } state.Put("vswitchid", vswitchId) s.isCreate = true s.VSwitchId = vswitchId return multistep.ActionContinue } func (s *stepConfigAlicloudVSwitch) Cleanup(state multistep.StateBag) { if !s.isCreate { return } client := state.Get("client").(*ecs.Client) ui := state.Get("ui").(packer.Ui) message(state, "vSwitch") timeoutPoint := time.Now().Add(10 * time.Second) for { if err := client.DeleteVSwitch(s.VSwitchId); err != nil { e, _ := err.(*common.Error) if (e.Code == "IncorrectVSwitchStatus" || e.Code == "DependencyViolation" || e.Code == "DependencyViolation.HaVip" || e.Code == "IncorrectRouteEntryStatus") && time.Now().Before(timeoutPoint) { time.Sleep(1 * time.Second) continue } ui.Error(fmt.Sprintf("Error deleting vswitch, it may still be around: %s", err)) return } break } }