github.com/rothwerx/packer@v0.9.0/builder/amazon/chroot/step_create_volume.go (about) 1 package chroot 2 3 import ( 4 "fmt" 5 "log" 6 7 "github.com/aws/aws-sdk-go/aws" 8 "github.com/aws/aws-sdk-go/service/ec2" 9 "github.com/mitchellh/multistep" 10 awscommon "github.com/mitchellh/packer/builder/amazon/common" 11 "github.com/mitchellh/packer/packer" 12 ) 13 14 // StepCreateVolume creates a new volume from the snapshot of the root 15 // device of the AMI. 16 // 17 // Produces: 18 // volume_id string - The ID of the created volume 19 type StepCreateVolume struct { 20 volumeId string 21 RootVolumeSize int64 22 } 23 24 func (s *StepCreateVolume) Run(state multistep.StateBag) multistep.StepAction { 25 ec2conn := state.Get("ec2").(*ec2.EC2) 26 image := state.Get("source_image").(*ec2.Image) 27 instance := state.Get("instance").(*ec2.Instance) 28 ui := state.Get("ui").(packer.Ui) 29 30 // Determine the root device snapshot 31 log.Printf("Searching for root device of the image (%s)", *image.RootDeviceName) 32 var rootDevice *ec2.BlockDeviceMapping 33 for _, device := range image.BlockDeviceMappings { 34 if *device.DeviceName == *image.RootDeviceName { 35 rootDevice = device 36 break 37 } 38 } 39 40 if rootDevice == nil { 41 err := fmt.Errorf("Couldn't find root device!") 42 state.Put("error", err) 43 ui.Error(err.Error()) 44 return multistep.ActionHalt 45 } 46 47 ui.Say("Creating the root volume...") 48 vs := *rootDevice.Ebs.VolumeSize 49 if s.RootVolumeSize > *rootDevice.Ebs.VolumeSize { 50 vs = s.RootVolumeSize 51 } 52 createVolume := &ec2.CreateVolumeInput{ 53 AvailabilityZone: instance.Placement.AvailabilityZone, 54 Size: aws.Int64(vs), 55 SnapshotId: rootDevice.Ebs.SnapshotId, 56 VolumeType: rootDevice.Ebs.VolumeType, 57 Iops: rootDevice.Ebs.Iops, 58 } 59 log.Printf("Create args: %+v", createVolume) 60 61 createVolumeResp, err := ec2conn.CreateVolume(createVolume) 62 if err != nil { 63 err := fmt.Errorf("Error creating root volume: %s", err) 64 state.Put("error", err) 65 ui.Error(err.Error()) 66 return multistep.ActionHalt 67 } 68 69 // Set the volume ID so we remember to delete it later 70 s.volumeId = *createVolumeResp.VolumeId 71 log.Printf("Volume ID: %s", s.volumeId) 72 73 // Wait for the volume to become ready 74 stateChange := awscommon.StateChangeConf{ 75 Pending: []string{"creating"}, 76 StepState: state, 77 Target: "available", 78 Refresh: func() (interface{}, string, error) { 79 resp, err := ec2conn.DescribeVolumes(&ec2.DescribeVolumesInput{VolumeIds: []*string{&s.volumeId}}) 80 if err != nil { 81 return nil, "", err 82 } 83 84 v := resp.Volumes[0] 85 return v, *v.State, nil 86 }, 87 } 88 89 _, err = awscommon.WaitForState(&stateChange) 90 if err != nil { 91 err := fmt.Errorf("Error waiting for volume: %s", err) 92 state.Put("error", err) 93 ui.Error(err.Error()) 94 return multistep.ActionHalt 95 } 96 97 state.Put("volume_id", s.volumeId) 98 return multistep.ActionContinue 99 } 100 101 func (s *StepCreateVolume) Cleanup(state multistep.StateBag) { 102 if s.volumeId == "" { 103 return 104 } 105 106 ec2conn := state.Get("ec2").(*ec2.EC2) 107 ui := state.Get("ui").(packer.Ui) 108 109 ui.Say("Deleting the created EBS volume...") 110 _, err := ec2conn.DeleteVolume(&ec2.DeleteVolumeInput{VolumeId: &s.volumeId}) 111 if err != nil { 112 ui.Error(fmt.Sprintf("Error deleting EBS volume: %s", err)) 113 } 114 }