diff --git a/builder/amazon/chroot/block_device.go b/builder/amazon/chroot/block_device.go index f8b29f64f..442b782b5 100644 --- a/builder/amazon/chroot/block_device.go +++ b/builder/amazon/chroot/block_device.go @@ -65,13 +65,3 @@ func (bds BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) { } return errs } - -func (b BlockDevices) GetOmissions() map[string]bool { - omitMap := make(map[string]bool) - - for _, blockDevice := range b { - omitMap[blockDevice.DeviceName] = blockDevice.OmitFromArtifact - } - - return omitMap -} diff --git a/builder/amazon/common/block_device.go b/builder/amazon/common/block_device.go index 1babddcc1..15c1ddd9b 100644 --- a/builder/amazon/common/block_device.go +++ b/builder/amazon/common/block_device.go @@ -44,8 +44,6 @@ type BlockDevice struct { // The size of the volume, in GiB. Required if not specifying a // snapshot_id. VolumeSize int64 `mapstructure:"volume_size" required:"false"` - // ebssurrogate only - OmitFromArtifact bool `mapstructure:"omit_from_artifact"` } type BlockDevices []BlockDevice @@ -120,13 +118,3 @@ func (bds BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) { } return errs } - -func (b BlockDevices) GetOmissions() map[string]bool { - omitMap := make(map[string]bool) - - for _, blockDevice := range b { - omitMap[blockDevice.DeviceName] = blockDevice.OmitFromArtifact - } - - return omitMap -} diff --git a/builder/amazon/common/step_run_source_instance.go b/builder/amazon/common/step_run_source_instance.go index 6af509f92..07abadebf 100644 --- a/builder/amazon/common/step_run_source_instance.go +++ b/builder/amazon/common/step_run_source_instance.go @@ -21,7 +21,7 @@ import ( type StepRunSourceInstance struct { AssociatePublicIpAddress bool - LaunchMappings BlockDevices + LaunchMappings EC2BlockDeviceMappingsBuilder Comm *communicator.Config Ctx interpolate.Context Debug bool diff --git a/builder/amazon/common/step_run_spot_instance.go b/builder/amazon/common/step_run_spot_instance.go index 8961e4430..05a4f521c 100644 --- a/builder/amazon/common/step_run_spot_instance.go +++ b/builder/amazon/common/step_run_spot_instance.go @@ -21,9 +21,13 @@ import ( "github.com/hashicorp/packer/template/interpolate" ) +type EC2BlockDeviceMappingsBuilder interface { + BuildEC2BlockDeviceMappings() []*ec2.BlockDeviceMapping +} + type StepRunSpotInstance struct { AssociatePublicIpAddress bool - LaunchMappings BlockDevices + LaunchMappings EC2BlockDeviceMappingsBuilder BlockDurationMinutes int64 Debug bool Comm *communicator.Config diff --git a/builder/amazon/common/step_run_spot_instance_test.go b/builder/amazon/common/step_run_spot_instance_test.go index 72639a050..0be395463 100644 --- a/builder/amazon/common/step_run_spot_instance_test.go +++ b/builder/amazon/common/step_run_spot_instance_test.go @@ -82,7 +82,7 @@ func tStateSpot() multistep.StateBag { func getBasicStep() *StepRunSpotInstance { stepRunSpotInstance := StepRunSpotInstance{ AssociatePublicIpAddress: false, - LaunchMappings: []BlockDevice(nil), + LaunchMappings: BlockDevices{}, BlockDurationMinutes: 0, Debug: false, Comm: &communicator.Config{ diff --git a/builder/amazon/ebssurrogate/block_device.go b/builder/amazon/ebssurrogate/block_device.go new file mode 100644 index 000000000..f63dec861 --- /dev/null +++ b/builder/amazon/ebssurrogate/block_device.go @@ -0,0 +1,111 @@ +//go:generate struct-markdown + +package ebssurrogate + +import ( + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + awscommon "github.com/hashicorp/packer/builder/amazon/common" + "github.com/hashicorp/packer/template/interpolate" +) + +type BlockDevice struct { + awscommon.BlockDevice `mapstructure:",squash"` + + // ebssurrogate only + OmitFromArtifact bool `mapstructure:"omit_from_artifact"` +} + +type BlockDevices []BlockDevice + +func (bds BlockDevices) Common() []awscommon.BlockDevice { + res := []awscommon.BlockDevice{} + for _, bd := range bds { + res = append(res, bd.BlockDevice) + } + return res +} + +func (bds BlockDevices) BuildEC2BlockDeviceMappings() []*ec2.BlockDeviceMapping { + var blockDevices []*ec2.BlockDeviceMapping + + for _, blockDevice := range bds { + blockDevices = append(blockDevices, blockDevice.BuildEC2BlockDeviceMapping()) + } + return blockDevices +} + +func (blockDevice BlockDevice) BuildEC2BlockDeviceMapping() *ec2.BlockDeviceMapping { + + mapping := &ec2.BlockDeviceMapping{ + DeviceName: aws.String(blockDevice.DeviceName), + } + + if blockDevice.NoDevice { + mapping.NoDevice = aws.String("") + return mapping + } else if blockDevice.VirtualName != "" { + if strings.HasPrefix(blockDevice.VirtualName, "ephemeral") { + mapping.VirtualName = aws.String(blockDevice.VirtualName) + } + return mapping + } + + ebsBlockDevice := &ec2.EbsBlockDevice{ + DeleteOnTermination: aws.Bool(blockDevice.DeleteOnTermination), + } + + if blockDevice.VolumeType != "" { + ebsBlockDevice.VolumeType = aws.String(blockDevice.VolumeType) + } + + if blockDevice.VolumeSize > 0 { + ebsBlockDevice.VolumeSize = aws.Int64(blockDevice.VolumeSize) + } + + // IOPS is only valid for io1 type + if blockDevice.VolumeType == "io1" { + ebsBlockDevice.Iops = aws.Int64(blockDevice.IOPS) + } + + // You cannot specify Encrypted if you specify a Snapshot ID + if blockDevice.SnapshotId != "" { + ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId) + } + ebsBlockDevice.Encrypted = blockDevice.Encrypted + + mapping.Ebs = ebsBlockDevice + + return mapping +} + +func (b *BlockDevice) Prepare(ctx *interpolate.Context) error { + if b.DeviceName == "" { + return fmt.Errorf("The `device_name` must be specified " + + "for every device in the block device mapping.") + } + + return nil +} + +func (bds BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) { + for _, block := range bds { + if err := block.Prepare(ctx); err != nil { + errs = append(errs, err) + } + } + return errs +} + +func (b BlockDevices) GetOmissions() map[string]bool { + omitMap := make(map[string]bool) + + for _, blockDevice := range b { + omitMap[blockDevice.DeviceName] = blockDevice.OmitFromArtifact + } + + return omitMap +} diff --git a/builder/amazon/ebssurrogate/builder.go b/builder/amazon/ebssurrogate/builder.go index 860204499..3a576772c 100644 --- a/builder/amazon/ebssurrogate/builder.go +++ b/builder/amazon/ebssurrogate/builder.go @@ -26,7 +26,7 @@ type Config struct { awscommon.AccessConfig `mapstructure:",squash"` awscommon.RunConfig `mapstructure:",squash"` AMIMappings awscommon.BlockDevices `mapstructure:"ami_block_device_mappings" required:"false"` - LaunchMappings awscommon.BlockDevices `mapstructure:"launch_block_device_mappings" required:"false"` + LaunchMappings BlockDevices `mapstructure:"launch_block_device_mappings" required:"false"` awscommon.AMIConfig `mapstructure:",squash"` // A block device mapping describing the root device of the AMI. This looks // like the mappings in `ami_block_device_mapping`, except with an @@ -235,7 +235,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack TemporarySGSourceCidrs: b.config.TemporarySGSourceCidrs, }, &awscommon.StepCleanupVolumes{ - LaunchMappings: b.config.LaunchMappings, + LaunchMappings: b.config.LaunchMappings.Common(), }, instanceStep, &awscommon.StepGetPassword{ diff --git a/builder/amazon/ebsvolume/block_device.go b/builder/amazon/ebsvolume/block_device.go index e46f62a24..f9eafa122 100644 --- a/builder/amazon/ebsvolume/block_device.go +++ b/builder/amazon/ebsvolume/block_device.go @@ -3,28 +3,47 @@ package ebsvolume import ( + "github.com/aws/aws-sdk-go/service/ec2" awscommon "github.com/hashicorp/packer/builder/amazon/common" "github.com/hashicorp/packer/template/interpolate" ) type BlockDevice struct { - awscommon.BlockDevice `mapstructure:"-,squash"` + awscommon.BlockDevice `mapstructure:",squash"` + + OmitFromArtifact bool `mapstructure:"omit_from_artifact"` // Tags applied to the AMI. This is a // template engine, see Build template // data for more information. Tags awscommon.TagMap `mapstructure:"tags" required:"false"` } -func commonBlockDevices(mappings []BlockDevice, ctx *interpolate.Context) (awscommon.BlockDevices, error) { - result := make([]awscommon.BlockDevice, len(mappings)) +type BlockDevices []BlockDevice - for i, mapping := range mappings { - interpolateBlockDev, err := interpolate.RenderInterface(&mapping.BlockDevice, ctx) - if err != nil { - return awscommon.BlockDevices{}, err +func (bds BlockDevices) BuildEC2BlockDeviceMappings() []*ec2.BlockDeviceMapping { + var blockDevices []*ec2.BlockDeviceMapping + + for _, blockDevice := range bds { + blockDevices = append(blockDevices, blockDevice.BuildEC2BlockDeviceMapping()) + } + return blockDevices +} + +func (bds BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) { + for _, block := range bds { + if err := block.Prepare(ctx); err != nil { + errs = append(errs, err) } - result[i] = *interpolateBlockDev.(*awscommon.BlockDevice) + } + return errs +} + +func (b BlockDevices) GetOmissions() map[string]bool { + omitMap := make(map[string]bool) + + for _, blockDevice := range b { + omitMap[blockDevice.DeviceName] = blockDevice.OmitFromArtifact } - return result, nil + return omitMap } diff --git a/builder/amazon/ebsvolume/builder.go b/builder/amazon/ebsvolume/builder.go index 5db4fba23..ad1b26289 100644 --- a/builder/amazon/ebsvolume/builder.go +++ b/builder/amazon/ebsvolume/builder.go @@ -1,7 +1,7 @@ //go:generate struct-markdown -// The ebsvolume package contains a packer.Builder implementation that -// builds EBS volumes for Amazon EC2 using an ephemeral instance, +// The ebsvolume package contains a packer.Builder implementation that builds +// EBS volumes for Amazon EC2 using an ephemeral instance, package ebsvolume import ( @@ -24,9 +24,9 @@ type Config struct { common.PackerConfig `mapstructure:",squash"` awscommon.AccessConfig `mapstructure:",squash"` awscommon.RunConfig `mapstructure:",squash"` - // Add the block device - // mappings to the AMI. The block device mappings allow for keys: - VolumeMappings []BlockDevice `mapstructure:"ebs_volumes" required:"false"` + // Add the block device mappings to the AMI. The block device mappings + // allow for keys: + VolumeMappings BlockDevices `mapstructure:"ebs_volumes" required:"false"` // Enable enhanced networking (ENA but not SriovNetSupport) on // HVM-compatible AMIs. If set, add ec2:ModifyInstanceAttribute to your AWS // IAM policy. If false, this will disable enhanced networking in the final @@ -42,7 +42,7 @@ type Config struct { // Default `false`. AMISriovNetSupport bool `mapstructure:"sriov_support" required:"false"` - launchBlockDevices awscommon.BlockDevices + launchBlockDevices BlockDevices ctx interpolate.Context } @@ -84,7 +84,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { } } - b.config.launchBlockDevices, err = commonBlockDevices(b.config.VolumeMappings, &b.config.ctx) + b.config.launchBlockDevices = b.config.VolumeMappings if err != nil { errs = packer.MultiErrorAppend(errs, err) }