github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/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 config := state.Get("config").(*Config) 26 ec2conn := state.Get("ec2").(*ec2.EC2) 27 instance := state.Get("instance").(*ec2.Instance) 28 ui := state.Get("ui").(packer.Ui) 29 30 var createVolume *ec2.CreateVolumeInput 31 if config.FromScratch { 32 createVolume = &ec2.CreateVolumeInput{ 33 AvailabilityZone: instance.Placement.AvailabilityZone, 34 Size: aws.Int64(s.RootVolumeSize), 35 VolumeType: aws.String(ec2.VolumeTypeGp2), 36 } 37 } else { 38 // Determine the root device snapshot 39 image := state.Get("source_image").(*ec2.Image) 40 log.Printf("Searching for root device of the image (%s)", *image.RootDeviceName) 41 var rootDevice *ec2.BlockDeviceMapping 42 for _, device := range image.BlockDeviceMappings { 43 if *device.DeviceName == *image.RootDeviceName { 44 rootDevice = device 45 break 46 } 47 } 48 49 if rootDevice == nil { 50 err := fmt.Errorf("Couldn't find root device!") 51 state.Put("error", err) 52 ui.Error(err.Error()) 53 return multistep.ActionHalt 54 } 55 56 ui.Say("Creating the root volume...") 57 vs := *rootDevice.Ebs.VolumeSize 58 if s.RootVolumeSize > *rootDevice.Ebs.VolumeSize { 59 vs = s.RootVolumeSize 60 } 61 62 createVolume = &ec2.CreateVolumeInput{ 63 AvailabilityZone: instance.Placement.AvailabilityZone, 64 Size: aws.Int64(vs), 65 SnapshotId: rootDevice.Ebs.SnapshotId, 66 VolumeType: rootDevice.Ebs.VolumeType, 67 Iops: rootDevice.Ebs.Iops, 68 } 69 } 70 71 log.Printf("Create args: %+v", createVolume) 72 73 createVolumeResp, err := ec2conn.CreateVolume(createVolume) 74 if err != nil { 75 err := fmt.Errorf("Error creating root volume: %s", err) 76 state.Put("error", err) 77 ui.Error(err.Error()) 78 return multistep.ActionHalt 79 } 80 81 // Set the volume ID so we remember to delete it later 82 s.volumeId = *createVolumeResp.VolumeId 83 log.Printf("Volume ID: %s", s.volumeId) 84 85 // Wait for the volume to become ready 86 stateChange := awscommon.StateChangeConf{ 87 Pending: []string{"creating"}, 88 StepState: state, 89 Target: "available", 90 Refresh: func() (interface{}, string, error) { 91 resp, err := ec2conn.DescribeVolumes(&ec2.DescribeVolumesInput{VolumeIds: []*string{&s.volumeId}}) 92 if err != nil { 93 return nil, "", err 94 } 95 96 v := resp.Volumes[0] 97 return v, *v.State, nil 98 }, 99 } 100 101 _, err = awscommon.WaitForState(&stateChange) 102 if err != nil { 103 err := fmt.Errorf("Error waiting for volume: %s", err) 104 state.Put("error", err) 105 ui.Error(err.Error()) 106 return multistep.ActionHalt 107 } 108 109 state.Put("volume_id", s.volumeId) 110 return multistep.ActionContinue 111 } 112 113 func (s *StepCreateVolume) Cleanup(state multistep.StateBag) { 114 if s.volumeId == "" { 115 return 116 } 117 118 ec2conn := state.Get("ec2").(*ec2.EC2) 119 ui := state.Get("ui").(packer.Ui) 120 121 ui.Say("Deleting the created EBS volume...") 122 _, err := ec2conn.DeleteVolume(&ec2.DeleteVolumeInput{VolumeId: &s.volumeId}) 123 if err != nil { 124 ui.Error(fmt.Sprintf("Error deleting EBS volume: %s", err)) 125 } 126 }