github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/common/step_cleanup_volumes.go (about) 1 package common 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/aws/aws-sdk-go/aws" 8 "github.com/aws/aws-sdk-go/service/ec2" 9 "github.com/hashicorp/packer/helper/multistep" 10 "github.com/hashicorp/packer/packer" 11 ) 12 13 // stepCleanupVolumes cleans up any orphaned volumes that were not designated to 14 // remain after termination of the instance. These volumes are typically ones 15 // that are marked as "delete on terminate:false" in the source_ami of a build. 16 type StepCleanupVolumes struct { 17 BlockDevices BlockDevices 18 } 19 20 func (s *StepCleanupVolumes) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { 21 // stepCleanupVolumes is for Cleanup only 22 return multistep.ActionContinue 23 } 24 25 func (s *StepCleanupVolumes) Cleanup(state multistep.StateBag) { 26 ec2conn := state.Get("ec2").(*ec2.EC2) 27 instanceRaw := state.Get("instance") 28 var instance *ec2.Instance 29 if instanceRaw != nil { 30 instance = instanceRaw.(*ec2.Instance) 31 } 32 ui := state.Get("ui").(packer.Ui) 33 if instance == nil { 34 ui.Say("No volumes to clean up, skipping") 35 return 36 } 37 38 ui.Say("Cleaning up any extra volumes...") 39 40 // Collect Volume information from the cached Instance as a map of volume-id 41 // to device name, to compare with save list below 42 var vl []*string 43 volList := make(map[string]string) 44 for _, bdm := range instance.BlockDeviceMappings { 45 if bdm.Ebs != nil { 46 vl = append(vl, bdm.Ebs.VolumeId) 47 volList[*bdm.Ebs.VolumeId] = *bdm.DeviceName 48 } 49 } 50 51 // Using the volume list from the cached Instance, check with AWS for up to 52 // date information on them 53 resp, err := ec2conn.DescribeVolumes(&ec2.DescribeVolumesInput{ 54 Filters: []*ec2.Filter{ 55 { 56 Name: aws.String("volume-id"), 57 Values: vl, 58 }, 59 }, 60 }) 61 62 if err != nil { 63 ui.Say(fmt.Sprintf("Error describing volumes: %s", err)) 64 return 65 } 66 67 // If any of the returned volumes are in a "deleting" stage or otherwise not 68 // available, remove them from the list of volumes 69 for _, v := range resp.Volumes { 70 if v.State != nil && *v.State != "available" { 71 delete(volList, *v.VolumeId) 72 } 73 } 74 75 if len(resp.Volumes) == 0 { 76 ui.Say("No volumes to clean up, skipping") 77 return 78 } 79 80 // Filter out any devices created as part of the launch mappings, since 81 // we'll let amazon follow the `delete_on_termination` setting. 82 for _, b := range s.BlockDevices.LaunchMappings { 83 for volKey, volName := range volList { 84 if volName == b.DeviceName { 85 delete(volList, volKey) 86 } 87 } 88 } 89 90 // Destroy remaining volumes 91 for k := range volList { 92 ui.Say(fmt.Sprintf("Destroying volume (%s)...", k)) 93 _, err := ec2conn.DeleteVolume(&ec2.DeleteVolumeInput{VolumeId: aws.String(k)}) 94 if err != nil { 95 ui.Say(fmt.Sprintf("Error deleting volume: %s", err)) 96 } 97 98 } 99 }