github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/builder/amazon/ebs/step_create_ami.go (about) 1 package ebs 2 3 import ( 4 "fmt" 5 6 "github.com/aws/aws-sdk-go/service/ec2" 7 "github.com/mitchellh/multistep" 8 awscommon "github.com/mitchellh/packer/builder/amazon/common" 9 "github.com/mitchellh/packer/packer" 10 ) 11 12 type stepCreateAMI struct { 13 image *ec2.Image 14 } 15 16 func (s *stepCreateAMI) Run(state multistep.StateBag) multistep.StepAction { 17 config := state.Get("config").(Config) 18 ec2conn := state.Get("ec2").(*ec2.EC2) 19 instance := state.Get("instance").(*ec2.Instance) 20 ui := state.Get("ui").(packer.Ui) 21 22 // Create the image 23 ui.Say(fmt.Sprintf("Creating the AMI: %s", config.AMIName)) 24 createOpts := &ec2.CreateImageInput{ 25 InstanceId: instance.InstanceId, 26 Name: &config.AMIName, 27 BlockDeviceMappings: config.BlockDevices.BuildAMIDevices(), 28 } 29 30 createResp, err := ec2conn.CreateImage(createOpts) 31 if err != nil { 32 err := fmt.Errorf("Error creating AMI: %s", err) 33 state.Put("error", err) 34 ui.Error(err.Error()) 35 return multistep.ActionHalt 36 } 37 38 // Set the AMI ID in the state 39 ui.Message(fmt.Sprintf("AMI: %s", *createResp.ImageId)) 40 amis := make(map[string]string) 41 amis[*ec2conn.Config.Region] = *createResp.ImageId 42 state.Put("amis", amis) 43 44 // Wait for the image to become ready 45 stateChange := awscommon.StateChangeConf{ 46 Pending: []string{"pending"}, 47 Target: "available", 48 Refresh: awscommon.AMIStateRefreshFunc(ec2conn, *createResp.ImageId), 49 StepState: state, 50 } 51 52 ui.Say("Waiting for AMI to become ready...") 53 if _, err := awscommon.WaitForState(&stateChange); err != nil { 54 err := fmt.Errorf("Error waiting for AMI: %s", err) 55 state.Put("error", err) 56 ui.Error(err.Error()) 57 return multistep.ActionHalt 58 } 59 60 imagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{createResp.ImageId}}) 61 if err != nil { 62 err := fmt.Errorf("Error searching for AMI: %s", err) 63 state.Put("error", err) 64 ui.Error(err.Error()) 65 return multistep.ActionHalt 66 } 67 s.image = imagesResp.Images[0] 68 69 snapshots := make(map[string][]string) 70 for _, blockDeviceMapping := range imagesResp.Images[0].BlockDeviceMappings { 71 if blockDeviceMapping.Ebs != nil && blockDeviceMapping.Ebs.SnapshotId != nil { 72 73 snapshots[*ec2conn.Config.Region] = append(snapshots[*ec2conn.Config.Region], *blockDeviceMapping.Ebs.SnapshotId) 74 } 75 } 76 state.Put("snapshots", snapshots) 77 78 return multistep.ActionContinue 79 } 80 81 func (s *stepCreateAMI) Cleanup(state multistep.StateBag) { 82 if s.image == nil { 83 return 84 } 85 86 _, cancelled := state.GetOk(multistep.StateCancelled) 87 _, halted := state.GetOk(multistep.StateHalted) 88 if !cancelled && !halted { 89 return 90 } 91 92 ec2conn := state.Get("ec2").(*ec2.EC2) 93 ui := state.Get("ui").(packer.Ui) 94 95 ui.Say("Deregistering the AMI because cancelation or error...") 96 deregisterOpts := &ec2.DeregisterImageInput{ImageId: s.image.ImageId} 97 if _, err := ec2conn.DeregisterImage(deregisterOpts); err != nil { 98 ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err)) 99 return 100 } 101 }