packer-cn/builder/amazon/common/block_device.go

162 lines
5.6 KiB
Go
Raw Normal View History

//go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type BlockDevice
package common
import (
"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"
"github.com/hashicorp/packer/helper/config"
2017-04-04 16:39:01 -04:00
"github.com/hashicorp/packer/template/interpolate"
)
// These will be attached when booting a new instance from your AMI. Your
// options here may vary depending on the type of VM you use.
//
// Example use case:
//
// The following mapping will tell Packer to encrypt the root volume of the
// build instance at launch using a specific non-default kms key:
2019-06-18 11:05:10 -04:00
//
// ```json
// [{
// "device_name": "/dev/sda1",
// "encrypted": true,
// "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d"
// }]
2019-06-18 11:05:10 -04:00
// ```
//
2019-06-18 11:37:33 -04:00
// Documentation for Block Devices Mappings can be found here:
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html
//
type BlockDevice struct {
2019-06-18 05:55:12 -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.
2019-06-03 11:55:09 -04:00
DeleteOnTermination bool `mapstructure:"delete_on_termination" required:"false"`
2019-06-18 05:55:12 -04:00
// The device name exposed to the instance (for example, /dev/sdh or xvdh).
// Required for every device in the block device mapping.
2019-06-03 11:55:09 -04:00
DeviceName string `mapstructure:"device_name" required:"false"`
2019-06-18 05:55:12 -04:00
// 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 config.Trilean `mapstructure:"encrypted" required:"false"`
2019-06-18 05:55:12 -04:00
// The number of I/O operations per second (IOPS) that the volume supports.
// See the documentation on
// [IOPs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html)
// for more information
2019-06-03 11:55:09 -04:00
IOPS int64 `mapstructure:"iops" required:"false"`
2019-06-18 05:55:12 -04:00
// Suppresses the specified device included in the block device mapping of
// the AMI.
2019-06-03 11:55:09 -04:00
NoDevice bool `mapstructure:"no_device" required:"false"`
// The ID of the snapshot.
2019-06-03 11:55:09 -04:00
SnapshotId string `mapstructure:"snapshot_id" required:"false"`
2019-06-18 05:55:12 -04:00
// The virtual device name. See the documentation on Block Device Mapping
2019-06-03 11:55:09 -04:00
// for more information.
VirtualName string `mapstructure:"virtual_name" required:"false"`
2019-06-18 05:55:12 -04:00
// 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.
2019-06-03 11:55:09 -04:00
VolumeType string `mapstructure:"volume_type" required:"false"`
2019-06-18 05:55:12 -04:00
// The size of the volume, in GiB. Required if not specifying a
// snapshot_id.
2019-06-03 11:55:09 -04:00
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](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html)
// 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"`
}
type BlockDevices []BlockDevice
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.ToBoolPointer()
if blockDevice.KmsKeyId != "" {
ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId)
}
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.")
}
// Warn that encrypted must be true or nil when setting kms_key_id
if b.KmsKeyId != "" && b.Encrypted.False() {
return fmt.Errorf("The device %v, must also have `encrypted: "+
"true` when setting a kms_key_id.", b.DeviceName)
}
_, err := interpolate.RenderInterface(&b, ctx)
return err
}
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
}