2016-12-30 16:21:23 -05:00
|
|
|
package ebssurrogate
|
|
|
|
|
|
|
|
import (
|
2018-01-22 18:32:33 -05:00
|
|
|
"context"
|
2016-12-30 16:21:23 -05:00
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
"github.com/aws/aws-sdk-go/service/ec2"
|
2017-04-04 16:39:01 -04:00
|
|
|
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
2020-11-17 19:31:03 -05:00
|
|
|
"github.com/hashicorp/packer/packer-plugin-sdk/multistep"
|
2020-11-19 14:54:31 -05:00
|
|
|
packersdk "github.com/hashicorp/packer/packer-plugin-sdk/packer"
|
2020-11-12 17:44:02 -05:00
|
|
|
"github.com/hashicorp/packer/packer-plugin-sdk/random"
|
2020-11-18 13:34:59 -05:00
|
|
|
confighelper "github.com/hashicorp/packer/packer-plugin-sdk/template/config"
|
2016-12-30 16:21:23 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
// StepRegisterAMI creates the AMI.
|
|
|
|
type StepRegisterAMI struct {
|
2020-08-17 11:09:19 -04:00
|
|
|
PollingConfig *awscommon.AWSPollingConfig
|
2017-08-28 12:18:23 -04:00
|
|
|
RootDevice RootBlockDevice
|
2018-03-25 19:25:53 -04:00
|
|
|
AMIDevices []*ec2.BlockDeviceMapping
|
|
|
|
LaunchDevices []*ec2.BlockDeviceMapping
|
2019-08-22 16:17:35 -04:00
|
|
|
EnableAMIENASupport confighelper.Trilean
|
2017-08-28 12:18:23 -04:00
|
|
|
EnableAMISriovNetSupport bool
|
2019-05-07 19:38:55 -04:00
|
|
|
Architecture string
|
2017-08-28 12:18:23 -04:00
|
|
|
image *ec2.Image
|
2019-05-03 12:39:52 -04:00
|
|
|
LaunchOmitMap map[string]bool
|
2019-10-09 19:02:37 -04:00
|
|
|
AMISkipBuildRegion bool
|
2016-12-30 16:21:23 -05:00
|
|
|
}
|
|
|
|
|
2018-06-01 19:17:30 -04:00
|
|
|
func (s *StepRegisterAMI) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
2016-12-30 16:21:23 -05:00
|
|
|
config := state.Get("config").(*Config)
|
|
|
|
ec2conn := state.Get("ec2").(*ec2.EC2)
|
2018-03-25 19:25:53 -04:00
|
|
|
snapshotIds := state.Get("snapshot_ids").(map[string]string)
|
2020-11-19 14:54:31 -05:00
|
|
|
ui := state.Get("ui").(packersdk.Ui)
|
2016-12-30 16:21:23 -05:00
|
|
|
|
|
|
|
ui.Say("Registering the AMI...")
|
|
|
|
|
2018-03-25 19:25:53 -04:00
|
|
|
blockDevices := s.combineDevices(snapshotIds)
|
2016-12-30 16:21:23 -05:00
|
|
|
|
2019-10-09 19:02:37 -04:00
|
|
|
// Create the image
|
|
|
|
amiName := config.AMIName
|
|
|
|
state.Put("intermediary_image", false)
|
|
|
|
if config.AMIEncryptBootVolume.True() || s.AMISkipBuildRegion {
|
|
|
|
state.Put("intermediary_image", true)
|
|
|
|
|
|
|
|
// From AWS SDK docs: You can encrypt a copy of an unencrypted snapshot,
|
|
|
|
// but you cannot use it to create an unencrypted copy of an encrypted
|
|
|
|
// snapshot. Your default CMK for EBS is used unless you specify a
|
|
|
|
// non-default key using KmsKeyId.
|
|
|
|
|
|
|
|
// If encrypt_boot is nil or true, we need to create a temporary image
|
|
|
|
// so that in step_region_copy, we can copy it with the correct
|
|
|
|
// encryption
|
|
|
|
amiName = random.AlphaNum(7)
|
|
|
|
}
|
|
|
|
|
2016-12-30 16:21:23 -05:00
|
|
|
registerOpts := &ec2.RegisterImageInput{
|
2019-10-09 19:02:37 -04:00
|
|
|
Name: &amiName,
|
2019-05-07 19:38:55 -04:00
|
|
|
Architecture: aws.String(s.Architecture),
|
2016-12-30 16:21:23 -05:00
|
|
|
RootDeviceName: aws.String(s.RootDevice.DeviceName),
|
|
|
|
VirtualizationType: aws.String(config.AMIVirtType),
|
2018-03-25 19:25:53 -04:00
|
|
|
BlockDeviceMappings: blockDevices,
|
2016-12-30 16:21:23 -05:00
|
|
|
}
|
|
|
|
|
2017-08-28 12:18:23 -04:00
|
|
|
if s.EnableAMISriovNetSupport {
|
Always set both SRIOV and ENA when Enhanced Networking is enabled
Set SriovNetSupport to "simple". As of February 2017, this applies to C3, C4,
D2, I2, R3, and M4 (excluding m4.16xlarge).
Set EnaSupport to true. As of February 2017, this applies to C5, I3, P2, R4,
X1, and m4.16xlarge.
2017-02-21 20:46:16 -05:00
|
|
|
// Set SriovNetSupport to "simple". See http://goo.gl/icuXh5
|
|
|
|
// As of February 2017, this applies to C3, C4, D2, I2, R3, and M4 (excluding m4.16xlarge)
|
2016-12-30 16:21:23 -05:00
|
|
|
registerOpts.SriovNetSupport = aws.String("simple")
|
2017-08-28 12:18:23 -04:00
|
|
|
}
|
2019-08-22 16:17:35 -04:00
|
|
|
if s.EnableAMIENASupport.True() {
|
Always set both SRIOV and ENA when Enhanced Networking is enabled
Set SriovNetSupport to "simple". As of February 2017, this applies to C3, C4,
D2, I2, R3, and M4 (excluding m4.16xlarge).
Set EnaSupport to true. As of February 2017, this applies to C5, I3, P2, R4,
X1, and m4.16xlarge.
2017-02-21 20:46:16 -05:00
|
|
|
// Set EnaSupport to true
|
|
|
|
// As of February 2017, this applies to C5, I3, P2, R4, X1, and m4.16xlarge
|
|
|
|
registerOpts.EnaSupport = aws.Bool(true)
|
2016-12-30 16:21:23 -05:00
|
|
|
}
|
|
|
|
registerResp, err := ec2conn.RegisterImage(registerOpts)
|
|
|
|
if err != nil {
|
|
|
|
state.Put("error", fmt.Errorf("Error registering AMI: %s", err))
|
|
|
|
ui.Error(state.Get("error").(error).Error())
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the AMI ID in the state
|
|
|
|
ui.Say(fmt.Sprintf("AMI: %s", *registerResp.ImageId))
|
|
|
|
amis := make(map[string]string)
|
|
|
|
amis[*ec2conn.Config.Region] = *registerResp.ImageId
|
|
|
|
state.Put("amis", amis)
|
|
|
|
|
|
|
|
// Wait for the image to become ready
|
|
|
|
ui.Say("Waiting for AMI to become ready...")
|
2020-08-17 11:09:19 -04:00
|
|
|
if err := s.PollingConfig.WaitUntilAMIAvailable(ctx, ec2conn, *registerResp.ImageId); err != nil {
|
2016-12-30 16:21:23 -05:00
|
|
|
err := fmt.Errorf("Error waiting for AMI: %s", err)
|
|
|
|
state.Put("error", err)
|
|
|
|
ui.Error(err.Error())
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
|
|
|
|
2017-02-27 08:51:38 -05:00
|
|
|
imagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{registerResp.ImageId}})
|
|
|
|
if err != nil {
|
|
|
|
err := fmt.Errorf("Error searching for AMI: %s", err)
|
|
|
|
state.Put("error", err)
|
|
|
|
ui.Error(err.Error())
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
|
|
|
s.image = imagesResp.Images[0]
|
|
|
|
|
|
|
|
snapshots := make(map[string][]string)
|
|
|
|
for _, blockDeviceMapping := range imagesResp.Images[0].BlockDeviceMappings {
|
|
|
|
if blockDeviceMapping.Ebs != nil && blockDeviceMapping.Ebs.SnapshotId != nil {
|
|
|
|
|
|
|
|
snapshots[*ec2conn.Config.Region] = append(snapshots[*ec2conn.Config.Region], *blockDeviceMapping.Ebs.SnapshotId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
state.Put("snapshots", snapshots)
|
|
|
|
|
2016-12-30 16:21:23 -05:00
|
|
|
return multistep.ActionContinue
|
|
|
|
}
|
|
|
|
|
2017-02-27 08:51:38 -05:00
|
|
|
func (s *StepRegisterAMI) Cleanup(state multistep.StateBag) {
|
|
|
|
if s.image == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
_, cancelled := state.GetOk(multistep.StateCancelled)
|
|
|
|
_, halted := state.GetOk(multistep.StateHalted)
|
|
|
|
if !cancelled && !halted {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ec2conn := state.Get("ec2").(*ec2.EC2)
|
2020-11-19 14:54:31 -05:00
|
|
|
ui := state.Get("ui").(packersdk.Ui)
|
2017-02-27 08:51:38 -05:00
|
|
|
|
2017-05-25 21:49:29 -04:00
|
|
|
ui.Say("Deregistering the AMI because cancellation or error...")
|
2017-02-27 08:51:38 -05:00
|
|
|
deregisterOpts := &ec2.DeregisterImageInput{ImageId: s.image.ImageId}
|
|
|
|
if _, err := ec2conn.DeregisterImage(deregisterOpts); err != nil {
|
|
|
|
ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2017-06-27 19:12:22 -04:00
|
|
|
|
2018-03-25 19:25:53 -04:00
|
|
|
func (s *StepRegisterAMI) combineDevices(snapshotIds map[string]string) []*ec2.BlockDeviceMapping {
|
|
|
|
devices := map[string]*ec2.BlockDeviceMapping{}
|
|
|
|
|
|
|
|
for _, device := range s.AMIDevices {
|
|
|
|
devices[*device.DeviceName] = device
|
|
|
|
}
|
2017-06-27 19:12:22 -04:00
|
|
|
|
2018-03-25 19:25:53 -04:00
|
|
|
// Devices in launch_block_device_mappings override any with
|
|
|
|
// the same name in ami_block_device_mappings, except for the
|
|
|
|
// one designated as the root device in ami_root_device
|
|
|
|
for _, device := range s.LaunchDevices {
|
2019-05-03 12:39:52 -04:00
|
|
|
// Skip devices we've flagged for omission
|
|
|
|
omit, ok := s.LaunchOmitMap[*device.DeviceName]
|
|
|
|
if ok && omit {
|
|
|
|
continue
|
|
|
|
}
|
2018-03-25 19:25:53 -04:00
|
|
|
snapshotId, ok := snapshotIds[*device.DeviceName]
|
|
|
|
if ok {
|
|
|
|
device.Ebs.SnapshotId = aws.String(snapshotId)
|
|
|
|
// Block devices with snapshot inherit
|
|
|
|
// encryption settings from the snapshot
|
|
|
|
device.Ebs.Encrypted = nil
|
|
|
|
device.Ebs.KmsKeyId = nil
|
|
|
|
}
|
|
|
|
if *device.DeviceName == s.RootDevice.SourceDeviceName {
|
|
|
|
device.DeviceName = aws.String(s.RootDevice.DeviceName)
|
|
|
|
}
|
|
|
|
devices[*device.DeviceName] = device
|
2017-06-27 19:12:22 -04:00
|
|
|
}
|
|
|
|
|
2018-03-25 19:25:53 -04:00
|
|
|
blockDevices := []*ec2.BlockDeviceMapping{}
|
|
|
|
for _, device := range devices {
|
|
|
|
blockDevices = append(blockDevices, device)
|
|
|
|
}
|
|
|
|
return blockDevices
|
2017-06-27 19:12:22 -04:00
|
|
|
}
|