github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/builder/amazon/ebs/step_cleanup_volumes.go (about) 1 package ebs 2 3 import ( 4 "fmt" 5 6 "github.com/aws/aws-sdk-go/aws" 7 "github.com/aws/aws-sdk-go/service/ec2" 8 "github.com/mitchellh/multistep" 9 "github.com/mitchellh/packer/builder/amazon/common" 10 "github.com/mitchellh/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 common.BlockDevices 18 } 19 20 func (s *stepCleanupVolumes) Run(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 // We don't actually care about the value here, but we need Set behavior 41 save := make(map[string]struct{}) 42 for _, b := range s.BlockDevices.AMIMappings { 43 if !b.DeleteOnTermination { 44 save[b.DeviceName] = struct{}{} 45 } 46 } 47 48 for _, b := range s.BlockDevices.LaunchMappings { 49 if !b.DeleteOnTermination { 50 save[b.DeviceName] = struct{}{} 51 } 52 } 53 54 // Collect Volume information from the cached Instance as a map of volume-id 55 // to device name, to compare with save list above 56 var vl []*string 57 volList := make(map[string]string) 58 for _, bdm := range instance.BlockDeviceMappings { 59 if bdm.Ebs != nil { 60 vl = append(vl, bdm.Ebs.VolumeId) 61 volList[*bdm.Ebs.VolumeId] = *bdm.DeviceName 62 } 63 } 64 65 // Using the volume list from the cached Instance, check with AWS for up to 66 // date information on them 67 resp, err := ec2conn.DescribeVolumes(&ec2.DescribeVolumesInput{ 68 Filters: []*ec2.Filter{ 69 { 70 Name: aws.String("volume-id"), 71 Values: vl, 72 }, 73 }, 74 }) 75 76 if err != nil { 77 ui.Say(fmt.Sprintf("Error describing volumes: %s", err)) 78 return 79 } 80 81 // If any of the returned volumes are in a "deleting" stage or otherwise not 82 // available, remove them from the list of volumes 83 for _, v := range resp.Volumes { 84 if v.State != nil && *v.State != "available" { 85 delete(volList, *v.VolumeId) 86 } 87 } 88 89 if len(resp.Volumes) == 0 { 90 ui.Say("No volumes to clean up, skipping") 91 return 92 } 93 94 // Filter out any devices marked for saving 95 for saveName := range save { 96 for volKey, volName := range volList { 97 if volName == saveName { 98 delete(volList, volKey) 99 } 100 } 101 } 102 103 // Destroy remaining volumes 104 for k := range volList { 105 ui.Say(fmt.Sprintf("Destroying volume (%s)...", k)) 106 _, err := ec2conn.DeleteVolume(&ec2.DeleteVolumeInput{VolumeId: aws.String(k)}) 107 if err != nil { 108 ui.Say(fmt.Sprintf("Error deleting volume: %s", k)) 109 } 110 111 } 112 }