From ae6e0e799d6a76ff51313b7b66d48b8e305bf779 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Thu, 13 May 2021 21:38:03 +0900 Subject: [PATCH 1/8] feat: add appconfig_deployment_strategy --- aws/provider.go | 1 + ...ource_aws_appconfig_deployment_strategy.go | 220 ++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 aws/resource_aws_appconfig_deployment_strategy.go diff --git a/aws/provider.go b/aws/provider.go index f8570bba6aa..724c08aa80d 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -510,6 +510,7 @@ func Provider() *schema.Provider { "aws_appconfig_configuration_profile": resourceAwsAppconfigConfigurationProfile(), "aws_appconfig_environment": resourceAwsAppconfigEnvironment(), "aws_appconfig_hosted_configuration_version": resourceAwsAppconfigHostedConfigurationVersion(), + "aws_appconfig_deployment_strategy": resourceAwsAppconfigDeploymentStrategy(), "aws_appmesh_gateway_route": resourceAwsAppmeshGatewayRoute(), "aws_appmesh_mesh": resourceAwsAppmeshMesh(), "aws_appmesh_route": resourceAwsAppmeshRoute(), diff --git a/aws/resource_aws_appconfig_deployment_strategy.go b/aws/resource_aws_appconfig_deployment_strategy.go new file mode 100644 index 00000000000..089701267cb --- /dev/null +++ b/aws/resource_aws_appconfig_deployment_strategy.go @@ -0,0 +1,220 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/appconfig" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func resourceAwsAppconfigDeploymentStrategy() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAppconfigDeploymentStrategyCreate, + Read: resourceAwsAppconfigDeploymentStrategyRead, + Update: resourceAwsAppconfigDeploymentStrategyUpdate, + Delete: resourceAwsAppconfigDeploymentStrategyDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + ), + }, + "deployment_duration_in_minutes": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.All( + validation.IntBetween(0, 1440), + ), + }, + "growth_factor": { + Type: schema.TypeFloat, + Required: true, + }, + "replicate_to": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + "NONE", "SSM_DOCUMENT", + }, false), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 1024), + ), + }, + "final_bake_time_in_minutes": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.All( + validation.IntBetween(0, 1440), + ), + }, + "growth_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "EXPONENTIAL", "LINEAR", + }, false), + }, + "tags": tagsSchema(), + "arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsAppconfigDeploymentStrategyCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + input := &appconfig.CreateDeploymentStrategyInput{ + Name: aws.String(d.Get("name").(string)), + Description: aws.String(d.Get("description").(string)), + DeploymentDurationInMinutes: aws.Int64(int64(d.Get("deployment_duration_in_minutes").(int))), + FinalBakeTimeInMinutes: aws.Int64(int64(d.Get("final_bake_time_in_minutes").(int))), + ReplicateTo: aws.String(d.Get("replicate_to").(string)), + GrowthType: aws.String(d.Get("growth_type").(string)), + GrowthFactor: aws.Float64(d.Get("growth_factor").(float64)), + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), + } + + strategy, err := conn.CreateDeploymentStrategy(input) + if err != nil { + return fmt.Errorf("Error creating AppConfig DeploymentStrategy: %s", err) + } + + d.SetId(aws.StringValue(strategy.Id)) + + return resourceAwsAppconfigDeploymentStrategyRead(d, meta) +} + +func resourceAwsAppconfigDeploymentStrategyRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + input := &appconfig.GetDeploymentStrategyInput{ + DeploymentStrategyId: aws.String(d.Id()), + } + + output, err := conn.GetDeploymentStrategy(input) + + if !d.IsNewResource() && isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Appconfig DeploymentStrategy (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error getting AppConfig DeploymentStrategy (%s): %s", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting AppConfig DeploymentStrategy (%s): empty response", d.Id()) + } + + d.Set("name", output.Name) + d.Set("description", output.Description) + d.Set("deployment_duration_in_minutes", output.DeploymentDurationInMinutes) + d.Set("final_bake_time_in_minutes", output.FinalBakeTimeInMinutes) + d.Set("growth_factor", output.GrowthFactor) + d.Set("replicate_to", output.ReplicateTo) + d.Set("growth_type", output.GrowthType) + + strategyARN := arn.ARN{ + AccountID: meta.(*AWSClient).accountid, + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("deploymentstrategy/%s", d.Id()), + Service: "appconfig", + }.String() + d.Set("arn", strategyARN) + + tags, err := keyvaluetags.AppconfigListTags(conn, strategyARN) + if err != nil { + return fmt.Errorf("error getting tags for AppConfig DeploymentStrategy (%s): %s", d.Id(), err) + } + + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} + +func resourceAwsAppconfigDeploymentStrategyUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + updateInput := &appconfig.UpdateDeploymentStrategyInput{ + DeploymentStrategyId: aws.String(d.Id()), + } + + if d.HasChange("description") { + updateInput.Description = aws.String(d.Get("description").(string)) + } + + if d.HasChange("growth_type") { + updateInput.GrowthType = aws.String(d.Get("growth_type").(string)) + } + + if d.HasChange("deployment_duration_in_minutes") { + updateInput.DeploymentDurationInMinutes = aws.Int64(int64(d.Get("deployment_duration_in_minutes").(int))) + } + + if d.HasChange("growth_factor") { + updateInput.GrowthFactor = aws.Float64(d.Get("growth_factor").(float64)) + } + + if d.HasChange("final_bake_time_in_minutes") { + updateInput.FinalBakeTimeInMinutes = aws.Int64(int64(d.Get("final_bake_time_in_minutes").(int))) + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.AppconfigUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating AppConfig DeploymentStrategy (%s) tags: %s", d.Id(), err) + } + } + + _, err := conn.UpdateDeploymentStrategy(updateInput) + if err != nil { + return fmt.Errorf("error updating AppConfig DeploymentStrategy (%s): %s", d.Id(), err) + } + + return resourceAwsAppconfigDeploymentStrategyRead(d, meta) +} + +func resourceAwsAppconfigDeploymentStrategyDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + input := &appconfig.DeleteDeploymentStrategyInput{ + DeploymentStrategyId: aws.String(d.Id()), + } + + _, err := conn.DeleteDeploymentStrategy(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Appconfig DeploymentStrategy (%s): %s", d.Id(), err) + } + + return nil +} From 685851775e685f26a1a3a02bd3a12154f7ca9f8f Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Thu, 13 May 2021 22:04:19 +0900 Subject: [PATCH 2/8] docs: add document of appconfig_deployment_strategy --- ...ppconfig_deployment_strategy.html.markdown | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 website/docs/r/appconfig_deployment_strategy.html.markdown diff --git a/website/docs/r/appconfig_deployment_strategy.html.markdown b/website/docs/r/appconfig_deployment_strategy.html.markdown new file mode 100644 index 00000000000..dff2ded4073 --- /dev/null +++ b/website/docs/r/appconfig_deployment_strategy.html.markdown @@ -0,0 +1,58 @@ +--- +subcategory: "AppConfig" +layout: "aws" +page_title: "AWS: aws_appconfig_deployment_strategy" +description: |- + Provides an AppConfig Deployment Strategy resource. +--- + +# Resource: aws_appconfig_deployment_strategy + +Provides an AppConfig Deployment Strategy resource. + +## Example Usage + +### AppConfig Deployment Strategy + +```hcl +resource "aws_appconfig_deployment_strategy" "test" { + name = "test" + description = "test" + deployment_duration_in_minutes = 3 + final_bake_time_in_minutes = 4 + growth_factor = 10 + growth_type = "LINEAR" + replicate_to = "NONE" + tags = { + Env = "Test" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +- `name` - (Required, Forces new resource) A name for the deployment strategy. Must be between 1 and 64 characters in length. +- `description` - (Optional) A description of the deployment strategy. Can be at most 1024 characters. +- `deployment_duration_in_minutes` - (Required) Total amount of time for a deployment to last. +- `final_bake_time_in_minutes` - (Optional) The amount of time AWS AppConfig monitors for alarms before considering the deployment to be complete and no longer eligible for automatic roll back. +- `growth_factor` - (Required) The percentage of targets to receive a deployed configuration during each interval. +- `growth_type` - (Optional) The algorithm used to define how percentage grows over time. +- `replicate_to` - (Required) Save the deployment strategy to a Systems Manager (SSM) document. +- `tags` - (Optional) A map of tags to assign to the resource. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +- `arn` - The Amazon Resource Name (ARN) of the AppConfig Deployment Strategy. +- `id` - The AppConfig Deployment Strategy ID + +## Import + +`aws_appconfig_deployment_strategy` can be imported by the Deployment Strategy ID, e.g. + +``` +$ terraform import aws_appconfig_deployment_strategy.test 11xxxxx +``` From d42388c4a4ba1f49d57aab905c0dbde4052b5963 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Sat, 15 May 2021 07:31:25 +0900 Subject: [PATCH 3/8] test: add tests of aws_appconfig_deployment_strategy --- ..._aws_appconfig_deployment_strategy_test.go | 246 ++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 aws/resource_aws_appconfig_deployment_strategy_test.go diff --git a/aws/resource_aws_appconfig_deployment_strategy_test.go b/aws/resource_aws_appconfig_deployment_strategy_test.go new file mode 100644 index 00000000000..44cdab9665f --- /dev/null +++ b/aws/resource_aws_appconfig_deployment_strategy_test.go @@ -0,0 +1,246 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appconfig" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccAWSAppConfigDeploymentStrategy_basic(t *testing.T) { + var strategy appconfig.GetDeploymentStrategyOutput + resourceName := "aws_appconfig_deployment_strategy.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigDeploymentStrategyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigDeploymentStrategy(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), + testAccCheckAWSAppConfigDeploymentStrategyARN(resourceName, &strategy), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "description", "deployment strategy description"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAppConfigDeploymentStrategyImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigDeploymentStrategy_disappears(t *testing.T) { + var strategy appconfig.GetDeploymentStrategyOutput + resourceName := "aws_appconfig_deployment_strategy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigDeploymentStrategyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigDeploymentStrategy(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), + testAccCheckAWSAppConfigDeploymentStrategyDisappears(&strategy), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSAppConfigDeploymentStrategy_Tags(t *testing.T) { + var strategy appconfig.GetDeploymentStrategyOutput + + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appconfig_deployment_strategy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigDeploymentStrategyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigDeploymentStrategyTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAppConfigDeploymentStrategyImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigDeploymentStrategyTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSAppConfigDeploymentStrategyTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func testAccCheckAppConfigDeploymentStrategyDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_appconfig_deployment_strategy" { + continue + } + + input := &appconfig.GetDeploymentStrategyInput{ + DeploymentStrategyId: aws.String(rs.Primary.ID), + } + + output, err := conn.GetDeploymentStrategy(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + continue + } + + if err != nil { + return err + } + + if output != nil { + return fmt.Errorf("AppConfig DeploymentStrategy (%s) still exists", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckAWSAppConfigDeploymentStrategyDisappears(strategy *appconfig.GetDeploymentStrategyOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + _, err := conn.DeleteDeploymentStrategy(&appconfig.DeleteDeploymentStrategyInput{ + DeploymentStrategyId: strategy.Id, + }) + + return err + } +} + +func testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName string, strategy *appconfig.GetDeploymentStrategyOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Resource not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("Resource (%s) ID not set", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + output, err := conn.GetDeploymentStrategy(&appconfig.GetDeploymentStrategyInput{ + DeploymentStrategyId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + *strategy = *output + + return nil + } +} + +func testAccCheckAWSAppConfigDeploymentStrategyARN(resourceName string, strategy *appconfig.GetDeploymentStrategyOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + return testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appconfig", fmt.Sprintf("deploymentstrategy/%s", aws.StringValue(strategy.Id)))(s) + } +} + +func testAccAWSAppConfigDeploymentStrategy() string { + return fmt.Sprintf(` +resource "aws_appconfig_deployment_strategy" "test" { + name = "%s" + description = "deployment strategy description" + deployment_duration_in_minutes = 3 + final_bake_time_in_minutes = 4 + growth_factor = 10 + growth_type = "LINEAR" + replicate_to = "NONE" + tags = { + Env = "Test" + } +} +`, acctest.RandomWithPrefix("tf-acc-test")) +} + +func testAccAWSAppConfigDeploymentStrategyTags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_appconfig_deployment_strategy" "test" { + name = %[1]q + deployment_duration_in_minutes = 3 + final_bake_time_in_minutes = 4 + growth_factor = 10 + growth_type = "LINEAR" + replicate_to = "NONE" + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccAWSAppConfigDeploymentStrategyTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return testAccAWSAppConfigApplicationTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2) + fmt.Sprintf(` +resource "aws_appconfig_deployment_strategy" "test" { + name = %[1]q + deployment_duration_in_minutes = 3 + final_bake_time_in_minutes = 4 + growth_factor = 10 + growth_type = "LINEAR" + replicate_to = "NONE" + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} + +func testAccAWSAppConfigDeploymentStrategyImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not Found: %s", resourceName) + } + + return rs.Primary.ID, nil + } +} From dc46fc5c51087d81ee947a64126bda457890ef96 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Mon, 12 Jul 2021 23:24:10 +0900 Subject: [PATCH 4/8] docs: add CHANGELOG entry --- .changelog/19359.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19359.txt diff --git a/.changelog/19359.txt b/.changelog/19359.txt new file mode 100644 index 00000000000..d79ead83974 --- /dev/null +++ b/.changelog/19359.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_appconfig_deployment_strategy +``` From 3d12fa85fcfe09ead5d7b33d1920649ef203e7c0 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Mon, 12 Jul 2021 23:28:28 +0900 Subject: [PATCH 5/8] style: sort providers --- aws/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/provider.go b/aws/provider.go index 724c08aa80d..bd2642be4db 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -508,9 +508,9 @@ func Provider() *schema.Provider { "aws_appautoscaling_scheduled_action": resourceAwsAppautoscalingScheduledAction(), "aws_appconfig_application": resourceAwsAppconfigApplication(), "aws_appconfig_configuration_profile": resourceAwsAppconfigConfigurationProfile(), + "aws_appconfig_deployment_strategy": resourceAwsAppconfigDeploymentStrategy(), "aws_appconfig_environment": resourceAwsAppconfigEnvironment(), "aws_appconfig_hosted_configuration_version": resourceAwsAppconfigHostedConfigurationVersion(), - "aws_appconfig_deployment_strategy": resourceAwsAppconfigDeploymentStrategy(), "aws_appmesh_gateway_route": resourceAwsAppmeshGatewayRoute(), "aws_appmesh_mesh": resourceAwsAppmeshMesh(), "aws_appmesh_route": resourceAwsAppmeshRoute(), From 326ffda19198003991a981b5e2dc81d3733bee27 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Mon, 12 Jul 2021 23:36:51 +0900 Subject: [PATCH 6/8] style: format test --- aws/resource_aws_appconfig_deployment_strategy_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_appconfig_deployment_strategy_test.go b/aws/resource_aws_appconfig_deployment_strategy_test.go index 44cdab9665f..d34ad401e86 100644 --- a/aws/resource_aws_appconfig_deployment_strategy_test.go +++ b/aws/resource_aws_appconfig_deployment_strategy_test.go @@ -202,7 +202,7 @@ resource "aws_appconfig_deployment_strategy" "test" { func testAccAWSAppConfigDeploymentStrategyTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_appconfig_deployment_strategy" "test" { - name = %[1]q + name = %[1]q deployment_duration_in_minutes = 3 final_bake_time_in_minutes = 4 growth_factor = 10 @@ -219,7 +219,7 @@ resource "aws_appconfig_deployment_strategy" "test" { func testAccAWSAppConfigDeploymentStrategyTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return testAccAWSAppConfigApplicationTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2) + fmt.Sprintf(` resource "aws_appconfig_deployment_strategy" "test" { - name = %[1]q + name = %[1]q deployment_duration_in_minutes = 3 final_bake_time_in_minutes = 4 growth_factor = 10 From 9254447452d7c80b28241f2a70e8dc6d37867ada Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Mon, 12 Jul 2021 23:55:38 +0900 Subject: [PATCH 7/8] test: fix the expected length of tags --- aws/resource_aws_appconfig_deployment_strategy_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_appconfig_deployment_strategy_test.go b/aws/resource_aws_appconfig_deployment_strategy_test.go index d34ad401e86..a024b5a7306 100644 --- a/aws/resource_aws_appconfig_deployment_strategy_test.go +++ b/aws/resource_aws_appconfig_deployment_strategy_test.go @@ -25,7 +25,7 @@ func TestAccAWSAppConfigDeploymentStrategy_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), testAccCheckAWSAppConfigDeploymentStrategyARN(resourceName, &strategy), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "description", "deployment strategy description"), ), }, From 07b36aa86576ff8ae8ab38193db907d760975af0 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Mon, 12 Jul 2021 12:42:19 -0400 Subject: [PATCH 8/8] CR updates; add test coverage and default tags support --- ...ource_aws_appconfig_deployment_strategy.go | 192 +++++++++-------- ..._aws_appconfig_deployment_strategy_test.go | 203 ++++++++++++------ website/docs/index.html.markdown | 1 + ...ppconfig_deployment_strategy.html.markdown | 38 ++-- 4 files changed, 261 insertions(+), 173 deletions(-) diff --git a/aws/resource_aws_appconfig_deployment_strategy.go b/aws/resource_aws_appconfig_deployment_strategy.go index 089701267cb..5f4140ecd67 100644 --- a/aws/resource_aws_appconfig_deployment_strategy.go +++ b/aws/resource_aws_appconfig_deployment_strategy.go @@ -7,6 +7,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/appconfig" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" @@ -23,80 +24,83 @@ func resourceAwsAppconfigDeploymentStrategy() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { + "arn": { Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 64), - ), + Computed: true, }, "deployment_duration_in_minutes": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.All( - validation.IntBetween(0, 1440), - ), - }, - "growth_factor": { - Type: schema.TypeFloat, - Required: true, - }, - "replicate_to": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - "NONE", "SSM_DOCUMENT", - }, false), + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 1440), }, "description": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.All( - validation.StringLenBetween(0, 1024), - ), + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 1024), }, "final_bake_time_in_minutes": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.All( - validation.IntBetween(0, 1440), - ), + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 1440), + }, + "growth_factor": { + Type: schema.TypeFloat, + Required: true, + ValidateFunc: validation.FloatBetween(1.0, 100.0), }, "growth_type": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "EXPONENTIAL", "LINEAR", - }, false), + Type: schema.TypeString, + Optional: true, + Default: appconfig.GrowthTypeLinear, + ValidateFunc: validation.StringInSlice(appconfig.GrowthType_Values(), false), }, - "tags": tagsSchema(), - "arn": { - Type: schema.TypeString, - Computed: true, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 64), + }, + "replicate_to": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(appconfig.ReplicateTo_Values(), false), }, + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, + CustomizeDiff: SetTagsDiff, } } func resourceAwsAppconfigDeploymentStrategyCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) + + name := d.Get("name").(string) input := &appconfig.CreateDeploymentStrategyInput{ - Name: aws.String(d.Get("name").(string)), - Description: aws.String(d.Get("description").(string)), DeploymentDurationInMinutes: aws.Int64(int64(d.Get("deployment_duration_in_minutes").(int))), - FinalBakeTimeInMinutes: aws.Int64(int64(d.Get("final_bake_time_in_minutes").(int))), - ReplicateTo: aws.String(d.Get("replicate_to").(string)), - GrowthType: aws.String(d.Get("growth_type").(string)), GrowthFactor: aws.Float64(d.Get("growth_factor").(float64)), - Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), + GrowthType: aws.String(d.Get("growth_type").(string)), + Name: aws.String(name), + ReplicateTo: aws.String(d.Get("replicate_to").(string)), + Tags: tags.IgnoreAws().AppconfigTags(), + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("final_bake_time_in_minutes"); ok { + input.FinalBakeTimeInMinutes = aws.Int64(int64(v.(int))) } strategy, err := conn.CreateDeploymentStrategy(input) + if err != nil { - return fmt.Errorf("Error creating AppConfig DeploymentStrategy: %s", err) + return fmt.Errorf("error creating AppConfig Deployment Strategy (%s): %w", name, err) } d.SetId(aws.StringValue(strategy.Id)) @@ -106,6 +110,7 @@ func resourceAwsAppconfigDeploymentStrategyCreate(d *schema.ResourceData, meta i func resourceAwsAppconfigDeploymentStrategyRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig input := &appconfig.GetDeploymentStrategyInput{ @@ -114,44 +119,52 @@ func resourceAwsAppconfigDeploymentStrategyRead(d *schema.ResourceData, meta int output, err := conn.GetDeploymentStrategy(input) - if !d.IsNewResource() && isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] Appconfig DeploymentStrategy (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { + log.Printf("[WARN] Appconfig Deployment Strategy (%s) not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error getting AppConfig DeploymentStrategy (%s): %s", d.Id(), err) + return fmt.Errorf("error getting AppConfig Deployment Strategy (%s): %w", d.Id(), err) } if output == nil { - return fmt.Errorf("error getting AppConfig DeploymentStrategy (%s): empty response", d.Id()) + return fmt.Errorf("error getting AppConfig Deployment Strategy (%s): empty response", d.Id()) } - d.Set("name", output.Name) d.Set("description", output.Description) d.Set("deployment_duration_in_minutes", output.DeploymentDurationInMinutes) d.Set("final_bake_time_in_minutes", output.FinalBakeTimeInMinutes) d.Set("growth_factor", output.GrowthFactor) - d.Set("replicate_to", output.ReplicateTo) d.Set("growth_type", output.GrowthType) + d.Set("name", output.Name) + d.Set("replicate_to", output.ReplicateTo) - strategyARN := arn.ARN{ + arn := arn.ARN{ AccountID: meta.(*AWSClient).accountid, Partition: meta.(*AWSClient).partition, Region: meta.(*AWSClient).region, Resource: fmt.Sprintf("deploymentstrategy/%s", d.Id()), Service: "appconfig", }.String() - d.Set("arn", strategyARN) + d.Set("arn", arn) + + tags, err := keyvaluetags.AppconfigListTags(conn, arn) - tags, err := keyvaluetags.AppconfigListTags(conn, strategyARN) if err != nil { - return fmt.Errorf("error getting tags for AppConfig DeploymentStrategy (%s): %s", d.Id(), err) + return fmt.Errorf("error listing tags for AppConfig Deployment Strategy (%s): %w", d.Id(), err) + } + + tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) + + //lintignore:AWSR002 + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) } - if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %s", err) + if err := d.Set("tags_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) } return nil @@ -160,40 +173,43 @@ func resourceAwsAppconfigDeploymentStrategyRead(d *schema.ResourceData, meta int func resourceAwsAppconfigDeploymentStrategyUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn - updateInput := &appconfig.UpdateDeploymentStrategyInput{ - DeploymentStrategyId: aws.String(d.Id()), - } + if d.HasChangesExcept("tags", "tags_all") { + updateInput := &appconfig.UpdateDeploymentStrategyInput{ + DeploymentStrategyId: aws.String(d.Id()), + } - if d.HasChange("description") { - updateInput.Description = aws.String(d.Get("description").(string)) - } + if d.HasChange("deployment_duration_in_minutes") { + updateInput.DeploymentDurationInMinutes = aws.Int64(int64(d.Get("deployment_duration_in_minutes").(int))) + } - if d.HasChange("growth_type") { - updateInput.GrowthType = aws.String(d.Get("growth_type").(string)) - } + if d.HasChange("description") { + updateInput.Description = aws.String(d.Get("description").(string)) + } - if d.HasChange("deployment_duration_in_minutes") { - updateInput.DeploymentDurationInMinutes = aws.Int64(int64(d.Get("deployment_duration_in_minutes").(int))) - } + if d.HasChange("final_bake_time_in_minutes") { + updateInput.FinalBakeTimeInMinutes = aws.Int64(int64(d.Get("final_bake_time_in_minutes").(int))) + } - if d.HasChange("growth_factor") { - updateInput.GrowthFactor = aws.Float64(d.Get("growth_factor").(float64)) - } + if d.HasChange("growth_factor") { + updateInput.GrowthFactor = aws.Float64(d.Get("growth_factor").(float64)) + } - if d.HasChange("final_bake_time_in_minutes") { - updateInput.FinalBakeTimeInMinutes = aws.Int64(int64(d.Get("final_bake_time_in_minutes").(int))) - } + if d.HasChange("growth_type") { + updateInput.GrowthType = aws.String(d.Get("growth_type").(string)) + } - if d.HasChange("tags") { - o, n := d.GetChange("tags") - if err := keyvaluetags.AppconfigUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating AppConfig DeploymentStrategy (%s) tags: %s", d.Id(), err) + _, err := conn.UpdateDeploymentStrategy(updateInput) + + if err != nil { + return fmt.Errorf("error updating AppConfig Deployment Strategy (%s): %w", d.Id(), err) } } - _, err := conn.UpdateDeploymentStrategy(updateInput) - if err != nil { - return fmt.Errorf("error updating AppConfig DeploymentStrategy (%s): %s", d.Id(), err) + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + if err := keyvaluetags.AppconfigUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating AppConfig Deployment Strategy (%s) tags: %w", d.Id(), err) + } } return resourceAwsAppconfigDeploymentStrategyRead(d, meta) @@ -208,12 +224,12 @@ func resourceAwsAppconfigDeploymentStrategyDelete(d *schema.ResourceData, meta i _, err := conn.DeleteDeploymentStrategy(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { return nil } if err != nil { - return fmt.Errorf("error deleting Appconfig DeploymentStrategy (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting Appconfig Deployment Strategy (%s): %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_appconfig_deployment_strategy_test.go b/aws/resource_aws_appconfig_deployment_strategy_test.go index a024b5a7306..053a36d05c9 100644 --- a/aws/resource_aws_appconfig_deployment_strategy_test.go +++ b/aws/resource_aws_appconfig_deployment_strategy_test.go @@ -2,18 +2,21 @@ package aws import ( "fmt" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appconfig" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) func TestAccAWSAppConfigDeploymentStrategy_basic(t *testing.T) { - var strategy appconfig.GetDeploymentStrategyOutput + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_deployment_strategy.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), @@ -21,26 +24,107 @@ func TestAccAWSAppConfigDeploymentStrategy_basic(t *testing.T) { CheckDestroy: testAccCheckAppConfigDeploymentStrategyDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAppConfigDeploymentStrategy(), + Config: testAccAWSAppConfigDeploymentStrategyConfigName(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), - testAccCheckAWSAppConfigDeploymentStrategyARN(resourceName, &strategy), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "description", "deployment strategy description"), + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "appconfig", regexp.MustCompile(`deploymentstrategy/[a-z0-9]{4,7}`)), + resource.TestCheckResourceAttr(resourceName, "deployment_duration_in_minutes", "3"), + resource.TestCheckResourceAttr(resourceName, "growth_factor", "10"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "replicate_to", appconfig.ReplicateToNone), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigDeploymentStrategy_updateDescription(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + description := acctest.RandomWithPrefix("tf-acc-test-update") + resourceName := "aws_appconfig_deployment_strategy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigDeploymentStrategyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigDeploymentStrategyConfigDescription(rName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", rName), + ), + }, + { + Config: testAccAWSAppConfigDeploymentStrategyConfigDescription(rName, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", description), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigDeploymentStrategy_updateFinalBakeTime(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appconfig_deployment_strategy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigDeploymentStrategyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigDeploymentStrategyConfigFinalBakeTime(rName, 60), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "final_bake_time_in_minutes", "60"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigDeploymentStrategyConfigFinalBakeTime(rName, 30), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "final_bake_time_in_minutes", "30"), ), }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAppConfigDeploymentStrategyImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, + { + // Test FinalBakeTimeInMinutes Removal + Config: testAccAWSAppConfigDeploymentStrategyConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName), + ), + }, }, }) } func TestAccAWSAppConfigDeploymentStrategy_disappears(t *testing.T) { - var strategy appconfig.GetDeploymentStrategyOutput + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_deployment_strategy.test" resource.ParallelTest(t, resource.TestCase{ @@ -50,10 +134,10 @@ func TestAccAWSAppConfigDeploymentStrategy_disappears(t *testing.T) { CheckDestroy: testAccCheckAppConfigDeploymentStrategyDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAppConfigDeploymentStrategy(), + Config: testAccAWSAppConfigDeploymentStrategyConfigName(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), - testAccCheckAWSAppConfigDeploymentStrategyDisappears(&strategy), + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAppconfigDeploymentStrategy(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -62,8 +146,6 @@ func TestAccAWSAppConfigDeploymentStrategy_disappears(t *testing.T) { } func TestAccAWSAppConfigDeploymentStrategy_Tags(t *testing.T) { - var strategy appconfig.GetDeploymentStrategyOutput - rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_deployment_strategy.test" @@ -76,21 +158,20 @@ func TestAccAWSAppConfigDeploymentStrategy_Tags(t *testing.T) { { Config: testAccAWSAppConfigDeploymentStrategyTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAppConfigDeploymentStrategyImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, { Config: testAccAWSAppConfigDeploymentStrategyTags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), @@ -99,7 +180,7 @@ func TestAccAWSAppConfigDeploymentStrategy_Tags(t *testing.T) { { Config: testAccAWSAppConfigDeploymentStrategyTags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName, &strategy), + testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), @@ -122,35 +203,23 @@ func testAccCheckAppConfigDeploymentStrategyDestroy(s *terraform.State) error { output, err := conn.GetDeploymentStrategy(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { continue } if err != nil { - return err + return fmt.Errorf("error getting Appconfig Deployment Strategy (%s): %w", rs.Primary.ID, err) } if output != nil { - return fmt.Errorf("AppConfig DeploymentStrategy (%s) still exists", rs.Primary.ID) + return fmt.Errorf("AppConfig Deployment Strategy (%s) still exists", rs.Primary.ID) } } return nil } -func testAccCheckAWSAppConfigDeploymentStrategyDisappears(strategy *appconfig.GetDeploymentStrategyOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).appconfigconn - - _, err := conn.DeleteDeploymentStrategy(&appconfig.DeleteDeploymentStrategyInput{ - DeploymentStrategyId: strategy.Id, - }) - - return err - } -} - -func testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName string, strategy *appconfig.GetDeploymentStrategyOutput) resource.TestCheckFunc { +func testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -163,40 +232,57 @@ func testAccCheckAWSAppConfigDeploymentStrategyExists(resourceName string, strat conn := testAccProvider.Meta().(*AWSClient).appconfigconn - output, err := conn.GetDeploymentStrategy(&appconfig.GetDeploymentStrategyInput{ + input := &appconfig.GetDeploymentStrategyInput{ DeploymentStrategyId: aws.String(rs.Primary.ID), - }) + } + + output, err := conn.GetDeploymentStrategy(input) + if err != nil { - return err + return fmt.Errorf("error getting Appconfig Deployment Strategy (%s): %w", rs.Primary.ID, err) } - *strategy = *output + if output == nil { + return fmt.Errorf("AppConfig Deployment Strategy (%s) not found", rs.Primary.ID) + } return nil } } -func testAccCheckAWSAppConfigDeploymentStrategyARN(resourceName string, strategy *appconfig.GetDeploymentStrategyOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - return testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appconfig", fmt.Sprintf("deploymentstrategy/%s", aws.StringValue(strategy.Id)))(s) - } +func testAccAWSAppConfigDeploymentStrategyConfigName(rName string) string { + return fmt.Sprintf(` +resource "aws_appconfig_deployment_strategy" "test" { + name = %[1]q + deployment_duration_in_minutes = 3 + growth_factor = 10 + replicate_to = "NONE" +} +`, rName) } -func testAccAWSAppConfigDeploymentStrategy() string { +func testAccAWSAppConfigDeploymentStrategyConfigDescription(rName, description string) string { return fmt.Sprintf(` resource "aws_appconfig_deployment_strategy" "test" { - name = "%s" - description = "deployment strategy description" + name = %[1]q deployment_duration_in_minutes = 3 - final_bake_time_in_minutes = 4 + description = %[2]q growth_factor = 10 - growth_type = "LINEAR" replicate_to = "NONE" - tags = { - Env = "Test" - } } -`, acctest.RandomWithPrefix("tf-acc-test")) +`, rName, description) +} + +func testAccAWSAppConfigDeploymentStrategyConfigFinalBakeTime(rName string, time int) string { + return fmt.Sprintf(` +resource "aws_appconfig_deployment_strategy" "test" { + name = %[1]q + deployment_duration_in_minutes = 3 + final_bake_time_in_minutes = %[2]d + growth_factor = 10 + replicate_to = "NONE" +} +`, rName, time) } func testAccAWSAppConfigDeploymentStrategyTags1(rName, tagKey1, tagValue1 string) string { @@ -204,9 +290,7 @@ func testAccAWSAppConfigDeploymentStrategyTags1(rName, tagKey1, tagValue1 string resource "aws_appconfig_deployment_strategy" "test" { name = %[1]q deployment_duration_in_minutes = 3 - final_bake_time_in_minutes = 4 growth_factor = 10 - growth_type = "LINEAR" replicate_to = "NONE" tags = { @@ -217,13 +301,11 @@ resource "aws_appconfig_deployment_strategy" "test" { } func testAccAWSAppConfigDeploymentStrategyTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return testAccAWSAppConfigApplicationTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2) + fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_appconfig_deployment_strategy" "test" { name = %[1]q deployment_duration_in_minutes = 3 - final_bake_time_in_minutes = 4 growth_factor = 10 - growth_type = "LINEAR" replicate_to = "NONE" tags = { @@ -233,14 +315,3 @@ resource "aws_appconfig_deployment_strategy" "test" { } `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } - -func testAccAWSAppConfigDeploymentStrategyImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { - return func(s *terraform.State) (string, error) { - rs, ok := s.RootModule().Resources[resourceName] - if !ok { - return "", fmt.Errorf("Not Found: %s", resourceName) - } - - return rs.Primary.ID, nil - } -} diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 9f38e67fa0f..570f08ad738 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -253,6 +253,7 @@ for more information about connecting to alternate AWS endpoints or AWS compatib - [`aws_apigatewayv2_stage` resource](/docs/providers/aws/r/apigatewayv2_stage.html) - [`aws_appconfig_application` resource](/docs/providers/aws/r/appconfig_application.html) - [`aws_appconfig_configuration_profile` resource](/docs/providers/aws/r/appconfig_configuration_profile.html) + - [`aws_appconfig_deployment_strategy` resource](/docs/providers/aws/r/appconfig_deployment_strategy.html) - [`aws_appconfig_environment` resource](/docs/providers/aws/r/appconfig_environment.html) - [`aws_appconfig_hosted_configuration_version` resource](/docs/providers/aws/r/appconfig_hosted_configuration_version.html) - [`aws_athena_workgroup` resource](/docs/providers/aws/r/athena_workgroup.html) diff --git a/website/docs/r/appconfig_deployment_strategy.html.markdown b/website/docs/r/appconfig_deployment_strategy.html.markdown index dff2ded4073..139672745bd 100644 --- a/website/docs/r/appconfig_deployment_strategy.html.markdown +++ b/website/docs/r/appconfig_deployment_strategy.html.markdown @@ -12,19 +12,18 @@ Provides an AppConfig Deployment Strategy resource. ## Example Usage -### AppConfig Deployment Strategy - -```hcl -resource "aws_appconfig_deployment_strategy" "test" { - name = "test" - description = "test" +```terraform +resource "aws_appconfig_deployment_strategy" "example" { + name = "example-deployment-strategy-tf" + description = "Example Deployment Strategy" deployment_duration_in_minutes = 3 final_bake_time_in_minutes = 4 growth_factor = 10 growth_type = "LINEAR" replicate_to = "NONE" + tags = { - Env = "Test" + Type = "AppConfig Deployment Strategy" } } ``` @@ -33,26 +32,27 @@ resource "aws_appconfig_deployment_strategy" "test" { The following arguments are supported: -- `name` - (Required, Forces new resource) A name for the deployment strategy. Must be between 1 and 64 characters in length. -- `description` - (Optional) A description of the deployment strategy. Can be at most 1024 characters. -- `deployment_duration_in_minutes` - (Required) Total amount of time for a deployment to last. -- `final_bake_time_in_minutes` - (Optional) The amount of time AWS AppConfig monitors for alarms before considering the deployment to be complete and no longer eligible for automatic roll back. -- `growth_factor` - (Required) The percentage of targets to receive a deployed configuration during each interval. -- `growth_type` - (Optional) The algorithm used to define how percentage grows over time. -- `replicate_to` - (Required) Save the deployment strategy to a Systems Manager (SSM) document. -- `tags` - (Optional) A map of tags to assign to the resource. +* `deployment_duration_in_minutes` - (Required) Total amount of time for a deployment to last. Minimum value of 0, maximum value of 1440. +* `growth_factor` - (Required) The percentage of targets to receive a deployed configuration during each interval. Minimum value of 1.0, maximum value of 100.0. +* `name` - (Required, Forces new resource) A name for the deployment strategy. Must be between 1 and 64 characters in length. +* `replicate_to` - (Required, Forces new resource) Where to save the deployment strategy. Valid values: `NONE` and `SSM_DOCUMENT`. +* `description` - (Optional) A description of the deployment strategy. Can be at most 1024 characters. +* `final_bake_time_in_minutes` - (Optional) The amount of time AWS AppConfig monitors for alarms before considering the deployment to be complete and no longer eligible for automatic roll back. Minimum value of 0, maximum value of 1440. +* `growth_type` - (Optional) The algorithm used to define how percentage grows over time. Valid value: `LINEAR` and `EXPONENTIAL`. Defaults to `LINEAR`. +* `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -- `arn` - The Amazon Resource Name (ARN) of the AppConfig Deployment Strategy. -- `id` - The AppConfig Deployment Strategy ID +* `id` - The AppConfig deployment strategy ID. +* `arn` - The Amazon Resource Name (ARN) of the AppConfig Deployment Strategy. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block). ## Import -`aws_appconfig_deployment_strategy` can be imported by the Deployment Strategy ID, e.g. +AppConfig Deployment Strategies can be imported by using their deployment strategy ID, e.g. ``` -$ terraform import aws_appconfig_deployment_strategy.test 11xxxxx +$ terraform import aws_appconfig_deployment_strategy.example 11xxxxx ```