From df7dcdabe328dda424215919fe1e78c7e68ef336 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 22:07:31 +0900 Subject: [PATCH 01/16] feat: add aws_appconfig_configuration_profile --- aws/provider.go | 1 + ...rce_aws_appconfig_configuration_profile.go | 222 ++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 aws/resource_aws_appconfig_configuration_profile.go diff --git a/aws/provider.go b/aws/provider.go index 90236fbf4ec..48e60dbd52c 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -508,6 +508,7 @@ func Provider() *schema.Provider { "aws_appautoscaling_scheduled_action": resourceAwsAppautoscalingScheduledAction(), "aws_appconfig_application": resourceAwsAppconfigApplication(), "aws_appconfig_environment": resourceAwsAppconfigEnvironment(), + "aws_appconfig_configuration_profile": resourceAwsAppconfigConfigurationProfile(), "aws_appmesh_gateway_route": resourceAwsAppmeshGatewayRoute(), "aws_appmesh_mesh": resourceAwsAppmeshMesh(), "aws_appmesh_route": resourceAwsAppmeshRoute(), diff --git a/aws/resource_aws_appconfig_configuration_profile.go b/aws/resource_aws_appconfig_configuration_profile.go new file mode 100644 index 00000000000..700fe6f0f61 --- /dev/null +++ b/aws/resource_aws_appconfig_configuration_profile.go @@ -0,0 +1,222 @@ +package aws + +import ( + "fmt" + "log" + "strings" + + "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 resourceAwsAppconfigConfigurationProfile() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAppconfigConfigurationProfileCreate, + Read: resourceAwsAppconfigConfigurationProfileRead, + Update: resourceAwsAppconfigConfigurationProfileUpdate, + Delete: resourceAwsAppconfigConfigurationProfileDelete, + Importer: &schema.ResourceImporter{ + State: resourceAwsAppconfigConfigurationProfileImport, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + ), + }, + "application_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(4, 7), + ), + }, + "location_uri": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 2048), + ), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 1024), + ), + }, + "retrieval_role_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(20, 2048), + ), + }, + // "validators": { + // Type: schema.TypeString, + // Optional: true, + // ValidateFunc: validation.All( + // validation.StringLenBetween(20, 2048), + // ), + // }, + "tags": tagsSchema(), + "arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsAppconfigConfigurationProfileCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + input := &appconfig.CreateConfigurationProfileInput{ + Name: aws.String(d.Get("name").(string)), + Description: aws.String(d.Get("description").(string)), + LocationUri: aws.String(d.Get("location_uri").(string)), + RetrievalRoleArn: aws.String(d.Get("retrieval_role_arn").(string)), + ApplicationId: aws.String(d.Get("application_id").(string)), + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), + } + + profile, err := conn.CreateConfigurationProfile(input) + if err != nil { + return fmt.Errorf("Error creating AppConfig ConfigurationProfile: %s", err) + } + + d.SetId(aws.StringValue(profile.Id)) + + return resourceAwsAppconfigConfigurationProfileRead(d, meta) +} + +func resourceAwsAppconfigConfigurationProfileRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + appID := d.Get("application_id").(string) + + input := &appconfig.GetConfigurationProfileInput{ + ApplicationId: aws.String(appID), + ConfigurationProfileId: aws.String(d.Id()), + } + + output, err := conn.GetConfigurationProfile(input) + + if !d.IsNewResource() && isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Appconfig ConfigurationProfile (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error getting AppConfig ConfigurationProfile (%s): %s", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting AppConfig ConfigurationProfile (%s): empty response", d.Id()) + } + + d.Set("name", output.Name) + d.Set("description", output.Description) + d.Set("application_id", output.ApplicationId) + d.Set("location_uri", output.LocationUri) + d.Set("retrieval_role_arn", output.RetrievalRoleArn) + + profileARN := arn.ARN{ + AccountID: meta.(*AWSClient).accountid, + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("application/%s/configurationprofile/%s", appID, d.Id()), + Service: "appconfig", + }.String() + d.Set("arn", profileARN) + + tags, err := keyvaluetags.AppconfigListTags(conn, profileARN) + if err != nil { + return fmt.Errorf("error getting tags for AppConfig ConfigurationProfile (%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 resourceAwsAppconfigConfigurationProfileUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + updateInput := &appconfig.UpdateConfigurationProfileInput{ + ConfigurationProfileId: aws.String(d.Id()), + ApplicationId: aws.String(d.Get("application_id").(string)), + } + + if d.HasChange("description") { + updateInput.Description = aws.String(d.Get("description").(string)) + } + + if d.HasChange("name") { + updateInput.Name = aws.String(d.Get("name").(string)) + } + + if d.HasChange("retrieval_role_arn") { + updateInput.Name = aws.String(d.Get("retrieval_role_arn").(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 (%s) tags: %s", d.Id(), err) + } + } + + _, err := conn.UpdateConfigurationProfile(updateInput) + if err != nil { + return fmt.Errorf("error updating AppConfig ConfigurationProfile (%s): %s", d.Id(), err) + } + + return resourceAwsAppconfigConfigurationProfileRead(d, meta) +} + +func resourceAwsAppconfigConfigurationProfileDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + input := &appconfig.DeleteConfigurationProfileInput{ + ConfigurationProfileId: aws.String(d.Id()), + ApplicationId: aws.String(d.Get("application_id").(string)), + } + + _, err := conn.DeleteConfigurationProfile(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Appconfig ConfigurationProfile (%s): %s", d.Id(), err) + } + + return nil +} + +func resourceAwsAppconfigConfigurationProfileImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(d.Id(), "/") + if len(parts) != 2 { + return []*schema.ResourceData{}, fmt.Errorf("Wrong format of resource: %s. Please follow 'application-id/configurationprofile-id'", d.Id()) + } + + d.SetId(parts[1]) + d.Set("application_id", parts[0]) + + return []*schema.ResourceData{d}, nil +} From bf46b7fc3f37f1229331fa50666e7a2b295616c6 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 22:44:58 +0900 Subject: [PATCH 02/16] feat: support AppConfig Validators --- ...rce_aws_appconfig_configuration_profile.go | 59 ++++++++++++++++--- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_appconfig_configuration_profile.go b/aws/resource_aws_appconfig_configuration_profile.go index 700fe6f0f61..c0fce741008 100644 --- a/aws/resource_aws_appconfig_configuration_profile.go +++ b/aws/resource_aws_appconfig_configuration_profile.go @@ -61,13 +61,29 @@ func resourceAwsAppconfigConfigurationProfile() *schema.Resource { validation.StringLenBetween(20, 2048), ), }, - // "validators": { - // Type: schema.TypeString, - // Optional: true, - // ValidateFunc: validation.All( - // validation.StringLenBetween(20, 2048), - // ), - // }, + "validators": { + Type: schema.TypeList, + Optional: true, + MaxItems: 2, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "content": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 32768), + ), + }, + "type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "JSON_SCHEMA", "LAMBDA", + }, false), + }, + }, + }, + }, "tags": tagsSchema(), "arn": { Type: schema.TypeString, @@ -86,6 +102,7 @@ func resourceAwsAppconfigConfigurationProfileCreate(d *schema.ResourceData, meta LocationUri: aws.String(d.Get("location_uri").(string)), RetrievalRoleArn: aws.String(d.Get("retrieval_role_arn").(string)), ApplicationId: aws.String(d.Get("application_id").(string)), + Validators: expandAppconfigValidators(d.Get("validators").([]interface{})), Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), } @@ -99,6 +116,29 @@ func resourceAwsAppconfigConfigurationProfileCreate(d *schema.ResourceData, meta return resourceAwsAppconfigConfigurationProfileRead(d, meta) } +func expandAppconfigValidators(list []interface{}) []*appconfig.Validator { + validators := make([]*appconfig.Validator, len(list)) + for i, validatorInterface := range list { + m := validatorInterface.(map[string]interface{}) + validators[i] = &appconfig.Validator{ + Content: aws.String(m["content"].(string)), + Type: aws.String(m["type"].(string)), + } + } + return validators +} + +func flattenAwsAppconfigValidators(validators []*appconfig.Validator) []interface{} { + list := make([]interface{}, len(validators)) + for i, validator := range validators { + list[i] = map[string]interface{}{ + "content": aws.StringValue(validator.Content), + "type": aws.StringValue(validator.Type), + } + } + return list +} + func resourceAwsAppconfigConfigurationProfileRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig @@ -131,6 +171,7 @@ func resourceAwsAppconfigConfigurationProfileRead(d *schema.ResourceData, meta i d.Set("application_id", output.ApplicationId) d.Set("location_uri", output.LocationUri) d.Set("retrieval_role_arn", output.RetrievalRoleArn) + d.Set("validators", flattenAwsAppconfigValidators(output.Validators)) profileARN := arn.ARN{ AccountID: meta.(*AWSClient).accountid, @@ -180,6 +221,10 @@ func resourceAwsAppconfigConfigurationProfileUpdate(d *schema.ResourceData, meta } } + if d.HasChange("validators") { + updateInput.Validators = expandAppconfigValidators(d.Get("validators").([]interface{})) + } + _, err := conn.UpdateConfigurationProfile(updateInput) if err != nil { return fmt.Errorf("error updating AppConfig ConfigurationProfile (%s): %s", d.Id(), err) From b68724aa4f78b09d76fec19e677fddc44258b2c3 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 22:53:50 +0900 Subject: [PATCH 03/16] docs: add a document of aws_appconfig_configuration_profile --- ...config_configuration_profile.html.markdown | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 website/docs/r/appconfig_configuration_profile.html.markdown diff --git a/website/docs/r/appconfig_configuration_profile.html.markdown b/website/docs/r/appconfig_configuration_profile.html.markdown new file mode 100644 index 00000000000..862e1648474 --- /dev/null +++ b/website/docs/r/appconfig_configuration_profile.html.markdown @@ -0,0 +1,67 @@ +--- +subcategory: "AppConfig" +layout: "aws" +page_title: "AWS: aws_appconfig_configuration_profile" +description: |- + Provides an AppConfig Configuration Profile resource. +--- + +# Resource: aws_appconfig_configuration_profile + +Provides an AppConfig Configuration Profile resource. + +## Example Usage + +### AppConfig Configuration Profile + +```hcl +resource "aws_appconfig_configuration_profile" "production" { + name = "test" + description = "test" + application_id = aws_appconfig_application.test.id + validators { + content = "arn:aws:lambda:us-east-1:111111111111:function:test" + type = "LAMBDA" + } +} + +resource "aws_appconfig_application" "test" { + name = "test" + description = "Test" + tags = { + Type = "Test" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +- `name` - (Required) The environment name. Must be between 1 and 64 characters in length. +- `application_id` - (Required) The application id. Must be between 4 and 7 characters in length. +- `description` - (Optional) The description of the environment. Can be at most 1024 characters. +- `location_uri` - (Optional) A URI to locate the configuration. +- `validators` - (Optional) A list of methods for validating the configuration. Detailed below. +- `retrieval_role_arn` - (Optional) The ARN of an IAM role with permission to access the configuration at the specified LocationUri. +- `tags` - (Optional) A map of tags to assign to the resource. + +### validator + +- `content` - (Optional) Either the JSON Schema content or the Amazon Resource Name (ARN) of an AWS Lambda function. +- `type` - (Optional) AWS AppConfig supports validators of type `JSON_SCHEMA` and `LAMBDA` + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +- `arn` - The Amazon Resource Name (ARN) of the AppConfig Configuration Profile. +- `id` - The AppConfig Configuration Profile ID + +## Import + +`aws_appconfig_configuration_profile` can be imported by the Application ID and Configuration Profile ID, e.g. + +``` +$ terraform import aws_appconfig_configuration_profile.test 71abcde/11xxxxx +``` From 5c1b1da230281fff6a652e21873e5cd93413622a Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 07:20:57 +0900 Subject: [PATCH 04/16] test: add tests for aws_appconfig_configuration_profile --- ...ws_appconfig_configuration_profile_test.go | 258 ++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 aws/resource_aws_appconfig_configuration_profile_test.go diff --git a/aws/resource_aws_appconfig_configuration_profile_test.go b/aws/resource_aws_appconfig_configuration_profile_test.go new file mode 100644 index 00000000000..a25999e52ff --- /dev/null +++ b/aws/resource_aws_appconfig_configuration_profile_test.go @@ -0,0 +1,258 @@ +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 TestAccAWSAppConfigConfigurationProfile_basic(t *testing.T) { + var profile appconfig.GetConfigurationProfileOutput + profileName := acctest.RandomWithPrefix("tf-acc-test") + profileDesc := acctest.RandomWithPrefix("desc") + resourceName := "aws_appconfig_configuration_profile.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigConfigurationProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigConfigurationProfile(profileName, profileDesc), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName, &profile), + resource.TestCheckResourceAttr(resourceName, "name", profileName), + testAccCheckAWSAppConfigConfigurationProfileARN(resourceName, &profile), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "description", profileDesc), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAppConfigConfigurationProfileImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigConfigurationProfile_disappears(t *testing.T) { + var profile appconfig.GetConfigurationProfileOutput + + profileName := acctest.RandomWithPrefix("tf-acc-test") + profileDesc := acctest.RandomWithPrefix("desc") + resourceName := "aws_appconfig_configuration_profile.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigConfigurationProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigConfigurationProfile(profileName, profileDesc), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName, &profile), + testAccCheckAWSAppConfigConfigurationProfileDisappears(&profile), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSAppConfigConfigurationProfile_Tags(t *testing.T) { + var profile appconfig.GetConfigurationProfileOutput + + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appconfig_configuration_profile.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigConfigurationProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigConfigurationProfileTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName, &profile), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAppConfigConfigurationProfileImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigConfigurationProfileTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName, &profile), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSAppConfigConfigurationProfileTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName, &profile), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func testAccCheckAppConfigConfigurationProfileDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_appconfig_configuration_profile" { + continue + } + + input := &appconfig.GetConfigurationProfileInput{ + ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), + ConfigurationProfileId: aws.String(rs.Primary.ID), + } + + output, err := conn.GetConfigurationProfile(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + continue + } + + if err != nil { + return err + } + + if output != nil { + return fmt.Errorf("AppConfig ConfigurationProfile (%s) still exists", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckAWSAppConfigConfigurationProfileDisappears(profile *appconfig.GetConfigurationProfileOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + _, err := conn.DeleteConfigurationProfile(&appconfig.DeleteConfigurationProfileInput{ + ApplicationId: profile.ApplicationId, + ConfigurationProfileId: profile.Id, + }) + + return err + } +} + +func testAccCheckAWSAppConfigConfigurationProfileExists(resourceName string, profile *appconfig.GetConfigurationProfileOutput) 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.GetConfigurationProfile(&appconfig.GetConfigurationProfileInput{ + ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), + ConfigurationProfileId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + *profile = *output + + return nil + } +} + +func testAccCheckAWSAppConfigConfigurationProfileARN(resourceName string, profile *appconfig.GetConfigurationProfileOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + return testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appconfig", fmt.Sprintf("application/%s/configurationprofile/%s", aws.StringValue(profile.ApplicationId), aws.StringValue(profile.Id)))(s) + } +} + +func testAccAWSAppConfigConfigurationProfile(profileName, profileDesc string) string { + appName := acctest.RandomWithPrefix("tf-acc-test") + appDesc := acctest.RandomWithPrefix("desc") + return testAccAWSAppConfigApplicationName(appName, appDesc) + fmt.Sprintf(` +resource "aws_appconfig_configuration_profile" "test" { + name = %[1]q + description = %[2]q + application_id = aws_appconfig_application.test.id + validators { + type = "JSON_SCHEMA" + content = jsonencode({ + "$schema" = "http://json-schema.org/draft-04/schema#" + title = "$id$" + description = "BasicFeatureToggle-1" + type = "object" + additionalProperties = false + patternProperties = { + "[^\\s]+$" = { + type = "boolean" + } + } + minProperties = 1 + }) + } +} +`, profileName, profileDesc) +} + +func testAccAWSAppConfigConfigurationProfileTags1(rName, tagKey1, tagValue1 string) string { + return testAccAWSAppConfigApplicationTags1(rName, tagKey1, tagValue1) + fmt.Sprintf(` +resource "aws_appconfig_configuration_profile" "test" { + name = %[1]q + application_id = aws_appconfig_application.test.id + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccAWSAppConfigConfigurationProfileTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return testAccAWSAppConfigApplicationTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2) + fmt.Sprintf(` +resource "aws_appconfig_configuration_profile" "test" { + name = %[1]q + application_id = aws_appconfig_application.test.id + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} + +func testAccAWSAppConfigConfigurationProfileImportStateIdFunc(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 fmt.Sprintf("%s/%s", rs.Primary.Attributes["application_id"], rs.Primary.ID), nil + } +} From ccc26509da0c853bc94db101564794e2cda9802a Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 09:39:35 +0900 Subject: [PATCH 05/16] docs: fix document of aws_appconfig_configuration_profile --- website/docs/r/appconfig_configuration_profile.html.markdown | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/website/docs/r/appconfig_configuration_profile.html.markdown b/website/docs/r/appconfig_configuration_profile.html.markdown index 862e1648474..01da1fef385 100644 --- a/website/docs/r/appconfig_configuration_profile.html.markdown +++ b/website/docs/r/appconfig_configuration_profile.html.markdown @@ -19,6 +19,7 @@ resource "aws_appconfig_configuration_profile" "production" { name = "test" description = "test" application_id = aws_appconfig_application.test.id + location_uri = "hosted" validators { content = "arn:aws:lambda:us-east-1:111111111111:function:test" type = "LAMBDA" @@ -39,9 +40,9 @@ resource "aws_appconfig_application" "test" { The following arguments are supported: - `name` - (Required) The environment name. Must be between 1 and 64 characters in length. -- `application_id` - (Required) The application id. Must be between 4 and 7 characters in length. +- `application_id` - (Required, Forces new resource) The application id. Must be between 4 and 7 characters in length. +- `location_uri` - (Required, Forces new resource) A URI to locate the configuration. - `description` - (Optional) The description of the environment. Can be at most 1024 characters. -- `location_uri` - (Optional) A URI to locate the configuration. - `validators` - (Optional) A list of methods for validating the configuration. Detailed below. - `retrieval_role_arn` - (Optional) The ARN of an IAM role with permission to access the configuration at the specified LocationUri. - `tags` - (Optional) A map of tags to assign to the resource. From 404d894fab1ed83001fcd6f1c9c4b5841d48faab Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 09:41:16 +0900 Subject: [PATCH 06/16] test: specify location_uri --- aws/resource_aws_appconfig_configuration_profile_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aws/resource_aws_appconfig_configuration_profile_test.go b/aws/resource_aws_appconfig_configuration_profile_test.go index a25999e52ff..8b08b7130e7 100644 --- a/aws/resource_aws_appconfig_configuration_profile_test.go +++ b/aws/resource_aws_appconfig_configuration_profile_test.go @@ -199,6 +199,7 @@ resource "aws_appconfig_configuration_profile" "test" { name = %[1]q description = %[2]q application_id = aws_appconfig_application.test.id + location_uri = "hosted" validators { type = "JSON_SCHEMA" content = jsonencode({ @@ -224,6 +225,7 @@ func testAccAWSAppConfigConfigurationProfileTags1(rName, tagKey1, tagValue1 stri resource "aws_appconfig_configuration_profile" "test" { name = %[1]q application_id = aws_appconfig_application.test.id + location_uri = "hosted" tags = { %[2]q = %[3]q @@ -237,6 +239,7 @@ func testAccAWSAppConfigConfigurationProfileTags2(rName, tagKey1, tagValue1, tag resource "aws_appconfig_configuration_profile" "test" { name = %[1]q application_id = aws_appconfig_application.test.id + location_uri = "hosted" tags = { %[2]q = %[3]q From ad8463fb8c15ea27858b13264aa480cec07968b6 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 09:42:45 +0900 Subject: [PATCH 07/16] docs: fix typo --- website/docs/r/appconfig_configuration_profile.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/appconfig_configuration_profile.html.markdown b/website/docs/r/appconfig_configuration_profile.html.markdown index 01da1fef385..c3974e546ee 100644 --- a/website/docs/r/appconfig_configuration_profile.html.markdown +++ b/website/docs/r/appconfig_configuration_profile.html.markdown @@ -39,10 +39,10 @@ resource "aws_appconfig_application" "test" { The following arguments are supported: -- `name` - (Required) The environment name. Must be between 1 and 64 characters in length. +- `name` - (Required) The configuration profile name. Must be between 1 and 64 characters in length. - `application_id` - (Required, Forces new resource) The application id. Must be between 4 and 7 characters in length. - `location_uri` - (Required, Forces new resource) A URI to locate the configuration. -- `description` - (Optional) The description of the environment. Can be at most 1024 characters. +- `description` - (Optional) The description of the configuration profile. Can be at most 1024 characters. - `validators` - (Optional) A list of methods for validating the configuration. Detailed below. - `retrieval_role_arn` - (Optional) The ARN of an IAM role with permission to access the configuration at the specified LocationUri. - `tags` - (Optional) A map of tags to assign to the resource. From e4d694558a6223cba25f7a4371da18d73ed6fbae Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 09:45:38 +0900 Subject: [PATCH 08/16] style: format code --- aws/resource_aws_appconfig_configuration_profile_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_appconfig_configuration_profile_test.go b/aws/resource_aws_appconfig_configuration_profile_test.go index 8b08b7130e7..4b873474fde 100644 --- a/aws/resource_aws_appconfig_configuration_profile_test.go +++ b/aws/resource_aws_appconfig_configuration_profile_test.go @@ -203,10 +203,10 @@ resource "aws_appconfig_configuration_profile" "test" { validators { type = "JSON_SCHEMA" content = jsonencode({ - "$schema" = "http://json-schema.org/draft-04/schema#" - title = "$id$" - description = "BasicFeatureToggle-1" - type = "object" + "$schema" = "http://json-schema.org/draft-04/schema#" + title = "$id$" + description = "BasicFeatureToggle-1" + type = "object" additionalProperties = false patternProperties = { "[^\\s]+$" = { From 68586b5810e52e0bfd7a865dc53ee995c7a27585 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 22:31:15 +0900 Subject: [PATCH 09/16] fix: fix typo --- aws/resource_aws_appconfig_configuration_profile.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_appconfig_configuration_profile.go b/aws/resource_aws_appconfig_configuration_profile.go index c0fce741008..331c1fc6372 100644 --- a/aws/resource_aws_appconfig_configuration_profile.go +++ b/aws/resource_aws_appconfig_configuration_profile.go @@ -211,7 +211,7 @@ func resourceAwsAppconfigConfigurationProfileUpdate(d *schema.ResourceData, meta } if d.HasChange("retrieval_role_arn") { - updateInput.Name = aws.String(d.Get("retrieval_role_arn").(string)) + updateInput.RetrievalRoleArn = aws.String(d.Get("retrieval_role_arn").(string)) } if d.HasChange("tags") { From ef6252e9e01014ad5ed113a92736d24834579977 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Fri, 14 May 2021 20:36:12 +0900 Subject: [PATCH 10/16] fix: set RetrievalRoleArn only when the value isn't empty To avoid the following error. ``` Error: Error creating AppConfig ConfigurationProfile: InvalidParameter: 1 validation error(s) found. - minimum field size of 20, CreateConfigurationProfileInput.RetrievalRoleArn. ``` --- ...ource_aws_appconfig_configuration_profile.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_appconfig_configuration_profile.go b/aws/resource_aws_appconfig_configuration_profile.go index 331c1fc6372..321aba0c793 100644 --- a/aws/resource_aws_appconfig_configuration_profile.go +++ b/aws/resource_aws_appconfig_configuration_profile.go @@ -97,13 +97,16 @@ func resourceAwsAppconfigConfigurationProfileCreate(d *schema.ResourceData, meta conn := meta.(*AWSClient).appconfigconn input := &appconfig.CreateConfigurationProfileInput{ - Name: aws.String(d.Get("name").(string)), - Description: aws.String(d.Get("description").(string)), - LocationUri: aws.String(d.Get("location_uri").(string)), - RetrievalRoleArn: aws.String(d.Get("retrieval_role_arn").(string)), - ApplicationId: aws.String(d.Get("application_id").(string)), - Validators: expandAppconfigValidators(d.Get("validators").([]interface{})), - Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), + Name: aws.String(d.Get("name").(string)), + Description: aws.String(d.Get("description").(string)), + LocationUri: aws.String(d.Get("location_uri").(string)), + ApplicationId: aws.String(d.Get("application_id").(string)), + Validators: expandAppconfigValidators(d.Get("validators").([]interface{})), + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), + } + + if retrievalRoleARN := d.Get("retrieval_role_arn").(string); retrievalRoleARN != "" { + input.RetrievalRoleArn = aws.String(retrievalRoleARN) } profile, err := conn.CreateConfigurationProfile(input) From 2f17a3d1350e668db928108c9b9940a259875908 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 09:02:12 +0900 Subject: [PATCH 11/16] feat: add aws_appconfig_hosted_configuration_version --- aws/provider.go | 1 + ..._appconfig_hosted_configuration_version.go | 168 ++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 aws/resource_aws_appconfig_hosted_configuration_version.go diff --git a/aws/provider.go b/aws/provider.go index 48e60dbd52c..6555293a310 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -509,6 +509,7 @@ func Provider() *schema.Provider { "aws_appconfig_application": resourceAwsAppconfigApplication(), "aws_appconfig_environment": resourceAwsAppconfigEnvironment(), "aws_appconfig_configuration_profile": resourceAwsAppconfigConfigurationProfile(), + "aws_appconfig_hosted_configuration_version": resourceAwsAppconfigHostedConfigurationVersion(), "aws_appmesh_gateway_route": resourceAwsAppmeshGatewayRoute(), "aws_appmesh_mesh": resourceAwsAppmeshMesh(), "aws_appmesh_route": resourceAwsAppmeshRoute(), diff --git a/aws/resource_aws_appconfig_hosted_configuration_version.go b/aws/resource_aws_appconfig_hosted_configuration_version.go new file mode 100644 index 00000000000..f7471fe0331 --- /dev/null +++ b/aws/resource_aws_appconfig_hosted_configuration_version.go @@ -0,0 +1,168 @@ +package aws + +import ( + "fmt" + "log" + "strconv" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "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" +) + +func resourceAwsAppconfigHostedConfigurationVersion() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAppconfigHostedConfigurationVersionCreate, + Read: resourceAwsAppconfigHostedConfigurationVersionRead, + Update: resourceAwsAppconfigHostedConfigurationVersionUpdate, + Delete: resourceAwsAppconfigHostedConfigurationVersionDelete, + Importer: &schema.ResourceImporter{ + State: resourceAwsAppconfigHostedConfigurationVersionImport, + }, + + Schema: map[string]*schema.Schema{ + "application_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(4, 7), + ), + }, + "configuration_profile_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(4, 7), + ), + }, + "content": { + Type: schema.TypeString, + Required: true, + }, + "content_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 255), + ), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 1024), + ), + }, + "version_number": { + Type: schema.TypeInt, + Computed: true, + }, + }, + } +} + +func resourceAwsAppconfigHostedConfigurationVersionCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + appID := d.Get("application_id").(string) + profileID := d.Get("configuration_profile_id").(string) + + input := &appconfig.CreateHostedConfigurationVersionInput{ + ApplicationId: aws.String(appID), + ConfigurationProfileId: aws.String(profileID), + Content: []byte(d.Get("content").(string)), + ContentType: aws.String(d.Get("content_type").(string)), + Description: aws.String(d.Get("description").(string)), + } + + hcv, err := conn.CreateHostedConfigurationVersion(input) + if err != nil { + return fmt.Errorf("Error creating AppConfig HostedConfigurationVersion: %s", err) + } + + d.SetId(fmt.Sprintf("%s/%s/%d", appID, profileID, aws.Int64Value(hcv.VersionNumber))) + d.Set("version_number", hcv.VersionNumber) + + return resourceAwsAppconfigHostedConfigurationVersionRead(d, meta) +} + +func resourceAwsAppconfigHostedConfigurationVersionRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + input := &appconfig.GetHostedConfigurationVersionInput{ + ApplicationId: aws.String(d.Get("application_id").(string)), + ConfigurationProfileId: aws.String(d.Get("configuration_profile_id").(string)), + VersionNumber: aws.Int64(int64(d.Get("version_number").(int))), + } + + output, err := conn.GetHostedConfigurationVersion(input) + + if !d.IsNewResource() && isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Appconfig HostedConfigurationVersion (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error getting AppConfig HostedConfigurationVersion (%s): %s", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting AppConfig HostedConfigurationVersion (%s): empty response", d.Id()) + } + + d.Set("description", output.Description) + d.Set("content", string(output.Content)) + d.Set("content_type", output.ContentType) + + return nil +} + +func resourceAwsAppconfigHostedConfigurationVersionUpdate(d *schema.ResourceData, meta interface{}) error { + return resourceAwsAppconfigHostedConfigurationVersionCreate(d, meta) +} + +func resourceAwsAppconfigHostedConfigurationVersionDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + input := &appconfig.DeleteHostedConfigurationVersionInput{ + ConfigurationProfileId: aws.String(d.Get("configuration_profile_id").(string)), + ApplicationId: aws.String(d.Get("application_id").(string)), + VersionNumber: aws.Int64(d.Get("version_number").(int64)), + } + + _, err := conn.DeleteHostedConfigurationVersion(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Appconfig HostedConfigurationVersion (%s): %s", d.Id(), err) + } + + return nil +} + +func resourceAwsAppconfigHostedConfigurationVersionImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(d.Id(), "/") + if len(parts) != 3 { + return nil, fmt.Errorf("Wrong format of resource: %s. Please follow 'application-id/configurationprofile-id/version-number'", d.Id()) + } + + verString := parts[2] + verNumber, err := strconv.Atoi(verString) + if err != nil { + return nil, fmt.Errorf("version-number must be integer: %s: %w", verString, err) + } + + d.Set("application_id", parts[0]) + d.Set("configuration_profile_id", parts[1]) + d.Set("version_number", verNumber) + + return []*schema.ResourceData{d}, nil +} From 7578a0ec4c8b9563bda6dbe9067a629a1c2de803 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 09:34:13 +0900 Subject: [PATCH 12/16] docs: add document of appconfig_hosted_configuration_version --- ...hosted_configuration_version.html.markdown | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 website/docs/r/appconfig_hosted_configuration_version.html.markdown diff --git a/website/docs/r/appconfig_hosted_configuration_version.html.markdown b/website/docs/r/appconfig_hosted_configuration_version.html.markdown new file mode 100644 index 00000000000..1482f5ecb80 --- /dev/null +++ b/website/docs/r/appconfig_hosted_configuration_version.html.markdown @@ -0,0 +1,62 @@ +--- +subcategory: "AppConfig" +layout: "aws" +page_title: "AWS: aws_appconfig_hosted_configuration_version" +description: |- + Provides an AppConfig Hosted Configuration Version resource. +--- + +# Resource: aws_appconfig_hosted_configuration_version + +Provides an AppConfig Hosted Configuration Version resource. + +## Example Usage + +### AppConfig Hosted Configuration Version + +```hcl +resource "aws_appconfig_hosted_configuration_version" "production" { + application_id = aws_appconfig_application.test.id + configuration_profile_id = aws_appconfig_configuration_profile.test.id + description = "test" + content_type = "application/json" + content = jsonencode({ + foo = "foo" + }) +} + +resource "aws_appconfig_application" "test" { + name = "test" +} + +resource "aws_appconfig_configuration_profile" "test" { + name = "test" + application_id = aws_appconfig_application.test.id + location_uri = "hosted" +} +``` + +## Argument Reference + +The following arguments are supported: + +- `application_id` - (Required) The application id. +- `configuration_profile_id` - (Required) The configuration profile ID. +- `content` - (Required) The content of the configuration or the configuration data. +- `content_type` - (Required) A standard MIME type describing the format of the configuration content. +- `description` - (Optional) A description of the configuration. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +- `version_number` - hosted configuration version +- `id` - `//` + +## Import + +`aws_appconfig_hosted_configuration_version` can be imported by the Application ID and Configuration Profile ID and Hosted Configuration Version Number, e.g. + +``` +$ terraform import aws_appconfig_hosted_configuration_version.test 71abcde/11xxxxx/2 +``` From 9d464419e3de6c32d48a6c954f664da7604853e4 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Fri, 14 May 2021 21:37:43 +0900 Subject: [PATCH 13/16] test: add tests of aws_appconfig_hosted_configuration_version --- ...onfig_hosted_configuration_version_test.go | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 aws/resource_aws_appconfig_hosted_configuration_version_test.go diff --git a/aws/resource_aws_appconfig_hosted_configuration_version_test.go b/aws/resource_aws_appconfig_hosted_configuration_version_test.go new file mode 100644 index 00000000000..94971188037 --- /dev/null +++ b/aws/resource_aws_appconfig_hosted_configuration_version_test.go @@ -0,0 +1,178 @@ +package aws + +import ( + "fmt" + "strconv" + "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 TestAccAWSAppConfigHostedConfigurationVersion_basic(t *testing.T) { + var out appconfig.GetHostedConfigurationVersionOutput + resourceName := "aws_appconfig_hosted_configuration_version.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigHostedConfigurationVersionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigHostedConfigurationVersion(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigHostedConfigurationVersionExists(resourceName, &out), + testAccCheckAWSAppConfigHostedConfigurationVersionARN(resourceName, &out), + resource.TestCheckResourceAttr(resourceName, "description", "hosted configuration version description"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAppConfigHostedConfigurationVersionImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigHostedConfigurationVersion_disappears(t *testing.T) { + var out appconfig.GetHostedConfigurationVersionOutput + resourceName := "aws_appconfig_hosted_configuration_version.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigHostedConfigurationVersionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigHostedConfigurationVersion(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigHostedConfigurationVersionExists(resourceName, &out), + testAccCheckAWSAppConfigHostedConfigurationVersionDisappears(&out), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAppConfigHostedConfigurationVersionDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_appconfig_hosted_configuration_version" { + continue + } + versionNumber, err := strconv.Atoi(rs.Primary.Attributes["version_number"]) + if err != nil { + return fmt.Errorf("failed to convert version_number into int (%s): %w", rs.Primary.Attributes["version_number"], err) + } + + input := &appconfig.GetHostedConfigurationVersionInput{ + ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), + ConfigurationProfileId: aws.String(rs.Primary.Attributes["configuration_profile_id"]), + VersionNumber: aws.Int64(int64(versionNumber)), + } + + output, err := conn.GetHostedConfigurationVersion(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + continue + } + + if err != nil { + return err + } + + if output != nil { + return fmt.Errorf("AppConfig HostedConfigurationVersion (%s) still exists", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckAWSAppConfigHostedConfigurationVersionDisappears(hcv *appconfig.GetHostedConfigurationVersionOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + _, err := conn.DeleteHostedConfigurationVersion(&appconfig.DeleteHostedConfigurationVersionInput{ + ApplicationId: hcv.ApplicationId, + ConfigurationProfileId: hcv.ConfigurationProfileId, + VersionNumber: hcv.VersionNumber, + }) + + return err + } +} + +func testAccCheckAWSAppConfigHostedConfigurationVersionExists(resourceName string, hcv *appconfig.GetHostedConfigurationVersionOutput) 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 + + versionNumber, err := strconv.Atoi(rs.Primary.Attributes["version_number"]) + if err != nil { + return fmt.Errorf("failed to convert version_number into int (%s): %w", rs.Primary.Attributes["version_number"], err) + } + + output, err := conn.GetHostedConfigurationVersion(&appconfig.GetHostedConfigurationVersionInput{ + ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), + ConfigurationProfileId: aws.String(rs.Primary.Attributes["configuration_profile_id"]), + VersionNumber: aws.Int64(int64(versionNumber)), + }) + if err != nil { + return err + } + + *hcv = *output + + return nil + } +} + +func testAccCheckAWSAppConfigHostedConfigurationVersionARN(resourceName string, hcv *appconfig.GetHostedConfigurationVersionOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + return testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appconfig", fmt.Sprintf("application/%s/configurationprofile/%s/hostedconfigurationversion/%d", aws.StringValue(hcv.ApplicationId), aws.StringValue(hcv.ConfigurationProfileId), aws.Int64Value(hcv.VersionNumber)))(s) + } +} + +func testAccAWSAppConfigHostedConfigurationVersion() string { + appName := acctest.RandomWithPrefix("tf-acc-test") + profileName := acctest.RandomWithPrefix("tf-acc-test") + return testAccAWSAppConfigApplicationName(appName, "test") + testAccAWSAppConfigConfigurationProfile(profileName, "test") + ` +resource "aws_appconfig_hosted_configuration_version" "test" { + application_id = aws_appconfig_application.test.id + configuration_profile_id = aws_appconfig_configuration_profile.test.id + description = "hosted configuration version description" + content_type = "application/json" + content = jsonencode({ + foo = "foo" + }) +} +` +} + +func testAccAWSAppConfigHostedConfigurationVersionImportStateIdFunc(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 ec19afb46a36de3f7dcbdb64cadf51f819943da0 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Mon, 12 Jul 2021 12:05:24 +0900 Subject: [PATCH 14/16] fix: fix the error `undefined: testAccAWSAppConfigApplicationName` --- aws/resource_aws_appconfig_configuration_profile_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_appconfig_configuration_profile_test.go b/aws/resource_aws_appconfig_configuration_profile_test.go index 4b873474fde..f594dad9bf6 100644 --- a/aws/resource_aws_appconfig_configuration_profile_test.go +++ b/aws/resource_aws_appconfig_configuration_profile_test.go @@ -194,7 +194,7 @@ func testAccCheckAWSAppConfigConfigurationProfileARN(resourceName string, profil func testAccAWSAppConfigConfigurationProfile(profileName, profileDesc string) string { appName := acctest.RandomWithPrefix("tf-acc-test") appDesc := acctest.RandomWithPrefix("desc") - return testAccAWSAppConfigApplicationName(appName, appDesc) + fmt.Sprintf(` + return testAccAWSAppConfigApplicationConfigDescription(appName, appDesc) + fmt.Sprintf(` resource "aws_appconfig_configuration_profile" "test" { name = %[1]q description = %[2]q From 3a621b2fb5b76f826e6544780f2c1ca27eab3d68 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Mon, 12 Jul 2021 12:15:55 +0900 Subject: [PATCH 15/16] fix: fix the error `undefined: testAccAWSAppConfigApplicationName` --- aws/resource_aws_appconfig_hosted_configuration_version_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_appconfig_hosted_configuration_version_test.go b/aws/resource_aws_appconfig_hosted_configuration_version_test.go index 94971188037..8215e67cf9a 100644 --- a/aws/resource_aws_appconfig_hosted_configuration_version_test.go +++ b/aws/resource_aws_appconfig_hosted_configuration_version_test.go @@ -153,7 +153,7 @@ func testAccCheckAWSAppConfigHostedConfigurationVersionARN(resourceName string, func testAccAWSAppConfigHostedConfigurationVersion() string { appName := acctest.RandomWithPrefix("tf-acc-test") profileName := acctest.RandomWithPrefix("tf-acc-test") - return testAccAWSAppConfigApplicationName(appName, "test") + testAccAWSAppConfigConfigurationProfile(profileName, "test") + ` + return testAccAWSAppConfigApplicationConfigDescription(appName, "test") + testAccAWSAppConfigConfigurationProfile(profileName, "test") + ` resource "aws_appconfig_hosted_configuration_version" "test" { application_id = aws_appconfig_application.test.id configuration_profile_id = aws_appconfig_configuration_profile.test.id From dceee240f1466a3faff1adce7c64a7e0ea411da8 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Mon, 12 Jul 2021 09:52:01 -0400 Subject: [PATCH 16/16] CR updates; add CHANGELOG entry --- .changelog/19324.txt | 3 + aws/provider.go | 1 - ...rce_aws_appconfig_configuration_profile.go | 2 +- aws/resource_aws_appconfig_environment.go | 2 +- ..._appconfig_hosted_configuration_version.go | 142 ++++++++++-------- ...onfig_hosted_configuration_version_test.go | 113 ++++++-------- website/docs/index.html.markdown | 1 + ...hosted_configuration_version.html.markdown | 44 +++--- 8 files changed, 153 insertions(+), 155 deletions(-) create mode 100644 .changelog/19324.txt diff --git a/.changelog/19324.txt b/.changelog/19324.txt new file mode 100644 index 00000000000..14d91b6069a --- /dev/null +++ b/.changelog/19324.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_appconfig_hosted_configuration_version +``` diff --git a/aws/provider.go b/aws/provider.go index c060a254917..f8570bba6aa 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -509,7 +509,6 @@ func Provider() *schema.Provider { "aws_appconfig_application": resourceAwsAppconfigApplication(), "aws_appconfig_configuration_profile": resourceAwsAppconfigConfigurationProfile(), "aws_appconfig_environment": resourceAwsAppconfigEnvironment(), - "aws_appconfig_configuration_profile": resourceAwsAppconfigConfigurationProfile(), "aws_appconfig_hosted_configuration_version": resourceAwsAppconfigHostedConfigurationVersion(), "aws_appmesh_gateway_route": resourceAwsAppmeshGatewayRoute(), "aws_appmesh_mesh": resourceAwsAppmeshMesh(), diff --git a/aws/resource_aws_appconfig_configuration_profile.go b/aws/resource_aws_appconfig_configuration_profile.go index 6a17f212012..585b468fe78 100644 --- a/aws/resource_aws_appconfig_configuration_profile.go +++ b/aws/resource_aws_appconfig_configuration_profile.go @@ -287,7 +287,7 @@ func resourceAwsAppconfigConfigurationProfileParseID(id string) (string, string, parts := strings.Split(id, ":") if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return "", "", fmt.Errorf("unexpected format of ID (%q), expected configurationProfileID:applicationID", id) + return "", "", fmt.Errorf("unexpected format of ID (%q), expected ConfigurationProfileID:ApplicationID", id) } return parts[0], parts[1], nil diff --git a/aws/resource_aws_appconfig_environment.go b/aws/resource_aws_appconfig_environment.go index 413b95f8f94..14f4d67513e 100644 --- a/aws/resource_aws_appconfig_environment.go +++ b/aws/resource_aws_appconfig_environment.go @@ -261,7 +261,7 @@ func resourceAwsAppconfigEnvironmentParseID(id string) (string, string, error) { parts := strings.Split(id, ":") if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return "", "", fmt.Errorf("unexpected format of ID (%q), expected environmentID:applicationID", id) + return "", "", fmt.Errorf("unexpected format of ID (%q), expected EnvironmentID:ApplicationID", id) } return parts[0], parts[1], nil diff --git a/aws/resource_aws_appconfig_hosted_configuration_version.go b/aws/resource_aws_appconfig_hosted_configuration_version.go index f7471fe0331..f9c0507c01e 100644 --- a/aws/resource_aws_appconfig_hosted_configuration_version.go +++ b/aws/resource_aws_appconfig_hosted_configuration_version.go @@ -3,11 +3,14 @@ package aws import ( "fmt" "log" + "regexp" "strconv" "strings" "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" ) @@ -16,46 +19,45 @@ func resourceAwsAppconfigHostedConfigurationVersion() *schema.Resource { return &schema.Resource{ Create: resourceAwsAppconfigHostedConfigurationVersionCreate, Read: resourceAwsAppconfigHostedConfigurationVersionRead, - Update: resourceAwsAppconfigHostedConfigurationVersionUpdate, Delete: resourceAwsAppconfigHostedConfigurationVersionDelete, Importer: &schema.ResourceImporter{ - State: resourceAwsAppconfigHostedConfigurationVersionImport, + State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ "application_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`[a-z0-9]{4,7}`), ""), + }, + "arn": { Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(4, 7), - ), + Computed: true, }, "configuration_profile_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(4, 7), - ), + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`[a-z0-9]{4,7}`), ""), }, "content": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + Sensitive: true, }, "content_type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 255), - ), + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, "description": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.All( - validation.StringLenBetween(0, 1024), - ), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(0, 1024), }, "version_number": { Type: schema.TypeInt, @@ -76,16 +78,19 @@ func resourceAwsAppconfigHostedConfigurationVersionCreate(d *schema.ResourceData ConfigurationProfileId: aws.String(profileID), Content: []byte(d.Get("content").(string)), ContentType: aws.String(d.Get("content_type").(string)), - Description: aws.String(d.Get("description").(string)), } - hcv, err := conn.CreateHostedConfigurationVersion(input) + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + output, err := conn.CreateHostedConfigurationVersion(input) + if err != nil { - return fmt.Errorf("Error creating AppConfig HostedConfigurationVersion: %s", err) + return fmt.Errorf("error creating AppConfig HostedConfigurationVersion for Application (%s): %w", appID, err) } - d.SetId(fmt.Sprintf("%s/%s/%d", appID, profileID, aws.Int64Value(hcv.VersionNumber))) - d.Set("version_number", hcv.VersionNumber) + d.SetId(fmt.Sprintf("%s/%s/%d", aws.StringValue(output.ApplicationId), aws.StringValue(output.ConfigurationProfileId), aws.Int64Value(output.VersionNumber))) return resourceAwsAppconfigHostedConfigurationVersionRead(d, meta) } @@ -93,76 +98,93 @@ func resourceAwsAppconfigHostedConfigurationVersionCreate(d *schema.ResourceData func resourceAwsAppconfigHostedConfigurationVersionRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn + appID, confProfID, versionNumber, err := resourceAwsAppconfigHostedConfigurationVersionParseID(d.Id()) + + if err != nil { + return err + } + input := &appconfig.GetHostedConfigurationVersionInput{ - ApplicationId: aws.String(d.Get("application_id").(string)), - ConfigurationProfileId: aws.String(d.Get("configuration_profile_id").(string)), - VersionNumber: aws.Int64(int64(d.Get("version_number").(int))), + ApplicationId: aws.String(appID), + ConfigurationProfileId: aws.String(confProfID), + VersionNumber: aws.Int64(int64(versionNumber)), } output, err := conn.GetHostedConfigurationVersion(input) - if !d.IsNewResource() && isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] Appconfig HostedConfigurationVersion (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { + log.Printf("[WARN] Appconfig Hosted Configuration Version (%s) not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error getting AppConfig HostedConfigurationVersion (%s): %s", d.Id(), err) + return fmt.Errorf("error getting AppConfig Hosted Configuration Version (%s): %w", d.Id(), err) } if output == nil { - return fmt.Errorf("error getting AppConfig HostedConfigurationVersion (%s): empty response", d.Id()) + return fmt.Errorf("error getting AppConfig Hosted Configuration Version (%s): empty response", d.Id()) } - d.Set("description", output.Description) + d.Set("application_id", output.ApplicationId) + d.Set("configuration_profile_id", output.ConfigurationProfileId) d.Set("content", string(output.Content)) d.Set("content_type", output.ContentType) + d.Set("description", output.Description) + d.Set("version_number", output.VersionNumber) - return nil -} + arn := arn.ARN{ + AccountID: meta.(*AWSClient).accountid, + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("application/%s/configurationprofile/%s/hostedconfigurationversion/%d", appID, confProfID, versionNumber), + Service: "appconfig", + }.String() -func resourceAwsAppconfigHostedConfigurationVersionUpdate(d *schema.ResourceData, meta interface{}) error { - return resourceAwsAppconfigHostedConfigurationVersionCreate(d, meta) + d.Set("arn", arn) + + return nil } func resourceAwsAppconfigHostedConfigurationVersionDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn + appID, confProfID, versionNumber, err := resourceAwsAppconfigHostedConfigurationVersionParseID(d.Id()) + + if err != nil { + return err + } + input := &appconfig.DeleteHostedConfigurationVersionInput{ - ConfigurationProfileId: aws.String(d.Get("configuration_profile_id").(string)), - ApplicationId: aws.String(d.Get("application_id").(string)), - VersionNumber: aws.Int64(d.Get("version_number").(int64)), + ApplicationId: aws.String(appID), + ConfigurationProfileId: aws.String(confProfID), + VersionNumber: aws.Int64(int64(versionNumber)), } - _, err := conn.DeleteHostedConfigurationVersion(input) + _, err = conn.DeleteHostedConfigurationVersion(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { return nil } if err != nil { - return fmt.Errorf("error deleting Appconfig HostedConfigurationVersion (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting Appconfig Hosted Configuration Version (%s): %w", d.Id(), err) } return nil } -func resourceAwsAppconfigHostedConfigurationVersionImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(d.Id(), "/") - if len(parts) != 3 { - return nil, fmt.Errorf("Wrong format of resource: %s. Please follow 'application-id/configurationprofile-id/version-number'", d.Id()) +func resourceAwsAppconfigHostedConfigurationVersionParseID(id string) (string, string, int, error) { + parts := strings.Split(id, "/") + + if len(parts) != 3 || parts[0] == "" || parts[1] == "" || parts[2] == "" { + return "", "", 0, fmt.Errorf("unexpected format of ID (%q), expected ApplicationID/ConfigurationProfileID/VersionNumber", id) } - verString := parts[2] - verNumber, err := strconv.Atoi(verString) + version, err := strconv.Atoi(parts[2]) if err != nil { - return nil, fmt.Errorf("version-number must be integer: %s: %w", verString, err) + return "", "", 0, fmt.Errorf("error parsing Hosted Configuration Version version_number: %w", err) } - d.Set("application_id", parts[0]) - d.Set("configuration_profile_id", parts[1]) - d.Set("version_number", verNumber) - - return []*schema.ResourceData{d}, nil + return parts[0], parts[1], version, nil } diff --git a/aws/resource_aws_appconfig_hosted_configuration_version_test.go b/aws/resource_aws_appconfig_hosted_configuration_version_test.go index 8215e67cf9a..f08738cfb8d 100644 --- a/aws/resource_aws_appconfig_hosted_configuration_version_test.go +++ b/aws/resource_aws_appconfig_hosted_configuration_version_test.go @@ -2,19 +2,21 @@ package aws import ( "fmt" - "strconv" + "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 TestAccAWSAppConfigHostedConfigurationVersion_basic(t *testing.T) { - var out appconfig.GetHostedConfigurationVersionOutput + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_hosted_configuration_version.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), @@ -22,16 +24,20 @@ func TestAccAWSAppConfigHostedConfigurationVersion_basic(t *testing.T) { CheckDestroy: testAccCheckAppConfigHostedConfigurationVersionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAppConfigHostedConfigurationVersion(), + Config: testAccAWSAppConfigHostedConfigurationVersion(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigHostedConfigurationVersionExists(resourceName, &out), - testAccCheckAWSAppConfigHostedConfigurationVersionARN(resourceName, &out), - resource.TestCheckResourceAttr(resourceName, "description", "hosted configuration version description"), + testAccCheckAWSAppConfigHostedConfigurationVersionExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "appconfig", regexp.MustCompile(`application/[a-z0-9]{4,7}/configurationprofile/[a-z0-9]{4,7}/hostedconfigurationversion/[0-9]+`)), + resource.TestCheckResourceAttrPair(resourceName, "application_id", "aws_appconfig_application.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "configuration_profile_id", "aws_appconfig_configuration_profile.test", "configuration_profile_id"), + resource.TestCheckResourceAttr(resourceName, "content", "{\"foo\":\"bar\"}"), + resource.TestCheckResourceAttr(resourceName, "content_type", "application/json"), + resource.TestCheckResourceAttr(resourceName, "description", rName), + resource.TestCheckResourceAttr(resourceName, "version_number", "1"), ), }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAppConfigHostedConfigurationVersionImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -40,7 +46,7 @@ func TestAccAWSAppConfigHostedConfigurationVersion_basic(t *testing.T) { } func TestAccAWSAppConfigHostedConfigurationVersion_disappears(t *testing.T) { - var out appconfig.GetHostedConfigurationVersionOutput + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_hosted_configuration_version.test" resource.ParallelTest(t, resource.TestCase{ @@ -50,10 +56,10 @@ func TestAccAWSAppConfigHostedConfigurationVersion_disappears(t *testing.T) { CheckDestroy: testAccCheckAppConfigHostedConfigurationVersionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAppConfigHostedConfigurationVersion(), + Config: testAccAWSAppConfigHostedConfigurationVersion(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigHostedConfigurationVersionExists(resourceName, &out), - testAccCheckAWSAppConfigHostedConfigurationVersionDisappears(&out), + testAccCheckAWSAppConfigHostedConfigurationVersionExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAppconfigHostedConfigurationVersion(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -68,50 +74,38 @@ func testAccCheckAppConfigHostedConfigurationVersionDestroy(s *terraform.State) if rs.Type != "aws_appconfig_hosted_configuration_version" { continue } - versionNumber, err := strconv.Atoi(rs.Primary.Attributes["version_number"]) + + appID, confProfID, versionNumber, err := resourceAwsAppconfigHostedConfigurationVersionParseID(rs.Primary.ID) + if err != nil { - return fmt.Errorf("failed to convert version_number into int (%s): %w", rs.Primary.Attributes["version_number"], err) + return err } input := &appconfig.GetHostedConfigurationVersionInput{ - ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), - ConfigurationProfileId: aws.String(rs.Primary.Attributes["configuration_profile_id"]), + ApplicationId: aws.String(appID), + ConfigurationProfileId: aws.String(confProfID), VersionNumber: aws.Int64(int64(versionNumber)), } output, err := conn.GetHostedConfigurationVersion(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { continue } if err != nil { - return err + return fmt.Errorf("error reading AppConfig Hosted Configuration Version (%s): %w", rs.Primary.ID, err) } if output != nil { - return fmt.Errorf("AppConfig HostedConfigurationVersion (%s) still exists", rs.Primary.ID) + return fmt.Errorf("AppConfig Hosted Configuration Version (%s) still exists", rs.Primary.ID) } } return nil } -func testAccCheckAWSAppConfigHostedConfigurationVersionDisappears(hcv *appconfig.GetHostedConfigurationVersionOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).appconfigconn - - _, err := conn.DeleteHostedConfigurationVersion(&appconfig.DeleteHostedConfigurationVersionInput{ - ApplicationId: hcv.ApplicationId, - ConfigurationProfileId: hcv.ConfigurationProfileId, - VersionNumber: hcv.VersionNumber, - }) - - return err - } -} - -func testAccCheckAWSAppConfigHostedConfigurationVersionExists(resourceName string, hcv *appconfig.GetHostedConfigurationVersionOutput) resource.TestCheckFunc { +func testAccCheckAWSAppConfigHostedConfigurationVersionExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -122,57 +116,46 @@ func testAccCheckAWSAppConfigHostedConfigurationVersionExists(resourceName strin return fmt.Errorf("Resource (%s) ID not set", resourceName) } - conn := testAccProvider.Meta().(*AWSClient).appconfigconn + appID, confProfID, versionNumber, err := resourceAwsAppconfigHostedConfigurationVersionParseID(rs.Primary.ID) - versionNumber, err := strconv.Atoi(rs.Primary.Attributes["version_number"]) if err != nil { - return fmt.Errorf("failed to convert version_number into int (%s): %w", rs.Primary.Attributes["version_number"], err) + return err } + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + output, err := conn.GetHostedConfigurationVersion(&appconfig.GetHostedConfigurationVersionInput{ - ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), - ConfigurationProfileId: aws.String(rs.Primary.Attributes["configuration_profile_id"]), + ApplicationId: aws.String(appID), + ConfigurationProfileId: aws.String(confProfID), VersionNumber: aws.Int64(int64(versionNumber)), }) + if err != nil { - return err + return fmt.Errorf("error reading AppConfig Hosted Configuration Version (%s): %w", rs.Primary.ID, err) } - *hcv = *output + if output == nil { + return fmt.Errorf("AppConfig Hosted Configuration Version (%s) not found", rs.Primary.ID) + } return nil } } -func testAccCheckAWSAppConfigHostedConfigurationVersionARN(resourceName string, hcv *appconfig.GetHostedConfigurationVersionOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - return testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appconfig", fmt.Sprintf("application/%s/configurationprofile/%s/hostedconfigurationversion/%d", aws.StringValue(hcv.ApplicationId), aws.StringValue(hcv.ConfigurationProfileId), aws.Int64Value(hcv.VersionNumber)))(s) - } -} - -func testAccAWSAppConfigHostedConfigurationVersion() string { - appName := acctest.RandomWithPrefix("tf-acc-test") - profileName := acctest.RandomWithPrefix("tf-acc-test") - return testAccAWSAppConfigApplicationConfigDescription(appName, "test") + testAccAWSAppConfigConfigurationProfile(profileName, "test") + ` +func testAccAWSAppConfigHostedConfigurationVersion(rName string) string { + return composeConfig( + testAccAWSAppConfigConfigurationProfileConfigName(rName), + fmt.Sprintf(` resource "aws_appconfig_hosted_configuration_version" "test" { application_id = aws_appconfig_application.test.id - configuration_profile_id = aws_appconfig_configuration_profile.test.id - description = "hosted configuration version description" + configuration_profile_id = aws_appconfig_configuration_profile.test.configuration_profile_id content_type = "application/json" + content = jsonencode({ - foo = "foo" + foo = "bar" }) -} -` -} - -func testAccAWSAppConfigHostedConfigurationVersionImportStateIdFunc(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 - } + description = %q +} +`, rName)) } diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 018261ceed2..9f38e67fa0f 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -254,6 +254,7 @@ for more information about connecting to alternate AWS endpoints or AWS compatib - [`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_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) - [`aws_budgets_budget` resource](/docs/providers/aws/r/budgets_budget.html) - [`aws_codedeploy_app` resource](/docs/providers/aws/r/codedeploy_app.html) diff --git a/website/docs/r/appconfig_hosted_configuration_version.html.markdown b/website/docs/r/appconfig_hosted_configuration_version.html.markdown index 1482f5ecb80..a898309c10f 100644 --- a/website/docs/r/appconfig_hosted_configuration_version.html.markdown +++ b/website/docs/r/appconfig_hosted_configuration_version.html.markdown @@ -12,51 +12,41 @@ Provides an AppConfig Hosted Configuration Version resource. ## Example Usage -### AppConfig Hosted Configuration Version - -```hcl -resource "aws_appconfig_hosted_configuration_version" "production" { - application_id = aws_appconfig_application.test.id - configuration_profile_id = aws_appconfig_configuration_profile.test.id - description = "test" +```terraform +resource "aws_appconfig_hosted_configuration_version" "example" { + application_id = aws_appconfig_application.example.id + configuration_profile_id = aws_appconfig_configuration_profile.example.configuration_profile_id + description = "Example Hosted Configuration Version" content_type = "application/json" + content = jsonencode({ - foo = "foo" + foo = "bar" }) } - -resource "aws_appconfig_application" "test" { - name = "test" -} - -resource "aws_appconfig_configuration_profile" "test" { - name = "test" - application_id = aws_appconfig_application.test.id - location_uri = "hosted" -} ``` ## Argument Reference The following arguments are supported: -- `application_id` - (Required) The application id. -- `configuration_profile_id` - (Required) The configuration profile ID. -- `content` - (Required) The content of the configuration or the configuration data. -- `content_type` - (Required) A standard MIME type describing the format of the configuration content. -- `description` - (Optional) A description of the configuration. +* `application_id` - (Required, Forces new resource) The application ID. +* `configuration_profile_id` - (Required, Forces new resource) The configuration profile ID. +* `content` - (Required, Forces new resource) The content of the configuration or the configuration data. +* `content_type` - (Required, Forces new resource) A standard MIME type describing the format of the configuration content. For more information, see [Content-Type](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17). +* `description` - (Optional, Forces new resource) A description of the configuration. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -- `version_number` - hosted configuration version -- `id` - `//` +* `arn` - The Amazon Resource Name (ARN) of the AppConfig hosted configuration version. +* `id` - The AppConfig application ID, configuration profile ID, and version number separated by a slash (`/`). +* `version_number` - The version number of the hosted configuration. ## Import -`aws_appconfig_hosted_configuration_version` can be imported by the Application ID and Configuration Profile ID and Hosted Configuration Version Number, e.g. +AppConfig Hosted Configuration Versions can be imported by using the application ID, configuration profile ID, and version number separated by a slash (`/`), e.g. ``` -$ terraform import aws_appconfig_hosted_configuration_version.test 71abcde/11xxxxx/2 +$ terraform import aws_appconfig_hosted_configuration_version.example 71abcde/11xxxxx/2 ```