From 3b84fe57c5bab032b6794730fda4612df9cad2a7 Mon Sep 17 00:00:00 2001 From: Timon Wong Date: Tue, 6 Dec 2016 13:21:35 +0800 Subject: [PATCH] provider/aws: Add "no_device" support to ephemeral block devices Fixes #8455, #5390 This add a new `no_device` attribute to `ephemeral_block_device` block, which allows users omit ephemeral devices from AMI's predefined block device mappings, which is useful for EBS-only instance types. --- .../providers/aws/resource_aws_instance.go | 27 ++++++-- .../aws/resource_aws_instance_test.go | 64 +++++++++++++++++++ .../providers/aws/r/instance.html.markdown | 5 +- 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index ed96912510c9..d657f1334270 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -268,7 +268,13 @@ func resourceAwsInstance() *schema.Resource { "virtual_name": &schema.Schema{ Type: schema.TypeString, - Required: true, + Optional: true, + }, + + "no_device": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, }, }, }, @@ -276,7 +282,11 @@ func resourceAwsInstance() *schema.Resource { var buf bytes.Buffer m := v.(map[string]interface{}) buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string))) - buf.WriteString(fmt.Sprintf("%s-", m["virtual_name"].(string))) + if m["no_device"].(bool) { + buf.WriteString(fmt.Sprintf("%t-", m["no_device"].(bool))) + } else { + buf.WriteString(fmt.Sprintf("%s-", m["virtual_name"].(string))) + } return hashcode.String(buf.String()) }, }, @@ -936,10 +946,15 @@ func readBlockDeviceMappingsFromConfig( vL := v.(*schema.Set).List() for _, v := range vL { bd := v.(map[string]interface{}) - blockDevices = append(blockDevices, &ec2.BlockDeviceMapping{ - DeviceName: aws.String(bd["device_name"].(string)), - VirtualName: aws.String(bd["virtual_name"].(string)), - }) + bdm := &ec2.BlockDeviceMapping{ + DeviceName: aws.String(bd["device_name"].(string)), + } + if bd["no_device"].(bool) { + bdm.NoDevice = aws.String("") + } else { + bdm.VirtualName = aws.String(bd["virtual_name"].(string)) + } + blockDevices = append(blockDevices, bdm) } } diff --git a/builtin/providers/aws/resource_aws_instance_test.go b/builtin/providers/aws/resource_aws_instance_test.go index 38c2dccfc80e..450802046a22 100644 --- a/builtin/providers/aws/resource_aws_instance_test.go +++ b/builtin/providers/aws/resource_aws_instance_test.go @@ -285,6 +285,70 @@ func TestAccAWSInstance_rootInstanceStore(t *testing.T) { }) } +func TestAcctABSInstance_noAMIEphemeralDevices(t *testing.T) { + var v ec2.Instance + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_instance.foo", + IDRefreshIgnore: []string{ + "ephemeral_block_device", "security_groups", "vpc_security_groups"}, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: ` + resource "aws_instance" "foo" { + # us-west-2 + ami = "ami-01f05461" // This AMI (Ubuntu) contains two ephemerals + + instance_type = "m4.medium" + + root_block_device { + volume_type = "gp2" + volume_size = 11 + } + ephemeral_block_device { + device_name = "/dev/sdb" + no_device = true + } + ephemeral_block_device { + device_name = "/dev/sdc" + no_device = true + }`, + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists( + "aws_instance.foo", &v), + resource.TestCheckResourceAttr( + "aws_instance.foo", "ami", "ami-01f05461"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "ebs_optimized", "false"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "instance_type", "m4.medium"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "root_block_device.#", "1"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "root_block_device.0.volume_size", "11"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "root_block_device.0.volume_type", "gp2"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "ebs_block_device.#", "0"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "ephemeral_block_device.#", "2"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "ephemeral_block_device.1689158549.device_name", "/dev/sdb"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "ephemeral_block_device.1689158549.no_device", "true"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "ephemeral_block_device.1025931231.device_name", "/dev/sdc"), + resource.TestCheckResourceAttr( + "aws_instance.foo", "ephemeral_block_device.1025931231.no_device", "true"), + ), + }, + }, + }) +} + func TestAccAWSInstance_sourceDestCheck(t *testing.T) { var v ec2.Instance diff --git a/website/source/docs/providers/aws/r/instance.html.markdown b/website/source/docs/providers/aws/r/instance.html.markdown index cd331da91b28..6a6ef69417d2 100644 --- a/website/source/docs/providers/aws/r/instance.html.markdown +++ b/website/source/docs/providers/aws/r/instance.html.markdown @@ -126,9 +126,10 @@ Modifying any `ebs_block_device` currently requires resource replacement. Each `ephemeral_block_device` supports the following: * `device_name` - The name of the block device to mount on the instance. -* `virtual_name` - The [Instance Store Device +* `virtual_name` - (Optional) The [Instance Store Device Name](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html#InstanceStoreDeviceNames) - (e.g. `"ephemeral0"`) + (e.g. `"ephemeral0"`). +* `no_device` - (Optional) Suppresses the specified device included in the AMI's block device mapping. Each AWS Instance type has a different set of Instance Store block devices available for attachment. AWS [publishes a