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