diff --git a/builder/amazon/ebs/step_tag_ebs_volumes.go b/builder/amazon/common/step_tag_ebs_volumes.go similarity index 80% rename from builder/amazon/ebs/step_tag_ebs_volumes.go rename to builder/amazon/common/step_tag_ebs_volumes.go index ffadb16ae..9a912600a 100644 --- a/builder/amazon/ebs/step_tag_ebs_volumes.go +++ b/builder/amazon/common/step_tag_ebs_volumes.go @@ -1,21 +1,20 @@ -package ebs +package common import ( "fmt" "github.com/aws/aws-sdk-go/service/ec2" "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/builder/amazon/common" "github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/template/interpolate" ) -type stepTagEBSVolumes struct { +type StepTagEBSVolumes struct { VolumeRunTags map[string]string Ctx interpolate.Context } -func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction { ec2conn := state.Get("ec2").(*ec2.EC2) instance := state.Get("instance").(*ec2.Instance) sourceAMI := state.Get("source_image").(*ec2.Image) @@ -37,7 +36,7 @@ func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction { } ui.Say("Adding tags to source EBS Volumes") - tags, err := common.ConvertToEC2Tags(s.VolumeRunTags, *ec2conn.Config.Region, *sourceAMI.ImageId, s.Ctx) + tags, err := ConvertToEC2Tags(s.VolumeRunTags, *ec2conn.Config.Region, *sourceAMI.ImageId, s.Ctx) if err != nil { err := fmt.Errorf("Error tagging source EBS Volumes on %s: %s", *instance.InstanceId, err) state.Put("error", err) @@ -59,6 +58,6 @@ func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionContinue } -func (s *stepTagEBSVolumes) Cleanup(state multistep.StateBag) { +func (s *StepTagEBSVolumes) Cleanup(state multistep.StateBag) { // No cleanup... } diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index a5ce0cd86..13598b96a 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -149,7 +149,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe Ctx: b.config.ctx, InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, }, - &stepTagEBSVolumes{ + &awscommon.StepTagEBSVolumes{ VolumeRunTags: b.config.VolumeRunTags, Ctx: b.config.ctx, }, diff --git a/builder/amazon/ebssurrogate/builder.go b/builder/amazon/ebssurrogate/builder.go index 7a6c93239..df2db83c1 100644 --- a/builder/amazon/ebssurrogate/builder.go +++ b/builder/amazon/ebssurrogate/builder.go @@ -28,7 +28,8 @@ type Config struct { awscommon.BlockDevices `mapstructure:",squash"` awscommon.AMIConfig `mapstructure:",squash"` - RootDevice RootBlockDevice `mapstructure:"ami_root_device"` + RootDevice RootBlockDevice `mapstructure:"ami_root_device"` + VolumeRunTags map[string]string `mapstructure:"run_volume_tags"` ctx interpolate.Context } @@ -47,6 +48,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { Exclude: []string{ "ami_description", "run_tags", + "run_volume_tags", + "snapshot_tags", "tags", }, }, @@ -119,6 +122,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe // Build the steps steps := []multistep.Step{ + &awscommon.StepPreValidate{ + DestAmiName: b.config.AMIName, + ForceDeregister: b.config.AMIForceDeregister, + }, &awscommon.StepSourceAMIInfo{ SourceAmi: b.config.SourceAmi, EnhancedNetworking: b.config.AMIEnhancedNetworking, @@ -155,6 +162,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe Tags: b.config.RunTags, InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, }, + &awscommon.StepTagEBSVolumes{ + VolumeRunTags: b.config.VolumeRunTags, + Ctx: b.config.ctx, + }, &awscommon.StepGetPassword{ Debug: b.config.PackerDebug, Comm: &b.config.RunConfig.Comm, @@ -181,10 +192,39 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &StepSnapshotNewRootVolume{ NewRootMountPoint: b.config.RootDevice.SourceDeviceName, }, + &awscommon.StepDeregisterAMI{ + ForceDeregister: b.config.AMIForceDeregister, + ForceDeleteSnapshot: b.config.AMIForceDeleteSnapshot, + AMIName: b.config.AMIName, + }, &StepRegisterAMI{ RootDevice: b.config.RootDevice, BlockDevices: b.config.BlockDevices.BuildLaunchDevices(), }, + &awscommon.StepCreateEncryptedAMICopy{ + KeyID: b.config.AMIKmsKeyId, + EncryptBootVolume: b.config.AMIEncryptBootVolume, + Name: b.config.AMIName, + }, + &awscommon.StepAMIRegionCopy{ + AccessConfig: &b.config.AccessConfig, + Regions: b.config.AMIRegions, + Name: b.config.AMIName, + }, + &awscommon.StepModifyAMIAttributes{ + Description: b.config.AMIDescription, + Users: b.config.AMIUsers, + Groups: b.config.AMIGroups, + ProductCodes: b.config.AMIProductCodes, + SnapshotUsers: b.config.SnapshotUsers, + SnapshotGroups: b.config.SnapshotGroups, + Ctx: b.config.ctx, + }, + &awscommon.StepCreateTags{ + Tags: b.config.AMITags, + SnapshotTags: b.config.SnapshotTags, + Ctx: b.config.ctx, + }, } // Run! diff --git a/builder/amazon/ebssurrogate/step_register_ami.go b/builder/amazon/ebssurrogate/step_register_ami.go index c4d8d9480..5aef1c724 100644 --- a/builder/amazon/ebssurrogate/step_register_ami.go +++ b/builder/amazon/ebssurrogate/step_register_ami.go @@ -14,6 +14,7 @@ import ( type StepRegisterAMI struct { RootDevice RootBlockDevice BlockDevices []*ec2.BlockDeviceMapping + image *ec2.Image } func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction { @@ -82,7 +83,45 @@ func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } + 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) + return multistep.ActionContinue } -func (s *StepRegisterAMI) Cleanup(state multistep.StateBag) {} +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) + ui := state.Get("ui").(packer.Ui) + + ui.Say("Deregistering the AMI because cancelation or error...") + 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 + } +} diff --git a/website/source/docs/builders/amazon-ebssurrogate.html.md b/website/source/docs/builders/amazon-ebssurrogate.html.md index beb676071..6dae386a8 100644 --- a/website/source/docs/builders/amazon-ebssurrogate.html.md +++ b/website/source/docs/builders/amazon-ebssurrogate.html.md @@ -163,6 +163,14 @@ builder. - `force_delete_snapshot` (boolean) - Force Packer to delete snapshots associated with AMIs, which have been deregistered by `force_deregister`. Default `false`. +- `encrypt_boot` (boolean) - Instruct packer to automatically create a copy of the + AMI with an encrypted boot volume (discarding the initial unencrypted AMI in the + process). Default `false`. + +- `kms_key_id` (string) - The ID of the KMS key to use for boot volume encryption. + This only applies to the main `region`, other regions where the AMI will be copied + will be encrypted by the default EBS KMS key. + - `iam_instance_profile` (string) - The name of an [IAM instance profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html) to launch the EC2 instance with.