From 44d0fb559ad0e8f06057b6cf72b41ccb0b050553 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Mon, 7 Dec 2020 01:52:38 -0500 Subject: [PATCH 01/12] aws_instance: Allow iops attribute to be set for gp3 volumes --- aws/resource_aws_instance.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index 626d9116e85..12247d1858a 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -585,11 +585,11 @@ func resourceAwsInstance() *schema.Resource { } func iopsDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { - // Suppress diff if volume_type is not io1 or io2 and iops is unset or configured as 0 + // Suppress diff if volume_type is not io1, io2, or gp3 and iops is unset or configured as 0 i := strings.LastIndexByte(k, '.') vt := k[:i+1] + "volume_type" v := d.Get(vt).(string) - return (strings.ToLower(v) != ec2.VolumeTypeIo1 || strings.ToLower(v) != ec2.VolumeTypeIo2) && new == "0" + return (strings.ToLower(v) != ec2.VolumeTypeIo1 || strings.ToLower(v) != ec2.VolumeTypeIo2 || strings.ToLower(v) != ec2.VolumeTypeGp3) && new == "0" } func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error { @@ -1399,7 +1399,7 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { if v, ok := d.Get("root_block_device.0.iops").(int); ok && v != 0 { // Enforce IOPs usage with a valid volume type // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/12667 - if t, ok := d.Get("root_block_device.0.volume_type").(string); ok && t != ec2.VolumeTypeIo1 && t != ec2.VolumeTypeIo2 { + if t, ok := d.Get("root_block_device.0.volume_type").(string); ok && t != ec2.VolumeTypeIo1 && t != ec2.VolumeTypeIo2 && t != ec2.volumeTypeGp3 { if t == "" { // Volume defaults to gp2 t = ec2.VolumeTypeGp2 @@ -1931,9 +1931,9 @@ func readBlockDeviceMappingsFromConfig(d *schema.ResourceData, conn *ec2.EC2) ([ if v, ok := bd["volume_type"].(string); ok && v != "" { ebs.VolumeType = aws.String(v) if iops, ok := bd["iops"].(int); ok && iops > 0 { - if ec2.VolumeTypeIo1 == strings.ToLower(v) || ec2.VolumeTypeIo2 == strings.ToLower(v) { + if ec2.VolumeTypeIo1 == strings.ToLower(v) || ec2.VolumeTypeIo2 == strings.ToLower(v) || ec2.volumeTypeGp3 == strings.ToLower(v) { // Condition: This parameter is required for requests to create io1 or io2 - // volumes; it is not used in requests to create gp2, st1, sc1, or + // volumes and optional for gp3; it is not used in requests to create gp2, st1, sc1, or // standard volumes. // See: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html ebs.Iops = aws.Int64(int64(iops)) @@ -1997,8 +1997,8 @@ func readBlockDeviceMappingsFromConfig(d *schema.ResourceData, conn *ec2.EC2) ([ if v, ok := bd["volume_type"].(string); ok && v != "" { ebs.VolumeType = aws.String(v) if iops, ok := bd["iops"].(int); ok && iops > 0 { - if ec2.VolumeTypeIo1 == strings.ToLower(v) || ec2.VolumeTypeIo2 == strings.ToLower(v) { - // Only set the iops attribute if the volume type is io1 or io2. Setting otherwise + if ec2.VolumeTypeIo1 == strings.ToLower(v) || ec2.VolumeTypeIo2 == strings.ToLower(v) || ec2.VolumeTypeGp3 == strings.ToLower(v) { + // Only set the iops attribute if the volume type is io1, io2, or gp3. Setting otherwise // can trigger a refresh/plan loop based on the computed value that is given // from AWS, and prevent us from specifying 0 as a valid iops. // See https://github.com/hashicorp/terraform/pull/4146 From ee0fcbfb40777b2242a3f9b71814667b884ed744 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Mon, 7 Dec 2020 02:24:42 -0500 Subject: [PATCH 02/12] aws_instance: Add support for throughput attribute --- aws/resource_aws_instance.go | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index 12247d1858a..e5abde08b40 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -389,6 +389,14 @@ func resourceAwsInstance() *schema.Resource { ForceNew: true, }, + "throughput": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + DiffSuppressFunc: throughputDiffSuppressFunc, + }, + "volume_size": { Type: schema.TypeInt, Optional: true, @@ -496,6 +504,13 @@ func resourceAwsInstance() *schema.Resource { DiffSuppressFunc: iopsDiffSuppressFunc, }, + "throughput": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + DiffSuppressFunc: throughputDiffSuppressFunc, + }, + "volume_size": { Type: schema.TypeInt, Optional: true, @@ -592,6 +607,14 @@ func iopsDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { return (strings.ToLower(v) != ec2.VolumeTypeIo1 || strings.ToLower(v) != ec2.VolumeTypeIo2 || strings.ToLower(v) != ec2.VolumeTypeGp3) && new == "0" } +func throughputDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + // Suppress diff if volume_type is not gp3 and throughput is unset or configured as 0 + i := strings.LastIndexByte(k, '.') + vt := k[:i+1] + "volume_type" + v := d.Get(vt).(string) + return strings.ToLower(v) != ec2.VolumeTypeGp3 && new == "0" +} + func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn @@ -1410,6 +1433,16 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { input.Iops = aws.Int64(int64(v)) } } + if d.HasChange("root_block_device.0.throughput") { + if v, ok := d.Get("root_block_device.0.throughput").(int); ok && v != 0 { + // Enforce throughput usage with a valid volume type + if t, ok := d.Get("root_block_device.0.volume_type").(string); ok && t != ec2.volumeTypeGp3 { + return fmt.Errorf("error updating instance: throughput attribute not supported for type %s", t) + } + modifyVolume = true + input.Throughput = aws.Int64(int64(v)) + } + } if modifyVolume { _, err := conn.ModifyVolume(&input) if err != nil { @@ -1743,6 +1776,9 @@ func readBlockDevicesFromInstance(instance *ec2.Instance, conn *ec2.EC2) (map[st if vol.KmsKeyId != nil { bd["kms_key_id"] = aws.StringValue(vol.KmsKeyId) } + if vol.Throughput != nil { + bd["throughput"] = aws.Int64Value(vol.Throughput) + } if instanceBd.DeviceName != nil { bd["device_name"] = aws.StringValue(instanceBd.DeviceName) } @@ -1942,6 +1978,13 @@ func readBlockDeviceMappingsFromConfig(d *schema.ResourceData, conn *ec2.EC2) ([ // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/12667 return nil, fmt.Errorf("error creating resource: iops attribute not supported for ebs_block_device with volume_type %s", v) } + } else if throughput, ok := bd["throughput"].(int); ok && throughput > 0 { + // `throughput` is only valid for gp3 + if ec2.VolumeTypeGp3 == strings.ToLower(v) { + ebs.Throughput = aws.Int64(int64(throughput)) + } else { + return nil, fmt.Errorf("error creating resource: throughput attribute not supported for ebs_block_device with volume_type %s", v) + } } } @@ -2009,6 +2052,14 @@ func readBlockDeviceMappingsFromConfig(d *schema.ResourceData, conn *ec2.EC2) ([ // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/12667 return nil, fmt.Errorf("error creating resource: iops attribute not supported for root_block_device with volume_type %s", v) } + } else if throughput, ok := bd["throughput"].(int); ok && throughput > 0 { + // throughput is only valid for gp3 + if ec2.VolumeTypeGp3 == strings.ToLower(v) { + ebs.Throughput = aws.Int64(int64(throughput)) + } else { + // Enforce throughput usage with a valid volume type + return nil, fmt.Errorf("error creating resource: throughput attribute not supported for root_block_device with volume_type %s", v) + } } } From 1955595dc76bcbc6056f1dd9e772e06c1c0b91d8 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Mon, 7 Dec 2020 14:22:29 -0500 Subject: [PATCH 03/12] aws_instance: Write tests for throughput attribute --- aws/resource_aws_instance_test.go | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index e50b8a14c3c..8f412dbc870 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -494,6 +494,10 @@ func TestAccAWSInstance_blockDevices(t *testing.T) { return fmt.Errorf("block device doesn't exist: /dev/sdd") } + if _, ok := blockDevices["/dev/sde"]; !ok { + return fmt.Errorf("block device doesn't exist: /dev/sde") + } + return nil } } @@ -530,6 +534,12 @@ func TestAccAWSInstance_blockDevices(t *testing.T) { "volume_type": "io1", "iops": "100", }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "ebs_block_device.*", map[string]string{ + "device_name": "/dev/sde", + "volume_size": "10", + "volume_type": "gp3", + "throughput": "1000", + }), resource.TestMatchTypeSetElemNestedAttrs(resourceName, "ebs_block_device.*", map[string]*regexp.Regexp{ "volume_id": regexp.MustCompile("vol-[a-z0-9]+"), }), @@ -1654,6 +1664,48 @@ func TestAccAWSInstance_EbsRootDevice_ModifyIOPS_Io2(t *testing.T) { }) } +func TestAccAWSInstance_EbsRootDevice_ModifyThroughput_Gp3(t *testing.T) { + var original ec2.Instance + var updated ec2.Instance + resourceName := "aws_instance.test" + + volumeSize := "30" + deleteOnTermination := "true" + volumeType := "gp3" + + originalThroughput := "250" + updatedThroughput := "300" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsEc2InstanceRootBlockDeviceWithThroughput(volumeSize, deleteOnTermination, volumeType, originalThroughput), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resourceName, &original), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_size", volumeSize), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.delete_on_termination", deleteOnTermination), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_type", volumeType), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.throughput", originalThroughput), + ), + }, + { + Config: testAccAwsEc2InstanceRootBlockDeviceWithThroughput(volumeSize, deleteOnTermination, volumeType, updatedThroughput), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resourceName, &updated), + testAccCheckInstanceNotRecreated(t, &original, &updated), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_size", volumeSize), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.delete_on_termination", deleteOnTermination), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_type", volumeType), + resource.TestCheckResourceAttr(resourceName, "root_block_device.0.throughput", updatedThroughput), + ), + }, + }, + }) +} + func TestAccAWSInstance_EbsRootDevice_ModifyDeleteOnTermination(t *testing.T) { var original ec2.Instance var updated ec2.Instance @@ -3556,6 +3608,27 @@ resource "aws_instance" "test" { `, size, delete, volumeType, iops)) } +func testAccAwsEc2InstanceRootBlockDeviceWithThroughput(size, delete, volumeType, throughput string) string { + if throughput == "" { + throughput = "null" + } + return composeConfig(testAccAwsEc2InstanceAmiWithEbsRootVolume, + fmt.Sprintf(` +resource "aws_instance" "test" { + ami = data.aws_ami.ami.id + + instance_type = "t2.medium" + + root_block_device { + volume_size = %[1]s + delete_on_termination = %[2]s + volume_type = %[3]q + throughput = %[4]s + } +} +`, size, delete, volumeType, throughput)) +} + const testAccAwsEc2InstanceAmiWithEbsRootVolume = ` data "aws_ami" "ami" { owners = ["amazon"] From 4d8b7e636d30758368137b3e9abb0765ce8a48bf Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Mon, 7 Dec 2020 14:37:45 -0500 Subject: [PATCH 04/12] aws_instance: Fix typo --- aws/resource_aws_instance.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index e5abde08b40..ceae2823ff9 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -1422,7 +1422,7 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { if v, ok := d.Get("root_block_device.0.iops").(int); ok && v != 0 { // Enforce IOPs usage with a valid volume type // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/12667 - if t, ok := d.Get("root_block_device.0.volume_type").(string); ok && t != ec2.VolumeTypeIo1 && t != ec2.VolumeTypeIo2 && t != ec2.volumeTypeGp3 { + if t, ok := d.Get("root_block_device.0.volume_type").(string); ok && t != ec2.VolumeTypeIo1 && t != ec2.VolumeTypeIo2 && t != ec2.VolumeTypeGp3 { if t == "" { // Volume defaults to gp2 t = ec2.VolumeTypeGp2 @@ -1436,7 +1436,7 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { if d.HasChange("root_block_device.0.throughput") { if v, ok := d.Get("root_block_device.0.throughput").(int); ok && v != 0 { // Enforce throughput usage with a valid volume type - if t, ok := d.Get("root_block_device.0.volume_type").(string); ok && t != ec2.volumeTypeGp3 { + if t, ok := d.Get("root_block_device.0.volume_type").(string); ok && t != ec2.VolumeTypeGp3 { return fmt.Errorf("error updating instance: throughput attribute not supported for type %s", t) } modifyVolume = true @@ -1967,7 +1967,7 @@ func readBlockDeviceMappingsFromConfig(d *schema.ResourceData, conn *ec2.EC2) ([ if v, ok := bd["volume_type"].(string); ok && v != "" { ebs.VolumeType = aws.String(v) if iops, ok := bd["iops"].(int); ok && iops > 0 { - if ec2.VolumeTypeIo1 == strings.ToLower(v) || ec2.VolumeTypeIo2 == strings.ToLower(v) || ec2.volumeTypeGp3 == strings.ToLower(v) { + if ec2.VolumeTypeIo1 == strings.ToLower(v) || ec2.VolumeTypeIo2 == strings.ToLower(v) || ec2.VolumeTypeGp3 == strings.ToLower(v) { // Condition: This parameter is required for requests to create io1 or io2 // volumes and optional for gp3; it is not used in requests to create gp2, st1, sc1, or // standard volumes. From 7f525cb6f41ae32158e701b1405483c6c142ae04 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Mon, 7 Dec 2020 15:42:36 -0500 Subject: [PATCH 05/12] aws_instance: Add a negative acceptance test --- aws/resource_aws_instance_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index 8f412dbc870..48fd456af43 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -340,6 +340,20 @@ func TestAccAWSInstance_EbsBlockDevice_InvalidIopsForVolumeType(t *testing.T) { }) } +func TestAccAWSInstance_EbsBlockDevice_InvalidThroughputForVolumeType(t *testing.T) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckInstanceConfigEBSBlockDeviceInvalidThroughput, + ExpectError: regexp.MustCompile(`error creating resource: throughput attribute not supported for ebs_block_device with volume_type gp2`), + }, + }, + }) +} + func TestAccAWSInstance_RootBlockDevice_KmsKeyArn(t *testing.T) { var instance ec2.Instance kmsKeyResourceName := "aws_kms_key.test" @@ -4003,6 +4017,21 @@ resource "aws_instance" "test" { } `) +var testAccCheckInstanceConfigEBSBlockDeviceInvalidThroughput = composeConfig(testAccAwsEc2InstanceAmiWithEbsRootVolume, ` +resource "aws_instance" "test" { + ami = data.aws_ami.ami.id + + instance_type = "t2.medium" + + ebs_block_device { + device_name = "/dev/sdc" + volume_size = 10 + volume_type = "gp2" + throughput = 300 + } +} +`) + func testAccCheckInstanceConfigWithVolumeTags() string { return composeConfig(testAccLatestAmazonLinuxHvmEbsAmiConfig(), fmt.Sprintf(` resource "aws_instance" "test" { From b1fc67a0b478f88fa8f652b7fa5941f26f6a230b Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Mon, 7 Dec 2020 16:23:00 -0500 Subject: [PATCH 06/12] aws_instance: Update docs to add info about gp3 and throughput attribute --- website/docs/r/instance.html.markdown | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/website/docs/r/instance.html.markdown b/website/docs/r/instance.html.markdown index 55d6a9498df..c61535d2cb2 100644 --- a/website/docs/r/instance.html.markdown +++ b/website/docs/r/instance.html.markdown @@ -130,8 +130,8 @@ The `root_block_device` mapping supports the following: * `volume_size` - (Optional) The size of the volume in gibibytes (GiB). * `iops` - (Optional) The amount of provisioned [IOPS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-io-characteristics.html). - This is only valid for `volume_type` of `"io1/io2"`, and must be specified if - using that type + This is only valid for `volume_type` of `"io1/io2"` (required) and `"gp3"` (optional). +* `throughput` - (Optional) The throughput to provision for a volume in mebibytes per second (MiB/s). This is only valid for `volume_type` of `"gp3"`. * `delete_on_termination` - (Optional) Whether the volume should be destroyed on instance termination (Default: `true`). * `encrypted` - (Optional) Enable volume encryption. (Default: `false`). Must be configured to perform drift detection. @@ -149,7 +149,8 @@ Each `ebs_block_device` supports the following: * `volume_size` - (Optional) The size of the volume in gibibytes (GiB). * `iops` - (Optional) The amount of provisioned [IOPS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-io-characteristics.html). - This must be set with a `volume_type` of `"io1/io2"`. + This is only valid for `volume_type` of `"io1/io2"` (required) and `"gp3"` (optional). +* `throughput` - (Optional) The throughput to provision for a volume in mebibytes per second (MiB/s). This is only valid for `volume_type` of `"gp3"`. * `delete_on_termination` - (Optional) Whether the volume should be destroyed on instance termination (Default: `true`). * `encrypted` - (Optional) Enables [EBS From 1d74e4cfd0a711e282a5e3a6521238226bcaf604 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Fri, 11 Dec 2020 13:48:00 -0500 Subject: [PATCH 07/12] aws_instance: Update docs --- website/docs/r/instance.html.markdown | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/website/docs/r/instance.html.markdown b/website/docs/r/instance.html.markdown index c61535d2cb2..aee60122ab3 100644 --- a/website/docs/r/instance.html.markdown +++ b/website/docs/r/instance.html.markdown @@ -126,11 +126,10 @@ to understand the implications of using these attributes. The `root_block_device` mapping supports the following: -* `volume_type` - (Optional) The type of volume. Can be `"standard"`, `"gp2"`, `"io1"`, `"io2"`, `"sc1"`, or `"st1"`. (Default: `"gp2"`). +* `volume_type` - (Optional) The type of volume. Can be `"standard"`, `"gp2"`, `"gp3"`, `"io1"`, `"io2"`, `"sc1"`, or `"st1"`. (Default: `"gp2"`). * `volume_size` - (Optional) The size of the volume in gibibytes (GiB). * `iops` - (Optional) The amount of provisioned - [IOPS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-io-characteristics.html). - This is only valid for `volume_type` of `"io1/io2"` (required) and `"gp3"` (optional). + [IOPS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-io-characteristics.html). Only valid for volume_type of `"io1"`, `"io2"` or `"gp3"`. * `throughput` - (Optional) The throughput to provision for a volume in mebibytes per second (MiB/s). This is only valid for `volume_type` of `"gp3"`. * `delete_on_termination` - (Optional) Whether the volume should be destroyed on instance termination (Default: `true`). @@ -144,12 +143,11 @@ Each `ebs_block_device` supports the following: * `device_name` - (Required) The name of the device to mount. * `snapshot_id` - (Optional) The Snapshot ID to mount. -* `volume_type` - (Optional) The type of volume. Can be `"standard"`, `"gp2"`, `"io1"` - or `"io2"`. (Default: `"gp2"`). +* `volume_type` - (Optional) The type of volume. Can be `"standard"`, `"gp2"`, `"gp3"`, `"io1"`, `"io2"`, `"sc1"`, or `"st1"`. (Default: `"gp2"`). * `volume_size` - (Optional) The size of the volume in gibibytes (GiB). * `iops` - (Optional) The amount of provisioned [IOPS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-io-characteristics.html). - This is only valid for `volume_type` of `"io1/io2"` (required) and `"gp3"` (optional). + Only valid for volume_type of `"io1"`, `"io2"` or `"gp3"`. * `throughput` - (Optional) The throughput to provision for a volume in mebibytes per second (MiB/s). This is only valid for `volume_type` of `"gp3"`. * `delete_on_termination` - (Optional) Whether the volume should be destroyed on instance termination (Default: `true`). From 0ac70181201e155f408d2ed803d268219c7c66dd Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Fri, 11 Dec 2020 13:49:34 -0500 Subject: [PATCH 08/12] aws_instance: Fix bug in iopsDiffSuppressFunc Co-authored-by: Kit Ewbank --- aws/resource_aws_instance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index ceae2823ff9..ad8f47f16b3 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -604,7 +604,7 @@ func iopsDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { i := strings.LastIndexByte(k, '.') vt := k[:i+1] + "volume_type" v := d.Get(vt).(string) - return (strings.ToLower(v) != ec2.VolumeTypeIo1 || strings.ToLower(v) != ec2.VolumeTypeIo2 || strings.ToLower(v) != ec2.VolumeTypeGp3) && new == "0" + return (strings.ToLower(v) != ec2.VolumeTypeIo1 && strings.ToLower(v) != ec2.VolumeTypeIo2 && strings.ToLower(v) != ec2.VolumeTypeGp3) && new == "0" } func throughputDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { From c7f42b0872c4a0205bf02019779605a2f5c9d6fd Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Fri, 11 Dec 2020 16:29:34 -0500 Subject: [PATCH 09/12] aws_instance: Update data source for throughput attribute --- aws/data_source_aws_instance.go | 10 ++++++ aws/data_source_aws_instance_test.go | 49 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/aws/data_source_aws_instance.go b/aws/data_source_aws_instance.go index 826322a6503..a01b73c31b4 100644 --- a/aws/data_source_aws_instance.go +++ b/aws/data_source_aws_instance.go @@ -208,6 +208,11 @@ func dataSourceAwsInstance() *schema.Resource { Computed: true, }, + "throughput": { + Type: schema.TypeInt, + Computed: true, + }, + "volume_size": { Type: schema.TypeInt, Computed: true, @@ -263,6 +268,11 @@ func dataSourceAwsInstance() *schema.Resource { Computed: true, }, + "throughput": { + Type: schema.TypeInt, + Computed: true, + }, + "volume_size": { Type: schema.TypeInt, Computed: true, diff --git a/aws/data_source_aws_instance_test.go b/aws/data_source_aws_instance_test.go index e8c56d7caaa..d6b46e90bfa 100644 --- a/aws/data_source_aws_instance_test.go +++ b/aws/data_source_aws_instance_test.go @@ -98,6 +98,30 @@ func TestAccAWSInstanceDataSource_gp2IopsDevice(t *testing.T) { }) } +func TestAccAWSInstanceDataSource_gp3ThroughputDevice(t *testing.T) { + resourceName := "aws_instance.test" + datasourceName := "data.aws_instance.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccInstanceDataSourceConfig_gp3ThroughputDevice, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(datasourceName, "ami", resourceName, "ami"), + resource.TestCheckResourceAttrPair(datasourceName, "instance_type", resourceName, "instance_type"), + resource.TestCheckResourceAttrPair(datasourceName, "root_block_device.#", resourceName, "root_block_device.#"), + resource.TestCheckResourceAttrPair(datasourceName, "root_block_device.0.volume_size", resourceName, "root_block_device.0.volume_size"), + resource.TestCheckResourceAttrPair(datasourceName, "root_block_device.0.volume_type", resourceName, "root_block_device.0.volume_type"), + resource.TestCheckResourceAttrPair(datasourceName, "root_block_device.0.device_name", resourceName, "root_block_device.0.device_name"), + resource.TestCheckResourceAttrPair(datasourceName, "root_block_device.0.throughput", resourceName, "root_block_device.0.throughput"), + ), + }, + }, + }) +} + func TestAccAWSInstanceDataSource_blockDevices(t *testing.T) { resourceName := "aws_instance.test" datasourceName := "data.aws_instance.test" @@ -567,6 +591,24 @@ data "aws_instance" "test" { } ` +// GP3ThroughputDevice +var testAccInstanceDataSourceConfig_gp3ThroughputDevice = testAccLatestAmazonLinuxHvmEbsAmiConfig() + ` +resource "aws_instance" "test" { + ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = "t3.medium" + + root_block_device { + volume_type = "gp3" + volume_size = 10 + throughput = 300 + } +} + +data "aws_instance" "test" { + instance_id = aws_instance.test.id +} +` + // Block Device var testAccInstanceDataSourceConfig_blockDevices = testAccLatestAmazonLinuxHvmEbsAmiConfig() + ` resource "aws_instance" "test" { @@ -601,6 +643,13 @@ resource "aws_instance" "test" { device_name = "/dev/sde" virtual_name = "ephemeral0" } + + ebs_block_device { + device_name = "/device/sdf" + volume_size = 10 + volume_type = "gp3" + throughput = 300 + } } data "aws_instance" "test" { From 0526d91a5a6179d7918a6b147294175e52cba545 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Mon, 14 Dec 2020 19:04:05 -0500 Subject: [PATCH 10/12] aws_instance: Fix typo Co-authored-by: Kit Ewbank --- aws/data_source_aws_instance_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/data_source_aws_instance_test.go b/aws/data_source_aws_instance_test.go index d6b46e90bfa..76ffdee1eb5 100644 --- a/aws/data_source_aws_instance_test.go +++ b/aws/data_source_aws_instance_test.go @@ -645,7 +645,7 @@ resource "aws_instance" "test" { } ebs_block_device { - device_name = "/device/sdf" + device_name = "/dev/sdf" volume_size = 10 volume_type = "gp3" throughput = 300 From 2d2248c996571fdd50b28c7577494c75f5275354 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Tue, 15 Dec 2020 13:56:06 -0500 Subject: [PATCH 11/12] aws_instance: Fix TestAccAWSInstance_blockDevices test --- aws/resource_aws_instance_test.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index 48fd456af43..e6b5b0b9108 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -533,7 +533,7 @@ func TestAccAWSInstance_blockDevices(t *testing.T) { resource.TestMatchResourceAttr(resourceName, "root_block_device.0.volume_id", regexp.MustCompile("vol-[a-z0-9]+")), resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_size", rootVolumeSize), resource.TestCheckResourceAttr(resourceName, "root_block_device.0.volume_type", "gp2"), - resource.TestCheckResourceAttr(resourceName, "ebs_block_device.#", "3"), + resource.TestCheckResourceAttr(resourceName, "ebs_block_device.#", "4"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "ebs_block_device.*", map[string]string{ "device_name": "/dev/sdb", "volume_size": "9", @@ -549,10 +549,10 @@ func TestAccAWSInstance_blockDevices(t *testing.T) { "iops": "100", }), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "ebs_block_device.*", map[string]string{ - "device_name": "/dev/sde", + "device_name": "/dev/sdf", "volume_size": "10", "volume_type": "gp3", - "throughput": "1000", + "throughput": "300", }), resource.TestMatchTypeSetElemNestedAttrs(resourceName, "ebs_block_device.*", map[string]*regexp.Regexp{ "volume_id": regexp.MustCompile("vol-[a-z0-9]+"), @@ -3710,6 +3710,14 @@ resource "aws_instance" "test" { device_name = "/dev/sde" virtual_name = "ephemeral0" } + + ebs_block_device { + device_name = "/dev/sdf" + volume_size = 10 + volume_type = "gp3" + throughput = 300 + } + } `, size, delete)) } From c3af2ad7e434ac3cde973b9d3789f59340f41818 Mon Sep 17 00:00:00 2001 From: Rajiv Shah Date: Tue, 15 Dec 2020 17:18:26 -0500 Subject: [PATCH 12/12] aws_instance: Fix test failure Co-authored-by: Kit Ewbank --- aws/resource_aws_instance_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index e6b5b0b9108..081117f1032 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -508,8 +508,8 @@ func TestAccAWSInstance_blockDevices(t *testing.T) { return fmt.Errorf("block device doesn't exist: /dev/sdd") } - if _, ok := blockDevices["/dev/sde"]; !ok { - return fmt.Errorf("block device doesn't exist: /dev/sde") + if _, ok := blockDevices["/dev/sdf"]; !ok { + return fmt.Errorf("block device doesn't exist: /dev/sdf") } return nil