github.com/angdraug/packer@v1.3.2/builder/amazon/ebssurrogate/step_register_ami.go (about) 1 package ebssurrogate 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/aws/aws-sdk-go/aws" 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 // StepRegisterAMI creates the AMI. 15 type StepRegisterAMI struct { 16 RootDevice RootBlockDevice 17 AMIDevices []*ec2.BlockDeviceMapping 18 LaunchDevices []*ec2.BlockDeviceMapping 19 EnableAMIENASupport *bool 20 EnableAMISriovNetSupport bool 21 image *ec2.Image 22 } 23 24 func (s *StepRegisterAMI) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { 25 config := state.Get("config").(*Config) 26 ec2conn := state.Get("ec2").(*ec2.EC2) 27 snapshotIds := state.Get("snapshot_ids").(map[string]string) 28 ui := state.Get("ui").(packer.Ui) 29 30 ui.Say("Registering the AMI...") 31 32 blockDevices := s.combineDevices(snapshotIds) 33 34 registerOpts := &ec2.RegisterImageInput{ 35 Name: &config.AMIName, 36 Architecture: aws.String(ec2.ArchitectureValuesX8664), 37 RootDeviceName: aws.String(s.RootDevice.DeviceName), 38 VirtualizationType: aws.String(config.AMIVirtType), 39 BlockDeviceMappings: blockDevices, 40 } 41 42 if s.EnableAMISriovNetSupport { 43 // Set SriovNetSupport to "simple". See http://goo.gl/icuXh5 44 // As of February 2017, this applies to C3, C4, D2, I2, R3, and M4 (excluding m4.16xlarge) 45 registerOpts.SriovNetSupport = aws.String("simple") 46 } 47 if s.EnableAMIENASupport != nil && *s.EnableAMIENASupport { 48 // Set EnaSupport to true 49 // As of February 2017, this applies to C5, I3, P2, R4, X1, and m4.16xlarge 50 registerOpts.EnaSupport = aws.Bool(true) 51 } 52 registerResp, err := ec2conn.RegisterImage(registerOpts) 53 if err != nil { 54 state.Put("error", fmt.Errorf("Error registering AMI: %s", err)) 55 ui.Error(state.Get("error").(error).Error()) 56 return multistep.ActionHalt 57 } 58 59 // Set the AMI ID in the state 60 ui.Say(fmt.Sprintf("AMI: %s", *registerResp.ImageId)) 61 amis := make(map[string]string) 62 amis[*ec2conn.Config.Region] = *registerResp.ImageId 63 state.Put("amis", amis) 64 65 // Wait for the image to become ready 66 ui.Say("Waiting for AMI to become ready...") 67 if err := awscommon.WaitUntilAMIAvailable(ctx, ec2conn, *registerResp.ImageId); err != nil { 68 err := fmt.Errorf("Error waiting for AMI: %s", err) 69 state.Put("error", err) 70 ui.Error(err.Error()) 71 return multistep.ActionHalt 72 } 73 74 imagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{registerResp.ImageId}}) 75 if err != nil { 76 err := fmt.Errorf("Error searching for AMI: %s", err) 77 state.Put("error", err) 78 ui.Error(err.Error()) 79 return multistep.ActionHalt 80 } 81 s.image = imagesResp.Images[0] 82 83 snapshots := make(map[string][]string) 84 for _, blockDeviceMapping := range imagesResp.Images[0].BlockDeviceMappings { 85 if blockDeviceMapping.Ebs != nil && blockDeviceMapping.Ebs.SnapshotId != nil { 86 87 snapshots[*ec2conn.Config.Region] = append(snapshots[*ec2conn.Config.Region], *blockDeviceMapping.Ebs.SnapshotId) 88 } 89 } 90 state.Put("snapshots", snapshots) 91 92 return multistep.ActionContinue 93 } 94 95 func (s *StepRegisterAMI) Cleanup(state multistep.StateBag) { 96 if s.image == nil { 97 return 98 } 99 100 _, cancelled := state.GetOk(multistep.StateCancelled) 101 _, halted := state.GetOk(multistep.StateHalted) 102 if !cancelled && !halted { 103 return 104 } 105 106 ec2conn := state.Get("ec2").(*ec2.EC2) 107 ui := state.Get("ui").(packer.Ui) 108 109 ui.Say("Deregistering the AMI because cancellation or error...") 110 deregisterOpts := &ec2.DeregisterImageInput{ImageId: s.image.ImageId} 111 if _, err := ec2conn.DeregisterImage(deregisterOpts); err != nil { 112 ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err)) 113 return 114 } 115 } 116 117 func (s *StepRegisterAMI) combineDevices(snapshotIds map[string]string) []*ec2.BlockDeviceMapping { 118 devices := map[string]*ec2.BlockDeviceMapping{} 119 120 for _, device := range s.AMIDevices { 121 devices[*device.DeviceName] = device 122 } 123 124 // Devices in launch_block_device_mappings override any with 125 // the same name in ami_block_device_mappings, except for the 126 // one designated as the root device in ami_root_device 127 for _, device := range s.LaunchDevices { 128 snapshotId, ok := snapshotIds[*device.DeviceName] 129 if ok { 130 device.Ebs.SnapshotId = aws.String(snapshotId) 131 // Block devices with snapshot inherit 132 // encryption settings from the snapshot 133 device.Ebs.Encrypted = nil 134 device.Ebs.KmsKeyId = nil 135 } 136 if *device.DeviceName == s.RootDevice.SourceDeviceName { 137 device.DeviceName = aws.String(s.RootDevice.DeviceName) 138 } 139 devices[*device.DeviceName] = device 140 } 141 142 blockDevices := []*ec2.BlockDeviceMapping{} 143 for _, device := range devices { 144 blockDevices = append(blockDevices, device) 145 } 146 return blockDevices 147 }