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