From cb3699a58410cfcc85b1fb13988f0194a0e816d8 Mon Sep 17 00:00:00 2001 From: Joseph Wright Date: Sun, 25 Mar 2018 19:25:53 -0400 Subject: [PATCH 1/2] Modify ebssurrogate builder to snapshot all launch devices Documentation for ebssurrogate states that all of the devices in `launch_block_device_mappings` are snapshotted and included in the image. In fact, only the device that was designated as the root device was snapshotted. This patch modifies the builder to create snapshots of all the devices and include them in the image. This allows creating images with separate filesystems preconfigured, rather than having to add volumes to `ami_block_device_mappings` and configure them after boot. --- builder/amazon/ebssurrogate/builder.go | 10 +- .../amazon/ebssurrogate/root_block_device.go | 20 -- .../amazon/ebssurrogate/step_register_ami.go | 46 +++- .../ebssurrogate/step_register_ami_test.go | 252 ++++++++++++++++-- .../ebssurrogate/step_snapshot_new_root.go | 103 ------- .../ebssurrogate/step_snapshot_volumes.go | 129 +++++++++ 6 files changed, 399 insertions(+), 161 deletions(-) delete mode 100644 builder/amazon/ebssurrogate/step_snapshot_new_root.go create mode 100644 builder/amazon/ebssurrogate/step_snapshot_volumes.go diff --git a/builder/amazon/ebssurrogate/builder.go b/builder/amazon/ebssurrogate/builder.go index b990c5758..002560602 100644 --- a/builder/amazon/ebssurrogate/builder.go +++ b/builder/amazon/ebssurrogate/builder.go @@ -176,6 +176,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } } + amiDevices := b.config.BuildAMIDevices() + launchDevices := b.config.BuildLaunchDevices() + // Build the steps steps := []multistep.Step{ &awscommon.StepPreValidate{ @@ -227,8 +230,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe EnableAMISriovNetSupport: b.config.AMISriovNetSupport, EnableAMIENASupport: b.config.AMIENASupport, }, - &StepSnapshotNewRootVolume{ - NewRootMountPoint: b.config.RootDevice.SourceDeviceName, + &StepSnapshotVolumes{ + LaunchDevices: launchDevices, }, &awscommon.StepDeregisterAMI{ AccessConfig: &b.config.AccessConfig, @@ -239,7 +242,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &StepRegisterAMI{ RootDevice: b.config.RootDevice, - BlockDevices: b.config.BlockDevices.BuildAMIDevices(), + AMIDevices: amiDevices, + LaunchDevices: launchDevices, EnableAMISriovNetSupport: b.config.AMISriovNetSupport, EnableAMIENASupport: b.config.AMIENASupport, }, diff --git a/builder/amazon/ebssurrogate/root_block_device.go b/builder/amazon/ebssurrogate/root_block_device.go index 7e34b3733..09c13ca00 100644 --- a/builder/amazon/ebssurrogate/root_block_device.go +++ b/builder/amazon/ebssurrogate/root_block_device.go @@ -3,8 +3,6 @@ package ebssurrogate import ( "errors" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/packer/template/interpolate" ) @@ -46,21 +44,3 @@ func (c *RootBlockDevice) Prepare(ctx *interpolate.Context) []error { return nil } - -func (d *RootBlockDevice) createBlockDeviceMapping(snapshotId string) *ec2.BlockDeviceMapping { - rootBlockDevice := &ec2.EbsBlockDevice{ - SnapshotId: aws.String(snapshotId), - VolumeType: aws.String(d.VolumeType), - VolumeSize: aws.Int64(d.VolumeSize), - DeleteOnTermination: aws.Bool(d.DeleteOnTermination), - } - - if d.IOPS != 0 { - rootBlockDevice.Iops = aws.Int64(d.IOPS) - } - - return &ec2.BlockDeviceMapping{ - DeviceName: aws.String(d.DeviceName), - Ebs: rootBlockDevice, - } -} diff --git a/builder/amazon/ebssurrogate/step_register_ami.go b/builder/amazon/ebssurrogate/step_register_ami.go index 002ed00af..4c12adca6 100644 --- a/builder/amazon/ebssurrogate/step_register_ami.go +++ b/builder/amazon/ebssurrogate/step_register_ami.go @@ -14,7 +14,8 @@ import ( // StepRegisterAMI creates the AMI. type StepRegisterAMI struct { RootDevice RootBlockDevice - BlockDevices []*ec2.BlockDeviceMapping + AMIDevices []*ec2.BlockDeviceMapping + LaunchDevices []*ec2.BlockDeviceMapping EnableAMIENASupport bool EnableAMISriovNetSupport bool image *ec2.Image @@ -23,19 +24,19 @@ type StepRegisterAMI struct { func (s *StepRegisterAMI) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) ec2conn := state.Get("ec2").(*ec2.EC2) - snapshotId := state.Get("snapshot_id").(string) + snapshotIds := state.Get("snapshot_ids").(map[string]string) ui := state.Get("ui").(packer.Ui) ui.Say("Registering the AMI...") - blockDevicesExcludingRoot := DeduplicateRootVolume(s.BlockDevices, s.RootDevice, snapshotId) + blockDevices := s.combineDevices(snapshotIds) registerOpts := &ec2.RegisterImageInput{ Name: &config.AMIName, Architecture: aws.String(ec2.ArchitectureValuesX8664), RootDeviceName: aws.String(s.RootDevice.DeviceName), VirtualizationType: aws.String(config.AMIVirtType), - BlockDeviceMappings: blockDevicesExcludingRoot, + BlockDeviceMappings: blockDevices, } if s.EnableAMISriovNetSupport { @@ -120,17 +121,34 @@ func (s *StepRegisterAMI) Cleanup(state multistep.StateBag) { } } -func DeduplicateRootVolume(BlockDevices []*ec2.BlockDeviceMapping, RootDevice RootBlockDevice, snapshotId string) []*ec2.BlockDeviceMapping { - // Defensive coding to make sure we only add the root volume once - blockDevicesExcludingRoot := make([]*ec2.BlockDeviceMapping, 0, len(BlockDevices)) - for _, blockDevice := range BlockDevices { - if *blockDevice.DeviceName == RootDevice.SourceDeviceName { - continue - } +func (s *StepRegisterAMI) combineDevices(snapshotIds map[string]string) []*ec2.BlockDeviceMapping { + devices := map[string]*ec2.BlockDeviceMapping{} + + for _, device := range s.AMIDevices { + devices[*device.DeviceName] = device + } - blockDevicesExcludingRoot = append(blockDevicesExcludingRoot, blockDevice) + // Devices in launch_block_device_mappings override any with + // the same name in ami_block_device_mappings, except for the + // one designated as the root device in ami_root_device + for _, device := range s.LaunchDevices { + snapshotId, ok := snapshotIds[*device.DeviceName] + if ok { + device.Ebs.SnapshotId = aws.String(snapshotId) + // Block devices with snapshot inherit + // encryption settings from the snapshot + device.Ebs.Encrypted = nil + device.Ebs.KmsKeyId = nil + } + if *device.DeviceName == s.RootDevice.SourceDeviceName { + device.DeviceName = aws.String(s.RootDevice.DeviceName) + } + devices[*device.DeviceName] = device } - blockDevicesExcludingRoot = append(blockDevicesExcludingRoot, RootDevice.createBlockDeviceMapping(snapshotId)) - return blockDevicesExcludingRoot + blockDevices := []*ec2.BlockDeviceMapping{} + for _, device := range devices { + blockDevices = append(blockDevices, device) + } + return blockDevices } diff --git a/builder/amazon/ebssurrogate/step_register_ami_test.go b/builder/amazon/ebssurrogate/step_register_ami_test.go index b2abd7827..10872bb86 100644 --- a/builder/amazon/ebssurrogate/step_register_ami_test.go +++ b/builder/amazon/ebssurrogate/step_register_ami_test.go @@ -1,37 +1,247 @@ package ebssurrogate import ( + "reflect" + "sort" "testing" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" ) -func GetStringPointer() *string { - tmp := "/dev/name" - return &tmp -} +const sourceDeviceName = "/dev/xvdf" +const rootDeviceName = "/dev/xvda" -func GetTestDevice() *ec2.BlockDeviceMapping { - TestDev := ec2.BlockDeviceMapping{ - DeviceName: GetStringPointer(), +func newStepRegisterAMI(amiDevices, launchDevices []*ec2.BlockDeviceMapping) *StepRegisterAMI { + return &StepRegisterAMI{ + RootDevice: RootBlockDevice{ + SourceDeviceName: sourceDeviceName, + DeviceName: rootDeviceName, + DeleteOnTermination: true, + VolumeType: "ebs", + VolumeSize: 10, + }, + AMIDevices: amiDevices, + LaunchDevices: launchDevices, } - return &TestDev } -func TestStepRegisterAmi_DeduplicateRootVolume(t *testing.T) { - TestRootDevice := RootBlockDevice{} - TestRootDevice.SourceDeviceName = "/dev/name" +func sorted(devices []*ec2.BlockDeviceMapping) []*ec2.BlockDeviceMapping { + sort.SliceStable(devices, func(i, j int) bool { + return *devices[i].DeviceName < *devices[j].DeviceName + }) + return devices +} - blockDevices := []*ec2.BlockDeviceMapping{} - blockDevicesExcludingRoot := DeduplicateRootVolume(blockDevices, TestRootDevice, "12342351") - if len(blockDevicesExcludingRoot) != 1 { - t.Fatalf("Unexpected length of block devices list") +func TestStepRegisterAmi_combineDevices(t *testing.T) { + cases := []struct { + snapshotIds map[string]string + amiDevices []*ec2.BlockDeviceMapping + launchDevices []*ec2.BlockDeviceMapping + allDevices []*ec2.BlockDeviceMapping + }{ + { + snapshotIds: map[string]string{}, + amiDevices: []*ec2.BlockDeviceMapping{}, + launchDevices: []*ec2.BlockDeviceMapping{}, + allDevices: []*ec2.BlockDeviceMapping{}, + }, + { + snapshotIds: map[string]string{}, + amiDevices: []*ec2.BlockDeviceMapping{}, + launchDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{}, + DeviceName: aws.String(sourceDeviceName), + }, + }, + allDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{}, + DeviceName: aws.String(rootDeviceName), + }, + }, + }, + { + // Minimal single device + snapshotIds: map[string]string{ + sourceDeviceName: "snap-0123456789abcdef1", + }, + amiDevices: []*ec2.BlockDeviceMapping{}, + launchDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{}, + DeviceName: aws.String(sourceDeviceName), + }, + }, + allDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + SnapshotId: aws.String("snap-0123456789abcdef1"), + }, + DeviceName: aws.String(rootDeviceName), + }, + }, + }, + { + // Single launch device with AMI device + snapshotIds: map[string]string{ + sourceDeviceName: "snap-0123456789abcdef1", + }, + amiDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{}, + DeviceName: aws.String("/dev/xvdg"), + }, + }, + launchDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{}, + DeviceName: aws.String(sourceDeviceName), + }, + }, + allDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + SnapshotId: aws.String("snap-0123456789abcdef1"), + }, + DeviceName: aws.String(rootDeviceName), + }, + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{}, + DeviceName: aws.String("/dev/xvdg"), + }, + }, + }, + { + // Multiple launch devices + snapshotIds: map[string]string{ + sourceDeviceName: "snap-0123456789abcdef1", + "/dev/xvdg": "snap-0123456789abcdef2", + }, + amiDevices: []*ec2.BlockDeviceMapping{}, + launchDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{}, + DeviceName: aws.String(sourceDeviceName), + }, + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{}, + DeviceName: aws.String("/dev/xvdg"), + }, + }, + allDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + SnapshotId: aws.String("snap-0123456789abcdef1"), + }, + DeviceName: aws.String(rootDeviceName), + }, + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + SnapshotId: aws.String("snap-0123456789abcdef2"), + }, + DeviceName: aws.String("/dev/xvdg"), + }, + }, + }, + { + // Multiple launch devices with encryption + snapshotIds: map[string]string{ + sourceDeviceName: "snap-0123456789abcdef1", + "/dev/xvdg": "snap-0123456789abcdef2", + }, + amiDevices: []*ec2.BlockDeviceMapping{}, + launchDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + Encrypted: aws.Bool(true), + }, + DeviceName: aws.String(sourceDeviceName), + }, + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + Encrypted: aws.Bool(true), + }, + DeviceName: aws.String("/dev/xvdg"), + }, + }, + allDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + SnapshotId: aws.String("snap-0123456789abcdef1"), + // Encrypted: true stripped from snapshotted devices + }, + DeviceName: aws.String(rootDeviceName), + }, + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + SnapshotId: aws.String("snap-0123456789abcdef2"), + }, + DeviceName: aws.String("/dev/xvdg"), + }, + }, + }, + { + // Multiple launch devices and AMI devices with encryption + snapshotIds: map[string]string{ + sourceDeviceName: "snap-0123456789abcdef1", + "/dev/xvdg": "snap-0123456789abcdef2", + }, + amiDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + Encrypted: aws.Bool(true), + KmsKeyId: aws.String("keyId"), + }, + // Source device name can be used in AMI devices + // since launch device of same name gets renamed + // to root device name + DeviceName: aws.String(sourceDeviceName), + }, + }, + launchDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + Encrypted: aws.Bool(true), + }, + DeviceName: aws.String(sourceDeviceName), + }, + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + Encrypted: aws.Bool(true), + }, + DeviceName: aws.String("/dev/xvdg"), + }, + }, + allDevices: []*ec2.BlockDeviceMapping{ + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + Encrypted: aws.Bool(true), + KmsKeyId: aws.String("keyId"), + }, + DeviceName: aws.String(sourceDeviceName), + }, + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + SnapshotId: aws.String("snap-0123456789abcdef1"), + }, + DeviceName: aws.String(rootDeviceName), + }, + &ec2.BlockDeviceMapping{ + Ebs: &ec2.EbsBlockDevice{ + SnapshotId: aws.String("snap-0123456789abcdef2"), + }, + DeviceName: aws.String("/dev/xvdg"), + }, + }, + }, } - - TestBlockDevice := GetTestDevice() - blockDevices = append(blockDevices, TestBlockDevice) - blockDevicesExcludingRoot = DeduplicateRootVolume(blockDevices, TestRootDevice, "12342351") - if len(blockDevicesExcludingRoot) != 1 { - t.Fatalf("Unexpected length of block devices list") + for _, tc := range cases { + stepRegisterAmi := newStepRegisterAMI(tc.amiDevices, tc.launchDevices) + allDevices := stepRegisterAmi.combineDevices(tc.snapshotIds) + if !reflect.DeepEqual(sorted(allDevices), sorted(tc.allDevices)) { + t.Fatalf("Unexpected output from combineDevices") + } } } diff --git a/builder/amazon/ebssurrogate/step_snapshot_new_root.go b/builder/amazon/ebssurrogate/step_snapshot_new_root.go deleted file mode 100644 index 3b607fbd0..000000000 --- a/builder/amazon/ebssurrogate/step_snapshot_new_root.go +++ /dev/null @@ -1,103 +0,0 @@ -package ebssurrogate - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/aws/aws-sdk-go/service/ec2" - awscommon "github.com/hashicorp/packer/builder/amazon/common" - "github.com/hashicorp/packer/helper/multistep" - "github.com/hashicorp/packer/packer" -) - -// StepSnapshotNewRootVolume creates a snapshot of the created volume. -// -// Produces: -// snapshot_id string - ID of the created snapshot -type StepSnapshotNewRootVolume struct { - NewRootMountPoint string - snapshotId string -} - -func (s *StepSnapshotNewRootVolume) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ec2conn := state.Get("ec2").(*ec2.EC2) - ui := state.Get("ui").(packer.Ui) - instance := state.Get("instance").(*ec2.Instance) - - var newRootVolume string - for _, volume := range instance.BlockDeviceMappings { - if *volume.DeviceName == s.NewRootMountPoint { - newRootVolume = *volume.Ebs.VolumeId - } - } - - ui.Say(fmt.Sprintf("Creating snapshot of EBS Volume %s...", newRootVolume)) - description := fmt.Sprintf("Packer: %s", time.Now().String()) - - createSnapResp, err := ec2conn.CreateSnapshot(&ec2.CreateSnapshotInput{ - VolumeId: &newRootVolume, - Description: &description, - }) - if err != nil { - err := fmt.Errorf("Error creating snapshot: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - // Set the snapshot ID so we can delete it later - s.snapshotId = *createSnapResp.SnapshotId - ui.Message(fmt.Sprintf("Snapshot ID: %s", s.snapshotId)) - - // Wait for the snapshot to be ready - stateChange := awscommon.StateChangeConf{ - Pending: []string{"pending"}, - StepState: state, - Target: "completed", - Refresh: func() (interface{}, string, error) { - resp, err := ec2conn.DescribeSnapshots(&ec2.DescribeSnapshotsInput{SnapshotIds: []*string{&s.snapshotId}}) - if err != nil { - return nil, "", err - } - - if len(resp.Snapshots) == 0 { - return nil, "", errors.New("No snapshots found.") - } - - s := resp.Snapshots[0] - return s, *s.State, nil - }, - } - - _, err = awscommon.WaitForState(&stateChange) - if err != nil { - err := fmt.Errorf("Error waiting for snapshot: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - state.Put("snapshot_id", s.snapshotId) - return multistep.ActionContinue -} - -func (s *StepSnapshotNewRootVolume) Cleanup(state multistep.StateBag) { - if s.snapshotId == "" { - return - } - - _, cancelled := state.GetOk(multistep.StateCancelled) - _, halted := state.GetOk(multistep.StateHalted) - - if cancelled || halted { - ec2conn := state.Get("ec2").(*ec2.EC2) - ui := state.Get("ui").(packer.Ui) - ui.Say("Removing snapshot since we cancelled or halted...") - _, err := ec2conn.DeleteSnapshot(&ec2.DeleteSnapshotInput{SnapshotId: &s.snapshotId}) - if err != nil { - ui.Error(fmt.Sprintf("Error: %s", err)) - } - } -} diff --git a/builder/amazon/ebssurrogate/step_snapshot_volumes.go b/builder/amazon/ebssurrogate/step_snapshot_volumes.go new file mode 100644 index 000000000..9de755ca5 --- /dev/null +++ b/builder/amazon/ebssurrogate/step_snapshot_volumes.go @@ -0,0 +1,129 @@ +package ebssurrogate + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "github.com/aws/aws-sdk-go/service/ec2" + multierror "github.com/hashicorp/go-multierror" + awscommon "github.com/hashicorp/packer/builder/amazon/common" + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" +) + +// StepSnapshotVolumes creates snapshots of the created volumes. +// +// Produces: +// snapshot_ids map[string]string - IDs of the created snapshots +type StepSnapshotVolumes struct { + LaunchDevices []*ec2.BlockDeviceMapping + snapshotIds map[string]string +} + +func (s *StepSnapshotVolumes) snapshotVolume(deviceName string, state multistep.StateBag) error { + ec2conn := state.Get("ec2").(*ec2.EC2) + ui := state.Get("ui").(packer.Ui) + instance := state.Get("instance").(*ec2.Instance) + + var volumeId string + for _, volume := range instance.BlockDeviceMappings { + if *volume.DeviceName == deviceName { + volumeId = *volume.Ebs.VolumeId + } + } + if volumeId == "" { + return fmt.Errorf("Volume ID for device %s not found", deviceName) + } + + ui.Say(fmt.Sprintf("Creating snapshot of EBS Volume %s...", volumeId)) + description := fmt.Sprintf("Packer: %s", time.Now().String()) + + createSnapResp, err := ec2conn.CreateSnapshot(&ec2.CreateSnapshotInput{ + VolumeId: &volumeId, + Description: &description, + }) + if err != nil { + return err + } + + // Set the snapshot ID so we can delete it later + s.snapshotIds[deviceName] = *createSnapResp.SnapshotId + + // Wait for the snapshot to be ready + stateChange := awscommon.StateChangeConf{ + Pending: []string{"pending"}, + StepState: state, + Target: "completed", + Refresh: func() (interface{}, string, error) { + resp, err := ec2conn.DescribeSnapshots(&ec2.DescribeSnapshotsInput{ + SnapshotIds: []*string{createSnapResp.SnapshotId}, + }) + if err != nil { + return nil, "", err + } + + if len(resp.Snapshots) == 0 { + return nil, "", errors.New("No snapshots found.") + } + + s := resp.Snapshots[0] + return s, *s.State, nil + }, + } + + _, err = awscommon.WaitForState(&stateChange) + return err +} + +func (s *StepSnapshotVolumes) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + + s.snapshotIds = map[string]string{} + + var wg sync.WaitGroup + var errs *multierror.Error + for _, device := range s.LaunchDevices { + wg.Add(1) + go func(device *ec2.BlockDeviceMapping) { + defer wg.Done() + if err := s.snapshotVolume(*device.DeviceName, state); err != nil { + errs = multierror.Append(errs, err) + } + }(device) + } + + wg.Wait() + + if errs != nil { + state.Put("error", errs) + ui.Error(errs.Error()) + return multistep.ActionHalt + } + + state.Put("snapshot_ids", s.snapshotIds) + return multistep.ActionContinue +} + +func (s *StepSnapshotVolumes) Cleanup(state multistep.StateBag) { + if len(s.snapshotIds) == 0 { + return + } + + _, cancelled := state.GetOk(multistep.StateCancelled) + _, halted := state.GetOk(multistep.StateHalted) + + if cancelled || halted { + ec2conn := state.Get("ec2").(*ec2.EC2) + ui := state.Get("ui").(packer.Ui) + ui.Say("Removing snapshots since we cancelled or halted...") + for _, snapshotId := range s.snapshotIds { + _, err := ec2conn.DeleteSnapshot(&ec2.DeleteSnapshotInput{SnapshotId: &snapshotId}) + if err != nil { + ui.Error(fmt.Sprintf("Error: %s", err)) + } + } + } +} From 1913517d29bdc20bb421d2dcb354a0c704a3e6e9 Mon Sep 17 00:00:00 2001 From: Joseph Wright Date: Sun, 25 Mar 2018 19:51:49 -0400 Subject: [PATCH 2/2] Fix formatting by running `make fmt` --- .../ebssurrogate/step_register_ami_test.go | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/builder/amazon/ebssurrogate/step_register_ami_test.go b/builder/amazon/ebssurrogate/step_register_ami_test.go index 10872bb86..d2ef67685 100644 --- a/builder/amazon/ebssurrogate/step_register_ami_test.go +++ b/builder/amazon/ebssurrogate/step_register_ami_test.go @@ -50,13 +50,13 @@ func TestStepRegisterAmi_combineDevices(t *testing.T) { snapshotIds: map[string]string{}, amiDevices: []*ec2.BlockDeviceMapping{}, launchDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{}, DeviceName: aws.String(sourceDeviceName), }, }, allDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{}, DeviceName: aws.String(rootDeviceName), }, @@ -69,13 +69,13 @@ func TestStepRegisterAmi_combineDevices(t *testing.T) { }, amiDevices: []*ec2.BlockDeviceMapping{}, launchDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{}, DeviceName: aws.String(sourceDeviceName), }, }, allDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ SnapshotId: aws.String("snap-0123456789abcdef1"), }, @@ -89,25 +89,25 @@ func TestStepRegisterAmi_combineDevices(t *testing.T) { sourceDeviceName: "snap-0123456789abcdef1", }, amiDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{}, DeviceName: aws.String("/dev/xvdg"), }, }, launchDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{}, DeviceName: aws.String(sourceDeviceName), }, }, allDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ SnapshotId: aws.String("snap-0123456789abcdef1"), }, DeviceName: aws.String(rootDeviceName), }, - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{}, DeviceName: aws.String("/dev/xvdg"), }, @@ -121,23 +121,23 @@ func TestStepRegisterAmi_combineDevices(t *testing.T) { }, amiDevices: []*ec2.BlockDeviceMapping{}, launchDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{}, DeviceName: aws.String(sourceDeviceName), }, - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{}, DeviceName: aws.String("/dev/xvdg"), }, }, allDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ SnapshotId: aws.String("snap-0123456789abcdef1"), }, DeviceName: aws.String(rootDeviceName), }, - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ SnapshotId: aws.String("snap-0123456789abcdef2"), }, @@ -153,13 +153,13 @@ func TestStepRegisterAmi_combineDevices(t *testing.T) { }, amiDevices: []*ec2.BlockDeviceMapping{}, launchDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ Encrypted: aws.Bool(true), }, DeviceName: aws.String(sourceDeviceName), }, - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ Encrypted: aws.Bool(true), }, @@ -167,14 +167,14 @@ func TestStepRegisterAmi_combineDevices(t *testing.T) { }, }, allDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ SnapshotId: aws.String("snap-0123456789abcdef1"), // Encrypted: true stripped from snapshotted devices }, DeviceName: aws.String(rootDeviceName), }, - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ SnapshotId: aws.String("snap-0123456789abcdef2"), }, @@ -189,7 +189,7 @@ func TestStepRegisterAmi_combineDevices(t *testing.T) { "/dev/xvdg": "snap-0123456789abcdef2", }, amiDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ Encrypted: aws.Bool(true), KmsKeyId: aws.String("keyId"), @@ -201,13 +201,13 @@ func TestStepRegisterAmi_combineDevices(t *testing.T) { }, }, launchDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ Encrypted: aws.Bool(true), }, DeviceName: aws.String(sourceDeviceName), }, - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ Encrypted: aws.Bool(true), }, @@ -215,20 +215,20 @@ func TestStepRegisterAmi_combineDevices(t *testing.T) { }, }, allDevices: []*ec2.BlockDeviceMapping{ - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ Encrypted: aws.Bool(true), KmsKeyId: aws.String("keyId"), }, DeviceName: aws.String(sourceDeviceName), }, - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ SnapshotId: aws.String("snap-0123456789abcdef1"), }, DeviceName: aws.String(rootDeviceName), }, - &ec2.BlockDeviceMapping{ + { Ebs: &ec2.EbsBlockDevice{ SnapshotId: aws.String("snap-0123456789abcdef2"), },