github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/common/block_device.go (about) 1 package common 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/aws/aws-sdk-go/aws" 8 "github.com/aws/aws-sdk-go/service/ec2" 9 "github.com/hashicorp/packer/template/interpolate" 10 ) 11 12 // BlockDevice 13 type BlockDevice struct { 14 DeleteOnTermination bool `mapstructure:"delete_on_termination"` 15 DeviceName string `mapstructure:"device_name"` 16 Encrypted bool `mapstructure:"encrypted"` 17 IOPS int64 `mapstructure:"iops"` 18 NoDevice bool `mapstructure:"no_device"` 19 SnapshotId string `mapstructure:"snapshot_id"` 20 VirtualName string `mapstructure:"virtual_name"` 21 VolumeType string `mapstructure:"volume_type"` 22 VolumeSize int64 `mapstructure:"volume_size"` 23 KmsKeyId string `mapstructure:"kms_key_id"` 24 } 25 26 type BlockDevices struct { 27 AMIBlockDevices `mapstructure:",squash"` 28 LaunchBlockDevices `mapstructure:",squash"` 29 } 30 31 type AMIBlockDevices struct { 32 AMIMappings []BlockDevice `mapstructure:"ami_block_device_mappings"` 33 } 34 35 type LaunchBlockDevices struct { 36 LaunchMappings []BlockDevice `mapstructure:"launch_block_device_mappings"` 37 } 38 39 func buildBlockDevices(b []BlockDevice) []*ec2.BlockDeviceMapping { 40 var blockDevices []*ec2.BlockDeviceMapping 41 42 for _, blockDevice := range b { 43 mapping := &ec2.BlockDeviceMapping{ 44 DeviceName: aws.String(blockDevice.DeviceName), 45 } 46 47 if blockDevice.NoDevice { 48 mapping.NoDevice = aws.String("") 49 } else if blockDevice.VirtualName != "" { 50 if strings.HasPrefix(blockDevice.VirtualName, "ephemeral") { 51 mapping.VirtualName = aws.String(blockDevice.VirtualName) 52 } 53 } else { 54 ebsBlockDevice := &ec2.EbsBlockDevice{ 55 DeleteOnTermination: aws.Bool(blockDevice.DeleteOnTermination), 56 } 57 58 if blockDevice.VolumeType != "" { 59 ebsBlockDevice.VolumeType = aws.String(blockDevice.VolumeType) 60 } 61 62 if blockDevice.VolumeSize > 0 { 63 ebsBlockDevice.VolumeSize = aws.Int64(blockDevice.VolumeSize) 64 } 65 66 // IOPS is only valid for io1 type 67 if blockDevice.VolumeType == "io1" { 68 ebsBlockDevice.Iops = aws.Int64(blockDevice.IOPS) 69 } 70 71 // You cannot specify Encrypted if you specify a Snapshot ID 72 if blockDevice.SnapshotId != "" { 73 ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId) 74 } else if blockDevice.Encrypted { 75 ebsBlockDevice.Encrypted = aws.Bool(blockDevice.Encrypted) 76 } 77 78 if blockDevice.KmsKeyId != "" { 79 ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId) 80 } 81 82 mapping.Ebs = ebsBlockDevice 83 } 84 85 blockDevices = append(blockDevices, mapping) 86 } 87 return blockDevices 88 } 89 90 func (b *BlockDevice) Prepare(ctx *interpolate.Context) error { 91 if b.DeviceName == "" { 92 return fmt.Errorf("The `device_name` must be specified " + 93 "for every device in the block device mapping.") 94 } 95 // Warn that encrypted must be true when setting kms_key_id 96 if b.KmsKeyId != "" && b.Encrypted == false { 97 return fmt.Errorf("The device %v, must also have `encrypted: "+ 98 "true` when setting a kms_key_id.", b.DeviceName) 99 } 100 return nil 101 } 102 103 func (b *BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) { 104 for _, d := range b.AMIMappings { 105 if err := d.Prepare(ctx); err != nil { 106 errs = append(errs, fmt.Errorf("AMIMapping: %s", err.Error())) 107 } 108 } 109 for _, d := range b.LaunchMappings { 110 if err := d.Prepare(ctx); err != nil { 111 errs = append(errs, fmt.Errorf("LaunchMapping: %s", err.Error())) 112 } 113 } 114 return errs 115 } 116 117 func (b *AMIBlockDevices) BuildAMIDevices() []*ec2.BlockDeviceMapping { 118 return buildBlockDevices(b.AMIMappings) 119 } 120 121 func (b *LaunchBlockDevices) BuildLaunchDevices() []*ec2.BlockDeviceMapping { 122 return buildBlockDevices(b.LaunchMappings) 123 }