2013-08-15 17:05:08 -04:00
|
|
|
package common
|
|
|
|
|
|
|
|
import (
|
2018-01-12 18:10:51 -05:00
|
|
|
"fmt"
|
2015-07-15 20:07:36 -04:00
|
|
|
"strings"
|
|
|
|
|
2015-06-03 17:13:52 -04:00
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
"github.com/aws/aws-sdk-go/service/ec2"
|
2017-04-04 16:39:01 -04:00
|
|
|
"github.com/hashicorp/packer/template/interpolate"
|
2013-08-15 17:05:08 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// BlockDevice
|
|
|
|
type BlockDevice struct {
|
2019-05-28 11:50:58 -04:00
|
|
|
// Indicates whether the EBS volume is
|
|
|
|
// deleted on instance termination. Default false. NOTE: If this
|
|
|
|
// value is not explicitly set to true and volumes are not cleaned up by
|
|
|
|
// an alternative method, additional volumes will accumulate after every
|
|
|
|
// build.
|
|
|
|
DeleteOnTermination bool `mapstructure:"delete_on_termination" required:"false"`
|
|
|
|
// The device name exposed to the instance (for
|
|
|
|
// example, /dev/sdh or xvdh). Required for every device in the block
|
|
|
|
// device mapping.
|
|
|
|
DeviceName string `mapstructure:"device_name" required:"false"`
|
|
|
|
// Indicates whether or not to encrypt the volume.
|
|
|
|
// By default, Packer will keep the encryption setting to what it was in
|
|
|
|
// the source image. Setting false will result in an unencrypted device,
|
|
|
|
// and true will result in an encrypted one.
|
|
|
|
Encrypted *bool `mapstructure:"encrypted" required:"false"`
|
|
|
|
// The number of I/O operations per second (IOPS) that
|
|
|
|
// the volume supports. See the documentation on
|
|
|
|
// IOPs
|
|
|
|
// for more information
|
|
|
|
IOPS int64 `mapstructure:"iops" required:"false"`
|
|
|
|
// Suppresses the specified device included in the
|
|
|
|
// block device mapping of the AMI.
|
|
|
|
NoDevice bool `mapstructure:"no_device" required:"false"`
|
|
|
|
// The ID of the snapshot.
|
|
|
|
SnapshotId string `mapstructure:"snapshot_id" required:"false"`
|
|
|
|
// The virtual device name. See the
|
|
|
|
// documentation on Block Device
|
|
|
|
// Mapping
|
|
|
|
// for more information.
|
|
|
|
VirtualName string `mapstructure:"virtual_name" required:"false"`
|
|
|
|
// The volume type. gp2 for General Purpose
|
|
|
|
// (SSD) volumes, io1 for Provisioned IOPS (SSD) volumes, st1 for
|
|
|
|
// Throughput Optimized HDD, sc1 for Cold HDD, and standard for
|
|
|
|
// Magnetic volumes.
|
|
|
|
VolumeType string `mapstructure:"volume_type" required:"false"`
|
|
|
|
// The size of the volume, in GiB. Required if
|
|
|
|
// not specifying a snapshot_id.
|
|
|
|
VolumeSize int64 `mapstructure:"volume_size" required:"false"`
|
|
|
|
// ID, alias or ARN 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.
|
|
|
|
// For valid formats see KmsKeyId in the AWS API docs -
|
|
|
|
// CopyImage.
|
|
|
|
// This field is validated by Packer, when using an alias, you will have to
|
|
|
|
// prefix kms_key_id with alias/.
|
|
|
|
KmsKeyId string `mapstructure:"kms_key_id" required:"false"`
|
2019-05-03 12:39:52 -04:00
|
|
|
// ebssurrogate only
|
|
|
|
OmitFromArtifact bool `mapstructure:"omit_from_artifact"`
|
2013-08-15 17:05:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
type BlockDevices struct {
|
2016-08-12 19:29:55 -04:00
|
|
|
AMIBlockDevices `mapstructure:",squash"`
|
|
|
|
LaunchBlockDevices `mapstructure:",squash"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type AMIBlockDevices struct {
|
2019-05-28 11:50:58 -04:00
|
|
|
// Add one or
|
|
|
|
// more block device
|
|
|
|
// mappings
|
|
|
|
// to the AMI. These will be attached when booting a new instance from your
|
|
|
|
// AMI. If this field is populated, and you are building from an existing source image,
|
|
|
|
// the block device mappings in the source image will be overwritten. This means you
|
|
|
|
// must have a block device mapping entry for your root volume, root_volume_size,
|
|
|
|
// and root_device_name. `Your options here may vary depending on the type of VM
|
|
|
|
// you use. The block device mappings allow for the following configuration:
|
|
|
|
AMIMappings []BlockDevice `mapstructure:"ami_block_device_mappings" required:"false"`
|
2016-08-12 19:29:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
type LaunchBlockDevices struct {
|
2019-05-28 11:50:58 -04:00
|
|
|
// Add one
|
|
|
|
// or more block devices before the Packer build starts. If you add instance
|
|
|
|
// store volumes or EBS volumes in addition to the root device volume, the
|
|
|
|
// created AMI will contain block device mapping information for those
|
|
|
|
// volumes. Amazon creates snapshots of the source instance's root volume and
|
|
|
|
// any other EBS volumes described here. When you launch an instance from this
|
|
|
|
// new AMI, the instance automatically launches with these additional volumes,
|
|
|
|
// and will restore them from snapshots taken from the source instance.
|
|
|
|
LaunchMappings []BlockDevice `mapstructure:"launch_block_device_mappings" required:"false"`
|
2013-08-15 17:05:08 -04:00
|
|
|
}
|
|
|
|
|
2015-04-05 17:58:48 -04:00
|
|
|
func buildBlockDevices(b []BlockDevice) []*ec2.BlockDeviceMapping {
|
|
|
|
var blockDevices []*ec2.BlockDeviceMapping
|
2013-08-15 17:05:08 -04:00
|
|
|
|
|
|
|
for _, blockDevice := range b {
|
2015-10-18 14:00:05 -04:00
|
|
|
mapping := &ec2.BlockDeviceMapping{
|
2015-08-24 17:19:11 -04:00
|
|
|
DeviceName: aws.String(blockDevice.DeviceName),
|
2015-04-05 17:58:48 -04:00
|
|
|
}
|
2015-06-09 12:38:53 -04:00
|
|
|
|
2015-08-24 17:19:11 -04:00
|
|
|
if blockDevice.NoDevice {
|
|
|
|
mapping.NoDevice = aws.String("")
|
2015-10-18 14:05:21 -04:00
|
|
|
} else if blockDevice.VirtualName != "" {
|
|
|
|
if strings.HasPrefix(blockDevice.VirtualName, "ephemeral") {
|
|
|
|
mapping.VirtualName = aws.String(blockDevice.VirtualName)
|
|
|
|
}
|
2015-08-24 17:19:11 -04:00
|
|
|
} else {
|
|
|
|
ebsBlockDevice := &ec2.EbsBlockDevice{
|
|
|
|
DeleteOnTermination: aws.Bool(blockDevice.DeleteOnTermination),
|
|
|
|
}
|
2015-06-09 12:38:53 -04:00
|
|
|
|
2015-08-24 17:19:11 -04:00
|
|
|
if blockDevice.VolumeType != "" {
|
|
|
|
ebsBlockDevice.VolumeType = aws.String(blockDevice.VolumeType)
|
|
|
|
}
|
2015-06-09 12:38:53 -04:00
|
|
|
|
2015-08-24 17:19:11 -04:00
|
|
|
if blockDevice.VolumeSize > 0 {
|
|
|
|
ebsBlockDevice.VolumeSize = aws.Int64(blockDevice.VolumeSize)
|
|
|
|
}
|
2015-06-29 17:11:58 -04:00
|
|
|
|
2015-08-24 17:19:11 -04:00
|
|
|
// IOPS is only valid for io1 type
|
|
|
|
if blockDevice.VolumeType == "io1" {
|
|
|
|
ebsBlockDevice.Iops = aws.Int64(blockDevice.IOPS)
|
|
|
|
}
|
2015-04-05 17:58:48 -04:00
|
|
|
|
2015-08-24 17:19:11 -04:00
|
|
|
// You cannot specify Encrypted if you specify a Snapshot ID
|
|
|
|
if blockDevice.SnapshotId != "" {
|
|
|
|
ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId)
|
|
|
|
}
|
2018-11-26 05:33:44 -05:00
|
|
|
ebsBlockDevice.Encrypted = blockDevice.Encrypted
|
2015-08-24 17:19:11 -04:00
|
|
|
|
2018-01-08 23:30:29 -05:00
|
|
|
if blockDevice.KmsKeyId != "" {
|
|
|
|
ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId)
|
|
|
|
}
|
|
|
|
|
2015-08-24 17:19:11 -04:00
|
|
|
mapping.Ebs = ebsBlockDevice
|
2015-04-05 17:58:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
blockDevices = append(blockDevices, mapping)
|
2013-08-15 17:05:08 -04:00
|
|
|
}
|
|
|
|
return blockDevices
|
|
|
|
}
|
|
|
|
|
2018-01-12 18:10:51 -05:00
|
|
|
func (b *BlockDevice) Prepare(ctx *interpolate.Context) error {
|
2018-10-12 16:01:13 -04:00
|
|
|
if b.DeviceName == "" {
|
|
|
|
return fmt.Errorf("The `device_name` must be specified " +
|
|
|
|
"for every device in the block device mapping.")
|
|
|
|
}
|
2018-01-12 18:10:51 -05:00
|
|
|
// Warn that encrypted must be true when setting kms_key_id
|
2018-11-26 05:33:44 -05:00
|
|
|
if b.KmsKeyId != "" && b.Encrypted != nil && *b.Encrypted == false {
|
2018-01-12 18:10:51 -05:00
|
|
|
return fmt.Errorf("The device %v, must also have `encrypted: "+
|
|
|
|
"true` when setting a kms_key_id.", b.DeviceName)
|
|
|
|
}
|
2019-05-03 12:39:52 -04:00
|
|
|
|
2014-09-05 15:38:19 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-01-12 18:10:51 -05:00
|
|
|
func (b *BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
|
|
|
|
for _, d := range b.AMIMappings {
|
|
|
|
if err := d.Prepare(ctx); err != nil {
|
|
|
|
errs = append(errs, fmt.Errorf("AMIMapping: %s", err.Error()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, d := range b.LaunchMappings {
|
|
|
|
if err := d.Prepare(ctx); err != nil {
|
|
|
|
errs = append(errs, fmt.Errorf("LaunchMapping: %s", err.Error()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return errs
|
|
|
|
}
|
|
|
|
|
2016-08-12 19:29:55 -04:00
|
|
|
func (b *AMIBlockDevices) BuildAMIDevices() []*ec2.BlockDeviceMapping {
|
2013-08-15 17:05:08 -04:00
|
|
|
return buildBlockDevices(b.AMIMappings)
|
|
|
|
}
|
|
|
|
|
2016-08-12 19:29:55 -04:00
|
|
|
func (b *LaunchBlockDevices) BuildLaunchDevices() []*ec2.BlockDeviceMapping {
|
2013-08-15 17:05:08 -04:00
|
|
|
return buildBlockDevices(b.LaunchMappings)
|
|
|
|
}
|
2019-05-03 12:39:52 -04:00
|
|
|
|
|
|
|
func (b *LaunchBlockDevices) GetOmissions() map[string]bool {
|
|
|
|
omitMap := make(map[string]bool)
|
|
|
|
|
|
|
|
for _, blockDevice := range b.LaunchMappings {
|
|
|
|
omitMap[blockDevice.DeviceName] = blockDevice.OmitFromArtifact
|
|
|
|
}
|
|
|
|
|
|
|
|
return omitMap
|
|
|
|
}
|