From c58d6f9b33ec92a324a0699e424c1b5aa548bb5b Mon Sep 17 00:00:00 2001 From: Marin Salinas Date: Thu, 20 Aug 2020 20:37:09 -0500 Subject: [PATCH] refactor: migrate run vm step to new SDK --- builder/osc/bsu/builder.go | 5 +- builder/osc/bsu/step_create_omi.go | 3 +- builder/osc/common/block_device.go | 51 ++++++++++++ builder/osc/common/ssh.go | 2 +- builder/osc/common/state.go | 46 +++++++++++ builder/osc/common/step_cleanup_volumes.go | 7 +- builder/osc/common/step_get_password.go | 3 +- builder/osc/common/step_run_source_vm.go | 81 +++++++++++-------- builder/osc/common/step_stop_bsu_backed_vm.go | 3 +- 9 files changed, 158 insertions(+), 43 deletions(-) diff --git a/builder/osc/bsu/builder.go b/builder/osc/bsu/builder.go index dc2906244..e81c9d084 100644 --- a/builder/osc/bsu/builder.go +++ b/builder/osc/bsu/builder.go @@ -164,6 +164,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack UserData: b.config.UserData, UserDataFile: b.config.UserDataFile, VolumeTags: b.config.VolumeRunTags, + RawRegion: b.config.RawRegion, }, &osccommon.StepGetPassword{ Debug: b.config.PackerDebug, @@ -173,8 +174,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, &communicator.StepConnect{ Config: &b.config.RunConfig.Comm, - Host: osccommon.SSHHost( - oapiconn, + Host: osccommon.OscSSHHost( + oscConn.VmApi, b.config.SSHInterface), SSHConfig: b.config.RunConfig.Comm.SSHConfigFunc(), }, diff --git a/builder/osc/bsu/step_create_omi.go b/builder/osc/bsu/step_create_omi.go index 2ccd538e3..cb935d89d 100644 --- a/builder/osc/bsu/step_create_omi.go +++ b/builder/osc/bsu/step_create_omi.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" "github.com/outscale/osc-go/oapi" + "github.com/outscale/osc-sdk-go/osc" ) type stepCreateOMI struct { @@ -18,7 +19,7 @@ type stepCreateOMI struct { func (s *stepCreateOMI) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) oapiconn := state.Get("oapi").(*oapi.Client) - vm := state.Get("vm").(oapi.Vm) + vm := state.Get("vm").(osc.Vm) ui := state.Get("ui").(packer.Ui) // Create the image diff --git a/builder/osc/common/block_device.go b/builder/osc/common/block_device.go index 3f72076d5..7c0c90034 100644 --- a/builder/osc/common/block_device.go +++ b/builder/osc/common/block_device.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/hashicorp/packer/template/interpolate" "github.com/outscale/osc-go/oapi" + "github.com/outscale/osc-sdk-go/osc" ) // BlockDevice @@ -123,6 +124,52 @@ func buildBlockDevicesVmCreation(b []BlockDevice) []oapi.BlockDeviceMappingVmCre return blockDevices } +func buildOscBlockDevicesVmCreation(b []BlockDevice) []osc.BlockDeviceMappingVmCreation { + log.Printf("[DEBUG] Launch Block Device %#v", b) + + var blockDevices []osc.BlockDeviceMappingVmCreation + + for _, blockDevice := range b { + mapping := osc.BlockDeviceMappingVmCreation{ + DeviceName: blockDevice.DeviceName, + } + + if blockDevice.NoDevice { + mapping.NoDevice = "" + } else if blockDevice.VirtualName != "" { + if strings.HasPrefix(blockDevice.VirtualName, "ephemeral") { + mapping.VirtualDeviceName = blockDevice.VirtualName + } + } else { + bsu := osc.BsuToCreate{ + DeleteOnVmDeletion: blockDevice.DeleteOnVmDeletion, + } + + if blockDevice.VolumeType != "" { + bsu.VolumeType = blockDevice.VolumeType + } + + if blockDevice.VolumeSize > 0 { + bsu.VolumeSize = int32(blockDevice.VolumeSize) + } + + // IOPS is only valid for io1 type + if blockDevice.VolumeType == "io1" { + bsu.Iops = int32(blockDevice.IOPS) + } + + if blockDevice.SnapshotId != "" { + bsu.SnapshotId = blockDevice.SnapshotId + } + + mapping.Bsu = bsu + } + + blockDevices = append(blockDevices, mapping) + } + return blockDevices +} + func (b *BlockDevice) Prepare(ctx *interpolate.Context) error { if b.DeviceName == "" { return fmt.Errorf("The `device_name` must be specified " + @@ -152,3 +199,7 @@ func (b *OMIBlockDevices) BuildOMIDevices() []oapi.BlockDeviceMappingImage { func (b *LaunchBlockDevices) BuildLaunchDevices() []oapi.BlockDeviceMappingVmCreation { return buildBlockDevicesVmCreation(b.LaunchMappings) } + +func (b *LaunchBlockDevices) BuildOSCLaunchDevices() []osc.BlockDeviceMappingVmCreation { + return buildOscBlockDevicesVmCreation(b.LaunchMappings) +} diff --git a/builder/osc/common/ssh.go b/builder/osc/common/ssh.go index 55e39289f..f45473808 100644 --- a/builder/osc/common/ssh.go +++ b/builder/osc/common/ssh.go @@ -35,7 +35,7 @@ func SSHHost(e oapiDescriber, sshInterface string) func(multistep.StateBag) (str // <= with current structure to check result of describing `tries` times for j := 0; j <= tries; j++ { var host string - i := state.Get("vm").(oapi.Vm) + i := state.Get("vm").(osc.Vm) if sshInterface != "" { switch sshInterface { diff --git a/builder/osc/common/state.go b/builder/osc/common/state.go index b1d5bebaa..dd9ddc378 100644 --- a/builder/osc/common/state.go +++ b/builder/osc/common/state.go @@ -1,11 +1,14 @@ package common import ( + "context" "fmt" "log" + "github.com/antihax/optional" "github.com/hashicorp/packer/common" "github.com/outscale/osc-go/oapi" + "github.com/outscale/osc-sdk-go/osc" ) type stateRefreshFunc func() (string, error) @@ -24,12 +27,25 @@ func waitUntilForVmRunning(conn *oapi.Client, vmID string) error { return err } +func waitUntilForOscVmRunning(conn *osc.APIClient, vmID string) error { + errCh := make(chan error, 1) + go waitForState(errCh, "running", waitUntilOscVmStateFunc(conn, vmID)) + err := <-errCh + return err +} + func waitUntilVmDeleted(conn *oapi.Client, vmID string) error { errCh := make(chan error, 1) go waitForState(errCh, "terminated", waitUntilVmStateFunc(conn, vmID)) return <-errCh } +func waitUntilOscVmDeleted(conn *osc.APIClient, vmID string) error { + errCh := make(chan error, 1) + go waitForState(errCh, "terminated", waitUntilOscVmStateFunc(conn, vmID)) + return <-errCh +} + func waitUntilVmStopped(conn *oapi.Client, vmID string) error { errCh := make(chan error, 1) go waitForState(errCh, "stopped", waitUntilVmStateFunc(conn, vmID)) @@ -113,6 +129,36 @@ func waitUntilVmStateFunc(conn *oapi.Client, id string) stateRefreshFunc { } } +func waitUntilOscVmStateFunc(conn *osc.APIClient, id string) stateRefreshFunc { + return func() (string, error) { + log.Printf("[Debug] Retrieving state for VM with id %s", id) + resp, _, err := conn.VmApi.ReadVms(context.Background(), &osc.ReadVmsOpts{ + ReadVmsRequest: optional.NewInterface(osc.ReadVmsRequest{ + Filters: osc.FiltersVm{ + VmIds: []string{id}, + }, + }), + }) + + log.Printf("[Debug] Read Response %+v", resp) + + if err != nil { + return "", err + } + + //TODO: check if needed + // if resp == nil { + // return "", fmt.Errorf("Vm with ID %s not Found", id) + // } + + if len(resp.Vms) == 0 { + return "pending", nil + } + + return resp.Vms[0].State, nil + } +} + func waitUntilVolumeLinkedStateFunc(conn *oapi.Client, id string) stateRefreshFunc { return func() (string, error) { log.Printf("[Debug] Check if volume with id %s exists", id) diff --git a/builder/osc/common/step_cleanup_volumes.go b/builder/osc/common/step_cleanup_volumes.go index 9cce3df59..92bda011d 100644 --- a/builder/osc/common/step_cleanup_volumes.go +++ b/builder/osc/common/step_cleanup_volumes.go @@ -8,7 +8,6 @@ import ( "github.com/antihax/optional" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/outscale/osc-go/oapi" "github.com/outscale/osc-sdk-go/osc" ) @@ -29,9 +28,9 @@ func (s *StepCleanupVolumes) Run(_ context.Context, state multistep.StateBag) mu func (s *StepCleanupVolumes) Cleanup(state multistep.StateBag) { oscconn := state.Get("osc").(*osc.APIClient) vmRaw := state.Get("vm") - var vm oapi.Vm + var vm osc.Vm if vmRaw != nil { - vm = vmRaw.(oapi.Vm) + vm = vmRaw.(osc.Vm) } ui := state.Get("ui").(packer.Ui) if vm.VmId == "" { @@ -46,7 +45,7 @@ func (s *StepCleanupVolumes) Cleanup(state multistep.StateBag) { var vl []string volList := make(map[string]string) for _, bdm := range vm.BlockDeviceMappings { - if !reflect.DeepEqual(bdm.Bsu, oapi.BsuCreated{}) { + if !reflect.DeepEqual(bdm.Bsu, osc.BsuCreated{}) { vl = append(vl, bdm.Bsu.VolumeId) volList[bdm.Bsu.VolumeId] = bdm.DeviceName } diff --git a/builder/osc/common/step_get_password.go b/builder/osc/common/step_get_password.go index 9971379d5..178babc8c 100644 --- a/builder/osc/common/step_get_password.go +++ b/builder/osc/common/step_get_password.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" "github.com/outscale/osc-go/oapi" + "github.com/outscale/osc-sdk-go/osc" ) // StepGetPassword reads the password from a Windows server and sets it @@ -103,7 +104,7 @@ func (s *StepGetPassword) Cleanup(multistep.StateBag) {} func (s *StepGetPassword) waitForPassword(state multistep.StateBag, cancel <-chan struct{}) (string, error) { oapiconn := state.Get("oapi").(*oapi.Client) - vm := state.Get("vm").(oapi.Vm) + vm := state.Get("vm").(osc.Vm) privateKey := s.Comm.SSHPrivateKey for { diff --git a/builder/osc/common/step_run_source_vm.go b/builder/osc/common/step_run_source_vm.go index 7777e913c..f4c13604f 100644 --- a/builder/osc/common/step_run_source_vm.go +++ b/builder/osc/common/step_run_source_vm.go @@ -8,6 +8,7 @@ import ( "log" "reflect" + "github.com/antihax/optional" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/outscale/osc-go/oapi" "github.com/outscale/osc-sdk-go/osc" @@ -40,13 +41,13 @@ type StepRunSourceVm struct { UserData string UserDataFile string VolumeTags TagMap + RawRegion string vmId string } func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - oapiconn := state.Get("oapi").(*oapi.Client) - + oscconn := state.Get("osc").(*osc.APIClient) securityGroupIds := state.Get("securityGroupIds").([]string) ui := state.Get("ui").(packer.Ui) @@ -90,7 +91,9 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul s.Tags["Name"] = "Packer Builder" } - oapiTags, err := s.Tags.OAPITags(s.Ctx, oapiconn.GetConfig().Region, state) + rawRegion := s.RawRegion + + oscTags, err := s.Tags.OSCTags(s.Ctx, rawRegion, state) if err != nil { err := fmt.Errorf("Error tagging source vm: %s", err) state.Put("error", err) @@ -98,7 +101,7 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul return multistep.ActionHalt } - volTags, err := s.VolumeTags.OAPITags(s.Ctx, oapiconn.GetConfig().Region, state) + volTags, err := s.VolumeTags.OSCTags(s.Ctx, rawRegion, state) if err != nil { err := fmt.Errorf("Error tagging volumes: %s", err) state.Put("error", err) @@ -107,15 +110,15 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul } subregion := state.Get("subregion_name").(string) - runOpts := oapi.CreateVmsRequest{ + runOpts := osc.CreateVmsRequest{ ImageId: s.SourceOMI, VmType: s.VmType, UserData: userData, MaxVmsCount: 1, MinVmsCount: 1, - Placement: oapi.Placement{SubregionName: subregion}, + Placement: osc.Placement{SubregionName: subregion}, BsuOptimized: s.BsuOptimized, - BlockDeviceMappings: s.BlockDevices.BuildLaunchDevices(), + BlockDeviceMappings: s.BlockDevices.BuildOSCLaunchDevices(), //IamVmProfile: oapi.IamVmProfileSpecification{Name: &s.IamVmProfile}, } @@ -156,24 +159,27 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul runOpts.KeypairName = s.Comm.SSHKeyPairName } - subnetId := state.Get("subnet_id").(string) + subnetID := state.Get("subnet_id").(string) - runOpts.SubnetId = subnetId + runOpts.SubnetId = subnetID runOpts.SecurityGroupIds = securityGroupIds if s.ExpectedRootDevice == "bsu" { runOpts.VmInitiatedShutdownBehavior = s.VmInitiatedShutdownBehavior } - runResp, err := oapiconn.POST_CreateVms(runOpts) + runResp, _, err := oscconn.VmApi.CreateVms(context.Background(), &osc.CreateVmsOpts{ + CreateVmsRequest: optional.NewInterface(runOpts), + }) + if err != nil { err := fmt.Errorf("Error launching source vm: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } - vmId = runResp.OK.Vms[0].VmId - volumeId := runResp.OK.Vms[0].BlockDeviceMappings[0].Bsu.VolumeId + vmId = runResp.Vms[0].VmId + volumeId := runResp.Vms[0].BlockDeviceMappings[0].Bsu.VolumeId // Set the vm ID so that the cleanup works properly s.vmId = vmId @@ -181,12 +187,12 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul ui.Message(fmt.Sprintf("Vm ID: %s", vmId)) ui.Say(fmt.Sprintf("Waiting for vm (%v) to become ready...", vmId)) - request := oapi.ReadVmsRequest{ - Filters: oapi.FiltersVm{ + request := osc.ReadVmsRequest{ + Filters: osc.FiltersVm{ VmIds: []string{vmId}, }, } - if err := waitUntilForVmRunning(oapiconn, vmId); err != nil { + if err := waitUntilForOscVmRunning(oscconn, vmId); err != nil { err := fmt.Errorf("Error waiting for vm (%s) to become ready: %s", vmId, err) state.Put("error", err) ui.Error(err.Error()) @@ -194,8 +200,8 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul } //Set Vm tags and vollume tags - if len(oapiTags) > 0 { - if err := CreateTags(oapiconn, s.vmId, ui, oapiTags); err != nil { + if len(oscTags) > 0 { + if err := CreateOSCTags(oscconn, s.vmId, ui, oscTags); err != nil { err := fmt.Errorf("Error creating tags for vm (%s): %s", s.vmId, err) state.Put("error", err) ui.Error(err.Error()) @@ -204,7 +210,7 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul } if len(volTags) > 0 { - if err := CreateTags(oapiconn, volumeId, ui, volTags); err != nil { + if err := CreateOSCTags(oscconn, volumeId, ui, volTags); err != nil { err := fmt.Errorf("Error creating tags for volume (%s): %s", volumeId, err) state.Put("error", err) ui.Error(err.Error()) @@ -214,7 +220,9 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul if publicip_id, ok := state.Get("publicip_id").(string); ok { ui.Say(fmt.Sprintf("Linking temporary PublicIp %s to instance %s", publicip_id, vmId)) - _, err := oapiconn.POST_LinkPublicIp(oapi.LinkPublicIpRequest{PublicIpId: publicip_id, VmId: vmId}) + _, _, err := oscconn.PublicIpApi.LinkPublicIp(context.Background(), &osc.LinkPublicIpOpts{ + LinkPublicIpRequest: optional.NewInterface(osc.LinkPublicIpRequest{PublicIpId: publicip_id, VmId: vmId}), + }) if err != nil { state.Put("error", fmt.Errorf("Error linking PublicIp to VM: %s", err)) ui.Error(err.Error()) @@ -222,9 +230,11 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul } } - resp, err := oapiconn.POST_ReadVms(request) + resp, _, err := oscconn.VmApi.ReadVms(context.Background(), &osc.ReadVmsOpts{ + ReadVmsRequest: optional.NewInterface(request), + }) - r := resp.OK + r := resp if err != nil || len(r.Vms) == 0 { err := fmt.Errorf("Error finding source vm.") @@ -257,12 +267,14 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul // do that now. if s.IsRestricted { - oapiTags.Report(ui) + oscTags.Report(ui) // Retry creating tags for about 2.5 minutes err = retry.Retry(0.2, 30, 11, func(_ uint) (bool, error) { - _, err := oapiconn.POST_CreateTags(oapi.CreateTagsRequest{ - Tags: oapiTags, - ResourceIds: []string{vmId}, + _, _, err := oscconn.TagApi.CreateTags(context.Background(), &osc.CreateTagsOpts{ + CreateTagsRequest: optional.NewInterface(osc.CreateTagsRequest{ + Tags: oscTags, + ResourceIds: []string{vmId}, + }), }) if err == nil { return true, nil @@ -295,7 +307,7 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul if len(volumeIds) > 0 && s.VolumeTags.IsSet() { ui.Say("Adding tags to source BSU Volumes") - volumeTags, err := s.VolumeTags.OAPITags(s.Ctx, oapiconn.GetConfig().Region, state) + volumeTags, err := s.VolumeTags.OSCTags(s.Ctx, rawRegion, state) if err != nil { err := fmt.Errorf("Error tagging source BSU Volumes on %s: %s", vm.VmId, err) state.Put("error", err) @@ -304,9 +316,11 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul } volumeTags.Report(ui) - _, err = oapiconn.POST_CreateTags(oapi.CreateTagsRequest{ - ResourceIds: volumeIds, - Tags: volumeTags, + _, _, err = oscconn.TagApi.CreateTags(context.Background(), &osc.CreateTagsOpts{ + CreateTagsRequest: optional.NewInterface(osc.CreateTagsRequest{ + ResourceIds: volumeIds, + Tags: volumeTags, + }), }) if err != nil { @@ -322,19 +336,20 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul } func (s *StepRunSourceVm) Cleanup(state multistep.StateBag) { - - oapiconn := state.Get("oapi").(*oapi.Client) + oscconn := state.Get("osc").(*osc.APIClient) ui := state.Get("ui").(packer.Ui) // Terminate the source vm if it exists if s.vmId != "" { ui.Say("Terminating the source OUTSCALE vm...") - if _, err := oapiconn.POST_DeleteVms(oapi.DeleteVmsRequest{VmIds: []string{s.vmId}}); err != nil { + if _, _, err := oscconn.VmApi.DeleteVms(context.Background(), &osc.DeleteVmsOpts{ + DeleteVmsRequest: optional.NewInterface(osc.DeleteVmsRequest{VmIds: []string{s.vmId}}), + }); err != nil { ui.Error(fmt.Sprintf("Error terminating vm, may still be around: %s", err)) return } - if err := waitUntilVmDeleted(oapiconn, s.vmId); err != nil { + if err := waitUntilOscVmDeleted(oscconn, s.vmId); err != nil { ui.Error(err.Error()) } } diff --git a/builder/osc/common/step_stop_bsu_backed_vm.go b/builder/osc/common/step_stop_bsu_backed_vm.go index 02076d35d..79bd693c8 100644 --- a/builder/osc/common/step_stop_bsu_backed_vm.go +++ b/builder/osc/common/step_stop_bsu_backed_vm.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" "github.com/outscale/osc-go/oapi" + "github.com/outscale/osc-sdk-go/osc" ) type StepStopBSUBackedVm struct { @@ -18,7 +19,7 @@ type StepStopBSUBackedVm struct { func (s *StepStopBSUBackedVm) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { oapiconn := state.Get("oapi").(*oapi.Client) - vm := state.Get("vm").(oapi.Vm) + vm := state.Get("vm").(osc.Vm) ui := state.Get("ui").(packer.Ui) // Skip when it is a spot vm