diff --git a/aws/resource_aws_instance.go b/aws/resource_aws_instance.go index 65637d7a05c..c0b0645ba11 100644 --- a/aws/resource_aws_instance.go +++ b/aws/resource_aws_instance.go @@ -479,6 +479,13 @@ func resourceAwsInstance() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "standard", + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if strings.HasPrefix(d.Get("instance_type").(string), "t3") && + old == "unlimited" && new == "standard" { + return true + } + return false + }, }, }, }, @@ -1741,15 +1748,22 @@ func buildAwsInstanceOpts( InstanceType: aws.String(instanceType), } + // Set default cpu_credits as Unlimited for T3 instance type + if strings.HasPrefix(instanceType, "t3") { + opts.CreditSpecification = &ec2.CreditSpecificationRequest{ + CpuCredits: aws.String("unlimited"), + } + } + if v, ok := d.GetOk("credit_specification"); ok { - // Only T2 instances support T2 Unlimited - if strings.HasPrefix(instanceType, "t2") { + // Only T2 and T3 are burstable performance instance types and supports Unlimited + if strings.HasPrefix(instanceType, "t2") || strings.HasPrefix(instanceType, "t3") { cs := v.([]interface{})[0].(map[string]interface{}) opts.CreditSpecification = &ec2.CreditSpecificationRequest{ CpuCredits: aws.String(cs["cpu_credits"].(string)), } } else { - log.Print("[WARN] credit_specification is defined but instance type is not T2. Ignoring...") + log.Print("[WARN] credit_specification is defined but instance type is not T2/T3. Ignoring...") } } diff --git a/aws/resource_aws_instance_test.go b/aws/resource_aws_instance_test.go index 4c1141630f6..442241067bc 100644 --- a/aws/resource_aws_instance_test.go +++ b/aws/resource_aws_instance_test.go @@ -1602,6 +1602,99 @@ func TestAccAWSInstance_creditSpecification_isNotAppliedToNonBurstable(t *testin }) } +func TestAccAWSInstance_creditSpecificationT3_unspecifiedDefaultsToUnlimited(t *testing.T) { + var instance ec2.Instance + resName := "aws_instance.foo" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceConfig_creditSpecification_unspecified_t3(acctest.RandInt()), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resName, &instance), + resource.TestCheckResourceAttr(resName, "credit_specification.#", "1"), + resource.TestCheckResourceAttr(resName, "credit_specification.0.cpu_credits", "unlimited"), + ), + }, + }, + }) +} + +func TestAccAWSInstance_creditSpecificationT3_standardCpuCredits(t *testing.T) { + var instance ec2.Instance + resName := "aws_instance.foo" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceConfig_creditSpecification_standardCpuCredits_t3(acctest.RandInt()), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resName, &instance), + resource.TestCheckResourceAttr(resName, "credit_specification.#", "1"), + resource.TestCheckResourceAttr(resName, "credit_specification.0.cpu_credits", "standard"), + ), + }, + }, + }) +} + +func TestAccAWSInstance_creditSpecificationT3_unlimitedCpuCredits(t *testing.T) { + var instance ec2.Instance + resName := "aws_instance.foo" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceConfig_creditSpecification_unlimitedCpuCredits_t3(acctest.RandInt()), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resName, &instance), + resource.TestCheckResourceAttr(resName, "credit_specification.#", "1"), + resource.TestCheckResourceAttr(resName, "credit_specification.0.cpu_credits", "unlimited"), + ), + }, + }, + }) +} + +func TestAccAWSInstance_creditSpecificationT3_updateCpuCredits(t *testing.T) { + var before ec2.Instance + var after ec2.Instance + resName := "aws_instance.foo" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceConfig_creditSpecification_standardCpuCredits_t3(acctest.RandInt()), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resName, &before), + resource.TestCheckResourceAttr(resName, "credit_specification.#", "1"), + resource.TestCheckResourceAttr(resName, "credit_specification.0.cpu_credits", "standard"), + ), + }, + { + Config: testAccInstanceConfig_creditSpecification_unlimitedCpuCredits_t3(acctest.RandInt()), + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists(resName, &after), + resource.TestCheckResourceAttr(resName, "credit_specification.#", "1"), + resource.TestCheckResourceAttr(resName, "credit_specification.0.cpu_credits", "unlimited"), + ), + }, + }, + }) +} + func TestAccAWSInstance_UserData_EmptyStringToUnspecified(t *testing.T) { var instance ec2.Instance rInt := acctest.RandInt() @@ -3283,6 +3376,29 @@ resource "aws_instance" "foo" { `, rInt) } +func testAccInstanceConfig_creditSpecification_unspecified_t3(rInt int) string { + return fmt.Sprintf(` +resource "aws_vpc" "my_vpc" { + cidr_block = "172.16.0.0/16" + tags { + Name = "tf-acctest-%d" + } +} + +resource "aws_subnet" "my_subnet" { + vpc_id = "${aws_vpc.my_vpc.id}" + cidr_block = "172.16.20.0/24" + availability_zone = "us-west-2a" +} + +resource "aws_instance" "foo" { + ami = "ami-51537029" # us-west-2 + instance_type = "t3.micro" + subnet_id = "${aws_subnet.my_subnet.id}" +} +`, rInt) +} + func testAccInstanceConfig_creditSpecification_standardCpuCredits(rInt int) string { return fmt.Sprintf(` resource "aws_vpc" "my_vpc" { @@ -3309,6 +3425,32 @@ resource "aws_instance" "foo" { `, rInt) } +func testAccInstanceConfig_creditSpecification_standardCpuCredits_t3(rInt int) string { + return fmt.Sprintf(` +resource "aws_vpc" "my_vpc" { + cidr_block = "172.16.0.0/16" + tags { + Name = "tf-acctest-%d" + } +} + +resource "aws_subnet" "my_subnet" { + vpc_id = "${aws_vpc.my_vpc.id}" + cidr_block = "172.16.20.0/24" + availability_zone = "us-west-2a" +} + +resource "aws_instance" "foo" { + ami = "ami-51537029" # us-west-2 + instance_type = "t3.micro" + subnet_id = "${aws_subnet.my_subnet.id}" + credit_specification { + cpu_credits = "standard" + } +} +`, rInt) +} + func testAccInstanceConfig_creditSpecification_unlimitedCpuCredits(rInt int) string { return fmt.Sprintf(` resource "aws_vpc" "my_vpc" { @@ -3335,6 +3477,32 @@ resource "aws_instance" "foo" { `, rInt) } +func testAccInstanceConfig_creditSpecification_unlimitedCpuCredits_t3(rInt int) string { + return fmt.Sprintf(` +resource "aws_vpc" "my_vpc" { + cidr_block = "172.16.0.0/16" + tags { + Name = "tf-acctest-%d" + } +} + +resource "aws_subnet" "my_subnet" { + vpc_id = "${aws_vpc.my_vpc.id}" + cidr_block = "172.16.20.0/24" + availability_zone = "us-west-2a" +} + +resource "aws_instance" "foo" { + ami = "ami-51537029" # us-west-2 + instance_type = "t3.micro" + subnet_id = "${aws_subnet.my_subnet.id}" + credit_specification { + cpu_credits = "unlimited" + } +} +`, rInt) +} + func testAccInstanceConfig_creditSpecification_isNotAppliedToNonBurstable(rInt int) string { return fmt.Sprintf(` resource "aws_vpc" "my_vpc" {