From 3772c52d019fdb2e013a4b17aeb9383f0c2791a3 Mon Sep 17 00:00:00 2001 From: lukehendrick Date: Thu, 22 Oct 2020 22:52:52 -0500 Subject: [PATCH 0001/1208] Updating port numbers in customer service endpoints documentation --- .../guides/custom-service-endpoints.html.md | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/website/docs/guides/custom-service-endpoints.html.md b/website/docs/guides/custom-service-endpoints.html.md index 2a113a66f805..23ffd0a61264 100644 --- a/website/docs/guides/custom-service-endpoints.html.md +++ b/website/docs/guides/custom-service-endpoints.html.md @@ -245,25 +245,25 @@ provider "aws" { skip_requesting_account_id = true endpoints { - apigateway = "http://localhost:4567" - cloudformation = "http://localhost:4581" - cloudwatch = "http://localhost:4582" - dynamodb = "http://localhost:4569" - es = "http://localhost:4578" - firehose = "http://localhost:4573" - iam = "http://localhost:4593" - kinesis = "http://localhost:4568" - lambda = "http://localhost:4574" - route53 = "http://localhost:4580" - redshift = "http://localhost:4577" - s3 = "http://localhost:4572" - secretsmanager = "http://localhost:4584" - ses = "http://localhost:4579" - sns = "http://localhost:4575" - sqs = "http://localhost:4576" - ssm = "http://localhost:4583" - stepfunctions = "http://localhost:4585" - sts = "http://localhost:4592" + apigateway = "http://localhost:4566" + cloudformation = "http://localhost:4566" + cloudwatch = "http://localhost:4566" + dynamodb = "http://localhost:4566" + es = "http://localhost:4566" + firehose = "http://localhost:4566" + iam = "http://localhost:4566" + kinesis = "http://localhost:4566" + lambda = "http://localhost:4566" + route53 = "http://localhost:4566" + redshift = "http://localhost:4566" + s3 = "http://localhost:4566" + secretsmanager = "http://localhost:4566" + ses = "http://localhost:4566" + sns = "http://localhost:4566" + sqs = "http://localhost:4566" + ssm = "http://localhost:4566" + stepfunctions = "http://localhost:4566" + sts = "http://localhost:4566" } } ``` From 8204801d424a347dce9df80ad7c1436fdf780d5e Mon Sep 17 00:00:00 2001 From: Isaiah-Turner <42742035+Isaiah-Turner@users.noreply.github.com> Date: Wed, 10 Mar 2021 15:15:43 -0500 Subject: [PATCH 0002/1208] Added AppConfig to keyvalue generators --- aws/config.go | 3 +++ aws/internal/keyvaluetags/generators/listtags/main.go | 1 + aws/internal/keyvaluetags/generators/servicetags/main.go | 1 + aws/internal/keyvaluetags/generators/updatetags/main.go | 1 + aws/internal/keyvaluetags/service_generation_customizations.go | 3 +++ 5 files changed, 9 insertions(+) diff --git a/aws/config.go b/aws/config.go index 0493b8d71a08..d0db99f78a1b 100644 --- a/aws/config.go +++ b/aws/config.go @@ -14,6 +14,7 @@ import ( "github.com/aws/aws-sdk-go/service/amplify" "github.com/aws/aws-sdk-go/service/apigateway" "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/aws/aws-sdk-go/service/appconfig" "github.com/aws/aws-sdk-go/service/applicationautoscaling" "github.com/aws/aws-sdk-go/service/applicationinsights" "github.com/aws/aws-sdk-go/service/appmesh" @@ -214,6 +215,7 @@ type AWSClient struct { apigatewayconn *apigateway.APIGateway apigatewayv2conn *apigatewayv2.ApiGatewayV2 appautoscalingconn *applicationautoscaling.ApplicationAutoScaling + appconfigconn *appconfig.AppConfig applicationinsightsconn *applicationinsights.ApplicationInsights appmeshconn *appmesh.AppMesh appstreamconn *appstream.AppStream @@ -457,6 +459,7 @@ func (c *Config) Client() (interface{}, error) { apigatewayconn: apigateway.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["apigateway"])})), apigatewayv2conn: apigatewayv2.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["apigateway"])})), appautoscalingconn: applicationautoscaling.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["applicationautoscaling"])})), + appconfigconn: appconfig.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["appconfig"])})), applicationinsightsconn: applicationinsights.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["applicationinsights"])})), appmeshconn: appmesh.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["appmesh"])})), appstreamconn: appstream.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["appstream"])})), diff --git a/aws/internal/keyvaluetags/generators/listtags/main.go b/aws/internal/keyvaluetags/generators/listtags/main.go index 4ffe44d98ec5..5c50c7e6d1ba 100644 --- a/aws/internal/keyvaluetags/generators/listtags/main.go +++ b/aws/internal/keyvaluetags/generators/listtags/main.go @@ -22,6 +22,7 @@ var serviceNames = []string{ "acmpca", "amplify", "apigatewayv2", + "appconfig", "appmesh", "appstream", "appsync", diff --git a/aws/internal/keyvaluetags/generators/servicetags/main.go b/aws/internal/keyvaluetags/generators/servicetags/main.go index 057627155924..24354c0660c1 100644 --- a/aws/internal/keyvaluetags/generators/servicetags/main.go +++ b/aws/internal/keyvaluetags/generators/servicetags/main.go @@ -20,6 +20,7 @@ const filename = `service_tags_gen.go` var sliceServiceNames = []string{ "acm", "acmpca", + "appconfig", "appmesh", "athena", "autoscaling", diff --git a/aws/internal/keyvaluetags/generators/updatetags/main.go b/aws/internal/keyvaluetags/generators/updatetags/main.go index 5d9b9cf73eb4..f2ce5f14b6ba 100644 --- a/aws/internal/keyvaluetags/generators/updatetags/main.go +++ b/aws/internal/keyvaluetags/generators/updatetags/main.go @@ -23,6 +23,7 @@ var serviceNames = []string{ "amplify", "apigateway", "apigatewayv2", + "appconfig", "appmesh", "appstream", "appsync", diff --git a/aws/internal/keyvaluetags/service_generation_customizations.go b/aws/internal/keyvaluetags/service_generation_customizations.go index ba3797f086a1..903f94c506f7 100644 --- a/aws/internal/keyvaluetags/service_generation_customizations.go +++ b/aws/internal/keyvaluetags/service_generation_customizations.go @@ -12,6 +12,7 @@ import ( "github.com/aws/aws-sdk-go/service/amplify" "github.com/aws/aws-sdk-go/service/apigateway" "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/aws/aws-sdk-go/service/appconfig" "github.com/aws/aws-sdk-go/service/appmesh" "github.com/aws/aws-sdk-go/service/appstream" "github.com/aws/aws-sdk-go/service/appsync" @@ -141,6 +142,8 @@ func ServiceClientType(serviceName string) string { funcType = reflect.TypeOf(apigateway.New) case "apigatewayv2": funcType = reflect.TypeOf(apigatewayv2.New) + case "appconfig": + funcType = reflect.TypeOf(appconfig.New) case "appmesh": funcType = reflect.TypeOf(appmesh.New) case "appstream": From 88142803f204c3377ceee55ba968aed0afacb2a1 Mon Sep 17 00:00:00 2001 From: Isaiah-Turner <42742035+Isaiah-Turner@users.noreply.github.com> Date: Wed, 10 Mar 2021 15:22:29 -0500 Subject: [PATCH 0003/1208] Generated all tags --- .../generators/servicetags/main.go | 2 +- aws/internal/keyvaluetags/list_tags_gen.go | 18 +++++++++ aws/internal/keyvaluetags/service_tags_gen.go | 10 +++++ aws/internal/keyvaluetags/update_tags_gen.go | 37 +++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/aws/internal/keyvaluetags/generators/servicetags/main.go b/aws/internal/keyvaluetags/generators/servicetags/main.go index 24354c0660c1..918b01622f2f 100644 --- a/aws/internal/keyvaluetags/generators/servicetags/main.go +++ b/aws/internal/keyvaluetags/generators/servicetags/main.go @@ -20,7 +20,6 @@ const filename = `service_tags_gen.go` var sliceServiceNames = []string{ "acm", "acmpca", - "appconfig", "appmesh", "athena", "autoscaling", @@ -110,6 +109,7 @@ var mapServiceNames = []string{ "amplify", "apigateway", "apigatewayv2", + "appconfig", "appstream", "appsync", "backup", diff --git a/aws/internal/keyvaluetags/list_tags_gen.go b/aws/internal/keyvaluetags/list_tags_gen.go index 5cbec75b054b..0fb0e72e04bc 100644 --- a/aws/internal/keyvaluetags/list_tags_gen.go +++ b/aws/internal/keyvaluetags/list_tags_gen.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/service/acmpca" "github.com/aws/aws-sdk-go/service/amplify" "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/aws/aws-sdk-go/service/appconfig" "github.com/aws/aws-sdk-go/service/appmesh" "github.com/aws/aws-sdk-go/service/appstream" "github.com/aws/aws-sdk-go/service/appsync" @@ -196,6 +197,23 @@ func Apigatewayv2ListTags(conn *apigatewayv2.ApiGatewayV2, identifier string) (K return Apigatewayv2KeyValueTags(output.Tags), nil } +// AppconfigListTags lists appconfig service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AppconfigListTags(conn *appconfig.AppConfig, identifier string) (KeyValueTags, error) { + input := &appconfig.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return AppconfigKeyValueTags(output.Tags), nil +} + // AppmeshListTags lists appmesh service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. diff --git a/aws/internal/keyvaluetags/service_tags_gen.go b/aws/internal/keyvaluetags/service_tags_gen.go index 8e1d2f68f6d1..c2bb82cf9b00 100644 --- a/aws/internal/keyvaluetags/service_tags_gen.go +++ b/aws/internal/keyvaluetags/service_tags_gen.go @@ -134,6 +134,16 @@ func Apigatewayv2KeyValueTags(tags map[string]*string) KeyValueTags { return New(tags) } +// AppconfigTags returns appconfig service tags. +func (tags KeyValueTags) AppconfigTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// AppconfigKeyValueTags creates KeyValueTags from appconfig service tags. +func AppconfigKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + // AppstreamTags returns appstream service tags. func (tags KeyValueTags) AppstreamTags() map[string]*string { return aws.StringMap(tags.Map()) diff --git a/aws/internal/keyvaluetags/update_tags_gen.go b/aws/internal/keyvaluetags/update_tags_gen.go index 62ee4ea9faef..48395f0c7a4a 100644 --- a/aws/internal/keyvaluetags/update_tags_gen.go +++ b/aws/internal/keyvaluetags/update_tags_gen.go @@ -12,6 +12,7 @@ import ( "github.com/aws/aws-sdk-go/service/amplify" "github.com/aws/aws-sdk-go/service/apigateway" "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/aws/aws-sdk-go/service/appconfig" "github.com/aws/aws-sdk-go/service/appmesh" "github.com/aws/aws-sdk-go/service/appstream" "github.com/aws/aws-sdk-go/service/appsync" @@ -336,6 +337,42 @@ func Apigatewayv2UpdateTags(conn *apigatewayv2.ApiGatewayV2, identifier string, return nil } +// AppconfigUpdateTags updates appconfig service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AppconfigUpdateTags(conn *appconfig.AppConfig, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &appconfig.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.IgnoreAws().Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %w", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &appconfig.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().AppconfigTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %w", identifier, err) + } + } + + return nil +} + // AppmeshUpdateTags updates appmesh service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. From d7bd4eb4e261eb1ae0a592c34f16a663aae0c1e5 Mon Sep 17 00:00:00 2001 From: Isaiah-Turner <42742035+Isaiah-Turner@users.noreply.github.com> Date: Wed, 10 Mar 2021 15:16:06 -0500 Subject: [PATCH 0004/1208] Added AppConfig Application Resource --- aws/provider.go | 2 + aws/resource_aws_appconfig_application.go | 177 ++++++++++++++ ...resource_aws_appconfig_application_test.go | 223 ++++++++++++++++++ 3 files changed, 402 insertions(+) create mode 100644 aws/resource_aws_appconfig_application.go create mode 100644 aws/resource_aws_appconfig_application_test.go diff --git a/aws/provider.go b/aws/provider.go index 5de81c4636cd..7d7c14c9309b 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -456,6 +456,7 @@ func Provider() *schema.Provider { "aws_appautoscaling_target": resourceAwsAppautoscalingTarget(), "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), "aws_appautoscaling_scheduled_action": resourceAwsAppautoscalingScheduledAction(), + "aws_appconfig_application": resourceAwsAppconfigApplication(), "aws_appmesh_gateway_route": resourceAwsAppmeshGatewayRoute(), "aws_appmesh_mesh": resourceAwsAppmeshMesh(), "aws_appmesh_route": resourceAwsAppmeshRoute(), @@ -1180,6 +1181,7 @@ func init() { "acmpca", "amplify", "apigateway", + "appconfig", "applicationautoscaling", "applicationinsights", "appmesh", diff --git a/aws/resource_aws_appconfig_application.go b/aws/resource_aws_appconfig_application.go new file mode 100644 index 000000000000..743b609df61b --- /dev/null +++ b/aws/resource_aws_appconfig_application.go @@ -0,0 +1,177 @@ +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 resourceAwsAppconfigApplication() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAppconfigApplicationCreate, + Read: resourceAwsAppconfigApplicationRead, + Update: resourceAwsAppconfigApplicationUpdate, + Delete: resourceAwsAppconfigApplicationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 64), + ), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 1024), + ), + }, + "tags": tagsSchema(), + "id": { + Type: schema.TypeString, + Computed: true, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsAppconfigApplicationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + applicationName := d.Get("name").(string) + applicationDescription := d.Get("description").(string) + + input := &appconfig.CreateApplicationInput{ + Name: aws.String(applicationName), + Description: aws.String(applicationDescription), + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), + } + + app, err := conn.CreateApplication(input) + if err != nil { + return fmt.Errorf("Error creating AppConfig application: %s", err) + } + + d.SetId(aws.StringValue(app.Id)) + + return resourceAwsAppconfigApplicationRead(d, meta) +} + +func resourceAwsAppconfigApplicationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + input := &appconfig.GetApplicationInput{ + ApplicationId: aws.String(d.Id()), + } + + output, err := conn.GetApplication(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Appconfig Application (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error getting AppConfig Application (%s): %s", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting AppConfig Application (%s): empty response", d.Id()) + } + + appARN := arn.ARN{ + AccountID: meta.(*AWSClient).accountid, + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("application/%s", aws.StringValue(output.Id)), + Service: "appconfig", + }.String() + + d.Set("arn", appARN) + d.Set("name", output.Name) + d.Set("description", output.Description) + + tags, err := keyvaluetags.AppconfigListTags(conn, appARN) + if err != nil { + return fmt.Errorf("error getting tags for AppConfig Application (%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 resourceAwsAppconfigApplicationUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + 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) + } + } + + appDesc := d.Get("description").(string) + appName := d.Get("name").(string) + + updateInput := &appconfig.UpdateApplicationInput{ + ApplicationId: aws.String(d.Id()), + Description: aws.String(appDesc), + Name: aws.String(appName), + } + + if d.HasChange("description") { + _, n := d.GetChange("description") + updateInput.Description = aws.String(n.(string)) + } + + if d.HasChange("name") { + _, n := d.GetChange("name") + updateInput.Name = aws.String(n.(string)) + } + + _, err := conn.UpdateApplication(updateInput) + if err != nil { + return fmt.Errorf("error updating AppConfig Application(%s): %s", d.Id(), err) + } + + return resourceAwsAppconfigApplicationRead(d, meta) +} + +func resourceAwsAppconfigApplicationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + input := &appconfig.DeleteApplicationInput{ + ApplicationId: aws.String(d.Id()), + } + + _, err := conn.DeleteApplication(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Appconfig Application (%s): %s", d.Id(), err) + } + + return nil +} diff --git a/aws/resource_aws_appconfig_application_test.go b/aws/resource_aws_appconfig_application_test.go new file mode 100644 index 000000000000..a405fdd57ee6 --- /dev/null +++ b/aws/resource_aws_appconfig_application_test.go @@ -0,0 +1,223 @@ +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 TestAccAWSAppConfigApplication_basic(t *testing.T) { + var application appconfig.GetApplicationOutput + rName := acctest.RandomWithPrefix("tf-acc-test") + rDesc := acctest.RandomWithPrefix("desc") + resourceName := "aws_appconfig_application.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigApplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigApplicationName(rName, rDesc), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigApplicationExists(resourceName, &application), + resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckAWSAppConfigApplicationARN(resourceName, &application), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "description", rDesc), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigApplication_disappears(t *testing.T) { + var application appconfig.GetApplicationOutput + + rName := acctest.RandomWithPrefix("tf-acc-test") + rDesc := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appconfig_application.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigApplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigApplicationName(rName, rDesc), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigApplicationExists(resourceName, &application), + testAccCheckAWSAppConfigApplicationDisappears(&application), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSAppConfigApplication_Tags(t *testing.T) { + var application appconfig.GetApplicationOutput + + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appconfig_application.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigApplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigApplicationTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigApplicationExists(resourceName, &application), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigApplicationTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigApplicationExists(resourceName, &application), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSAppConfigApplicationTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigApplicationExists(resourceName, &application), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func testAccCheckAppConfigApplicationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_appconfig_application" { + continue + } + + input := &appconfig.GetApplicationInput{ + ApplicationId: aws.String(rs.Primary.ID), + } + + output, err := conn.GetApplication(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + continue + } + + if err != nil { + return err + } + + if output != nil { + return fmt.Errorf("AppConfig Application (%s) still exists", rs.Primary.ID) + } + } + + return nil + +} + +func testAccCheckAWSAppConfigApplicationDisappears(application *appconfig.GetApplicationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + input := &appconfig.DeleteApplicationInput{ + ApplicationId: aws.String(*application.Id), + } + + _, err := conn.DeleteApplication(input) + + return err + } +} + +func testAccCheckAWSAppConfigApplicationExists(resourceName string, application *appconfig.GetApplicationOutput) 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 + + input := &appconfig.GetApplicationInput{ + ApplicationId: aws.String(rs.Primary.ID), + } + + output, err := conn.GetApplication(input) + if err != nil { + return err + } + + *application = *output + + return nil + } +} + +func testAccCheckAWSAppConfigApplicationARN(resourceName string, application *appconfig.GetApplicationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + return testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appconfig", fmt.Sprintf("application/%s", aws.StringValue(application.Id)))(s) + } +} + +func testAccAWSAppConfigApplicationName(rName, rDesc string) string { + return fmt.Sprintf(` +resource "aws_appconfig_application" "test" { + name = %[1]q + description = %[2]q +} +`, rName, rDesc) +} + +func testAccAWSAppConfigApplicationTags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_appconfig_application" "test" { + name = %[1]q + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccAWSAppConfigApplicationTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_appconfig_application" "test" { + name = %[1]q + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} From b434d7aa84c9717f008a072e0edb27386dea8957 Mon Sep 17 00:00:00 2001 From: Isaiah-Turner <42742035+Isaiah-Turner@users.noreply.github.com> Date: Wed, 10 Mar 2021 15:16:18 -0500 Subject: [PATCH 0005/1208] Added web documentation --- .../r/appconfig_application.html.markdown | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 website/docs/r/appconfig_application.html.markdown diff --git a/website/docs/r/appconfig_application.html.markdown b/website/docs/r/appconfig_application.html.markdown new file mode 100644 index 000000000000..d2850e984c92 --- /dev/null +++ b/website/docs/r/appconfig_application.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "AppConfig" +layout: "aws" +page_title: "AWS: aws_appconfig_application" +description: |- + Provides an AppConfig Application resource. +--- + +# Resource: aws_appconfig_application + +Provides an AppConfig Application resource. + +## Example Usage + +### AppConfig Application + +```hcl +resource "aws_appconfig_application" "test" { + name = "test-application-tf" + description = "Test AppConfig Application" + tags = { + Type = "AppConfig Application" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +- `name` - (Required) The name to use for the application. Must be between 1 and 64 characters in length. +- `description` - (Optional) The description of the application. Can be at most 1024 characters. +- `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 Application. +- `id` - The AppConfig Application ID + +## Import + +Applications can be imported using their ID, e.g. + +``` +$ terraform import aws_appconfig_application.bar 71rxuzt +``` From bdf3a4bb3b99d8ecf8fdc9cddb1a570bafe50220 Mon Sep 17 00:00:00 2001 From: Isaiah-Turner <42742035+Isaiah-Turner@users.noreply.github.com> Date: Wed, 10 Mar 2021 16:04:56 -0500 Subject: [PATCH 0006/1208] Added changelog entry --- .changelog/18032.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/18032.txt diff --git a/.changelog/18032.txt b/.changelog/18032.txt new file mode 100644 index 000000000000..bfbca0898be6 --- /dev/null +++ b/.changelog/18032.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_appconfig_application +``` \ No newline at end of file From bc89ad3e1bb65b6e4de4ef0c636b117712901629 Mon Sep 17 00:00:00 2001 From: Isaiah-Turner <42742035+Isaiah-Turner@users.noreply.github.com> Date: Wed, 10 Mar 2021 16:12:10 -0500 Subject: [PATCH 0007/1208] Fixed terraform formatting --- aws/resource_aws_appconfig_application_test.go | 4 ++-- website/docs/r/appconfig_application.html.markdown | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_appconfig_application_test.go b/aws/resource_aws_appconfig_application_test.go index a405fdd57ee6..e5702d0f1126 100644 --- a/aws/resource_aws_appconfig_application_test.go +++ b/aws/resource_aws_appconfig_application_test.go @@ -191,8 +191,8 @@ func testAccCheckAWSAppConfigApplicationARN(resourceName string, application *ap func testAccAWSAppConfigApplicationName(rName, rDesc string) string { return fmt.Sprintf(` resource "aws_appconfig_application" "test" { - name = %[1]q - description = %[2]q + name = %[1]q + description = %[2]q } `, rName, rDesc) } diff --git a/website/docs/r/appconfig_application.html.markdown b/website/docs/r/appconfig_application.html.markdown index d2850e984c92..c90809be06ae 100644 --- a/website/docs/r/appconfig_application.html.markdown +++ b/website/docs/r/appconfig_application.html.markdown @@ -16,7 +16,7 @@ Provides an AppConfig Application resource. ```hcl resource "aws_appconfig_application" "test" { - name = "test-application-tf" + name = "test-application-tf" description = "Test AppConfig Application" tags = { Type = "AppConfig Application" From be0d7b488808ffbdb8489f06d24ddf47ca258c2b Mon Sep 17 00:00:00 2001 From: Isaiah-Turner <42742035+Isaiah-Turner@users.noreply.github.com> Date: Wed, 10 Mar 2021 18:42:35 -0500 Subject: [PATCH 0008/1208] Fixed spacing in acceptance test --- aws/resource_aws_appconfig_application_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_appconfig_application_test.go b/aws/resource_aws_appconfig_application_test.go index e5702d0f1126..1721363742a1 100644 --- a/aws/resource_aws_appconfig_application_test.go +++ b/aws/resource_aws_appconfig_application_test.go @@ -191,8 +191,8 @@ func testAccCheckAWSAppConfigApplicationARN(resourceName string, application *ap func testAccAWSAppConfigApplicationName(rName, rDesc string) string { return fmt.Sprintf(` resource "aws_appconfig_application" "test" { - name = %[1]q - description = %[2]q + name = %[1]q + description = %[2]q } `, rName, rDesc) } From e873f355596b09b88d71ef588300aa9247beae7f Mon Sep 17 00:00:00 2001 From: Sunil Kumar Mohanty Date: Mon, 15 Mar 2021 20:49:26 +0200 Subject: [PATCH 0009/1208] initial commit for adding support for app cookie stickiness --- aws/data_source_aws_lb_target_group.go | 16 ++++++ aws/resource_aws_lb_target_group.go | 71 +++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/aws/data_source_aws_lb_target_group.go b/aws/data_source_aws_lb_target_group.go index 0b2b94a3211d..54b124cc2058 100644 --- a/aws/data_source_aws_lb_target_group.go +++ b/aws/data_source_aws_lb_target_group.go @@ -92,6 +92,22 @@ func dataSourceAwsLbTargetGroup() *schema.Resource { Type: schema.TypeInt, Computed: true, }, + "app_cookie": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cookie_name": { + Type: schema.TypeString, + Computed: true, + }, + "duration_seconds": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, }, }, }, diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index 2103b85b3a00..7a132835e31c 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -142,8 +142,9 @@ func resourceAwsLbTargetGroup() *schema.Resource { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - "lb_cookie", // Only for ALBs - "source_ip", // Only for NLBs + "lb_cookie", // Only for ALBs + "app_cookie", // Only for ALBs + "source_ip", // Only for NLBs }, false), DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { switch d.Get("protocol").(string) { @@ -169,6 +170,33 @@ func resourceAwsLbTargetGroup() *schema.Resource { return false }, }, + "app_cookie": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + switch d.Get("protocol").(string) { + case elbv2.ProtocolEnumTcp, elbv2.ProtocolEnumUdp, elbv2.ProtocolEnumTcpUdp, elbv2.ProtocolEnumTls: + return true + } + return false + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cookie_name": { + Type: schema.TypeString, + Required: true, + }, + "duration_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: 86400, + ValidateFunc: validation.IntBetween(0, 604800), + }, + }, + }, + }, }, }, }, @@ -450,7 +478,7 @@ func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) er if len(stickinessBlocks) == 1 { stickiness := stickinessBlocks[0].(map[string]interface{}) - if !stickiness["enabled"].(bool) && stickiness["type"].(string) == "lb_cookie" && d.Get("protocol").(string) != elbv2.ProtocolEnumHttp && d.Get("protocol").(string) != elbv2.ProtocolEnumHttps { + if !stickiness["enabled"].(bool) && (stickiness["type"].(string) == "lb_cookie" || stickiness["type"].(string) == "app_cookie") && d.Get("protocol").(string) != elbv2.ProtocolEnumHttp && d.Get("protocol").(string) != elbv2.ProtocolEnumHttps { log.Printf("[WARN] invalid configuration, this will fail in a future version: stickiness enabled %v, protocol %s, type %s", stickiness["enabled"].(bool), d.Get("protocol").(string), stickiness["type"].(string)) } else { attrs = append(attrs, @@ -465,11 +493,25 @@ func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) er switch d.Get("protocol").(string) { case elbv2.ProtocolEnumHttp, elbv2.ProtocolEnumHttps: - attrs = append(attrs, - &elbv2.TargetGroupAttribute{ - Key: aws.String("stickiness.lb_cookie.duration_seconds"), - Value: aws.String(fmt.Sprintf("%d", stickiness["cookie_duration"].(int))), - }) + if stickiness["type"].(string) == "lb_cookie" { + attrs = append(attrs, + &elbv2.TargetGroupAttribute{ + Key: aws.String("stickiness.lb_cookie.duration_seconds"), + Value: aws.String(fmt.Sprintf("%d", stickiness["cookie_duration"].(int))), + }) + } else { + appCookie := stickiness["app_cookie"].(map[string]interface{}) + attrs = append(attrs, + &elbv2.TargetGroupAttribute{ + Key: aws.String("stickiness.app_cookie.duration_seconds"), + Value: aws.String(fmt.Sprintf("%d", appCookie["duration_seconds"].(int))), + }, + &elbv2.TargetGroupAttribute{ + Key: aws.String("stickiness.app_cookie.cookie_name"), + Value: aws.String(appCookie["cookie_name"].(string)), + }) + } + } } } else if len(stickinessBlocks) == 0 { @@ -689,6 +731,7 @@ func flattenAwsLbTargetGroupResource(d *schema.ResourceData, meta interface{}, t func flattenAwsLbTargetGroupStickiness(d *schema.ResourceData, attributes []*elbv2.TargetGroupAttribute) error { stickinessMap := map[string]interface{}{} + appStickinessMap := map[string]interface{}{} for _, attr := range attributes { switch aws.StringValue(attr.Key) { case "stickiness.enabled": @@ -711,13 +754,25 @@ func flattenAwsLbTargetGroupStickiness(d *schema.ResourceData, attributes []*elb return fmt.Errorf("Error converting deregistration_delay.timeout_seconds to int: %s", aws.StringValue(attr.Value)) } d.Set("deregistration_delay", timeout) + case "stickiness.app_cookie.cookie_name": + appStickinessMap["cookie_name"] = aws.StringValue(attr.Value) + case "stickiness.app_cookie.duration_seconds": + duration, err := strconv.Atoi(aws.StringValue(attr.Value)) + if err != nil { + return fmt.Errorf("Error converting stickiness.app_cookie.duration_seconds to int: %s", aws.StringValue(attr.Value)) + } + appStickinessMap["duration_seconds"] = duration } } + if len(appStickinessMap) > 0 { + stickinessMap["app_cookie"] = appStickinessMap + } setStickyMap := []interface{}{} if len(stickinessMap) > 0 { setStickyMap = []interface{}{stickinessMap} } + if err := d.Set("stickiness", setStickyMap); err != nil { return err } From d6a6da58c1f8af861f74647af800e9c35d75fa7b Mon Sep 17 00:00:00 2001 From: Sunil Kumar Mohanty Date: Sun, 21 Mar 2021 23:13:46 +0200 Subject: [PATCH 0010/1208] add tests and minor fixes --- aws/resource_aws_lb_target_group.go | 25 ++-- aws/resource_aws_lb_target_group_test.go | 139 +++++++++++++++++++++++ 2 files changed, 153 insertions(+), 11 deletions(-) diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index 7a132835e31c..3f37a09dbbbd 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -500,16 +500,19 @@ func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) er Value: aws.String(fmt.Sprintf("%d", stickiness["cookie_duration"].(int))), }) } else { - appCookie := stickiness["app_cookie"].(map[string]interface{}) - attrs = append(attrs, - &elbv2.TargetGroupAttribute{ - Key: aws.String("stickiness.app_cookie.duration_seconds"), - Value: aws.String(fmt.Sprintf("%d", appCookie["duration_seconds"].(int))), - }, - &elbv2.TargetGroupAttribute{ - Key: aws.String("stickiness.app_cookie.cookie_name"), - Value: aws.String(appCookie["cookie_name"].(string)), - }) + appCookieBlocks := stickiness["app_cookie"].([]interface{}) + if len(appCookieBlocks) == 1 { + appStickiness := appCookieBlocks[0].(map[string]interface{}) + attrs = append(attrs, + &elbv2.TargetGroupAttribute{ + Key: aws.String("stickiness.app_cookie.duration_seconds"), + Value: aws.String(fmt.Sprintf("%d", appStickiness["duration_seconds"].(int))), + }, + &elbv2.TargetGroupAttribute{ + Key: aws.String("stickiness.app_cookie.cookie_name"), + Value: aws.String(appStickiness["cookie_name"].(string)), + }) + } } } @@ -765,7 +768,7 @@ func flattenAwsLbTargetGroupStickiness(d *schema.ResourceData, attributes []*elb } } if len(appStickinessMap) > 0 { - stickinessMap["app_cookie"] = appStickinessMap + stickinessMap["app_cookie"] = []interface{}{appStickinessMap} } setStickyMap := []interface{}{} diff --git a/aws/resource_aws_lb_target_group_test.go b/aws/resource_aws_lb_target_group_test.go index 34e4f3dfc616..5ae96d9de84e 100644 --- a/aws/resource_aws_lb_target_group_test.go +++ b/aws/resource_aws_lb_target_group_test.go @@ -887,6 +887,96 @@ func TestAccAWSLBTargetGroup_updateSticknessEnabled(t *testing.T) { }) } +func TestAccAWSLBTargetGroup_updateAppSticknessEnabled(t *testing.T) { + var conf elbv2.TargetGroup + targetGroupName := fmt.Sprintf("test-target-group-%s", acctest.RandString(10)) + resourceName := "aws_lb_target_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBTargetGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBTargetGroupConfig_appStickiness(targetGroupName, false, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBTargetGroupExists(resourceName, &conf), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "name", targetGroupName), + resource.TestCheckResourceAttr(resourceName, "port", "443"), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), + resource.TestCheckResourceAttrSet(resourceName, "vpc_id"), + resource.TestCheckResourceAttr(resourceName, "deregistration_delay", "200"), + resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.path", "/health2"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.interval", "30"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.port", "8082"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.timeout", "4"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.healthy_threshold", "4"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.unhealthy_threshold", "4"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.matcher", "200"), + ), + }, + { + Config: testAccAWSLBTargetGroupConfig_appStickiness(targetGroupName, true, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBTargetGroupExists(resourceName, &conf), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "name", targetGroupName), + resource.TestCheckResourceAttr(resourceName, "port", "443"), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), + resource.TestCheckResourceAttrSet(resourceName, "vpc_id"), + resource.TestCheckResourceAttr(resourceName, "deregistration_delay", "200"), + resource.TestCheckResourceAttr(resourceName, "stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.type", "app_cookie"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.0.cookie_name", "Cookie"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.0.duration_seconds", "10000"), + resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.path", "/health2"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.interval", "30"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.port", "8082"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.timeout", "4"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.healthy_threshold", "4"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.unhealthy_threshold", "4"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.matcher", "200"), + ), + }, + { + Config: testAccAWSLBTargetGroupConfig_appStickiness(targetGroupName, true, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBTargetGroupExists(resourceName, &conf), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "name", targetGroupName), + resource.TestCheckResourceAttr(resourceName, "port", "443"), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), + resource.TestCheckResourceAttrSet(resourceName, "vpc_id"), + resource.TestCheckResourceAttr(resourceName, "deregistration_delay", "200"), + resource.TestCheckResourceAttr(resourceName, "stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.type", "app_cookie"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.#", "1"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.0.cookie_name", "Cookie"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.0.duration_seconds", "10000"), + resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.path", "/health2"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.interval", "30"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.port", "8082"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.timeout", "4"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.healthy_threshold", "4"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.unhealthy_threshold", "4"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.matcher", "200"), + ), + }, + }, + }) +} + func TestAccAWSLBTargetGroup_defaults_application(t *testing.T) { var conf elbv2.TargetGroup targetGroupName := fmt.Sprintf("test-target-group-%s", acctest.RandString(10)) @@ -2113,6 +2203,55 @@ resource "aws_vpc" "test" { `, targetGroupName, stickinessBlock) } +func testAccAWSLBTargetGroupConfig_appStickiness(targetGroupName string, addAppStickinessBlock bool, enabled bool) string { + var appSstickinessBlock string + + if addAppStickinessBlock { + appSstickinessBlock = fmt.Sprintf(` +stickiness { + enabled = "%t" + type = "app_cookie" + app_cookie { + cookie_name = "Cookie" + duration_seconds = 10000 + } +} +`, enabled) + } + + return fmt.Sprintf(` +resource "aws_lb_target_group" "test" { + name = "%s" + port = 443 + protocol = "HTTPS" + vpc_id = aws_vpc.test.id + + deregistration_delay = 200 + + %s + + health_check { + path = "/health2" + interval = 30 + port = 8082 + protocol = "HTTPS" + timeout = 4 + healthy_threshold = 4 + unhealthy_threshold = 4 + matcher = "200" + } +} + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = "terraform-testacc-lb-target-group-stickiness" + } +} +`, targetGroupName, appSstickinessBlock) +} + const testAccAWSLBTargetGroupConfig_namePrefix = ` resource "aws_lb_target_group" "test" { name_prefix = "tf-" From 41f781b3c58c80ba44b3a8663d0db43a22a8cfb7 Mon Sep 17 00:00:00 2001 From: Sunil Kumar Mohanty Date: Sun, 21 Mar 2021 23:50:07 +0200 Subject: [PATCH 0011/1208] add documentation --- website/docs/r/lb_target_group.html.markdown | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/website/docs/r/lb_target_group.html.markdown b/website/docs/r/lb_target_group.html.markdown index e41d4f980c98..e85da44d881d 100644 --- a/website/docs/r/lb_target_group.html.markdown +++ b/website/docs/r/lb_target_group.html.markdown @@ -81,9 +81,15 @@ You can't specify publicly routable IP addresses. Stickiness Blocks (`stickiness`) support the following: -* `type` - (Required) The type of sticky sessions. The only current possible values are `lb_cookie` for ALBs and `source_ip` for NLBs. +* `type` - (Required) The type of sticky sessions. The only current possible values are `lb_cookie` and `app_cookie` for ALBs and `source_ip` for NLBs. * `cookie_duration` - (Optional) Only used when the type is `lb_cookie`. The time period, in seconds, during which requests from a client should be routed to the same target. After this time period expires, the load balancer-generated cookie is considered stale. The range is 1 second to 1 week (604800 seconds). The default value is 1 day (86400 seconds). -* `enabled` - (Optional) Boolean to enable / disable `stickiness`. Default is `true` +* `enabled` - (Optional) Boolean to enable / disable `stickiness`. Default is `true`. +* `app_cookie` - (Option) An Application Cookie block. Application Cookie blocks are documented below. + +Application Cookie Blocks (`app_coookie`) support the following: + +* `cookie_name` - (Required). Name of the application based cookie. Name of the cookie should not start with the following names: AWSALB, AWSALBAPP, and AWSALBTG. They're reserved for use by the load balancer. +* `duration_seconds` - (Optional). The time period, in seconds, during which requests from a client should be routed to the same target. The range is 1 second to 1 week (604800 seconds). The default value is 1 day (86400 seconds). ~> **NOTE:** Currently, an NLB (i.e., protocol of `HTTP` or `HTTPS`) can have an invalid `stickiness` block with `type` set to `lb_cookie` as long as `enabled` is set to `false`. However, please update your configurations to avoid errors in a future version of the provider: either remove the invalid `stickiness` block or set the `type` to `source_ip`. From 4d523d6688cb6d1a829fe82575ba309fb07bec88 Mon Sep 17 00:00:00 2001 From: Sunil Kumar Mohanty Date: Mon, 22 Mar 2021 23:03:12 +0200 Subject: [PATCH 0012/1208] add ErrorCheck --- aws/resource_aws_lb_target_group_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_lb_target_group_test.go b/aws/resource_aws_lb_target_group_test.go index 5ae96d9de84e..7b634d2fa749 100644 --- a/aws/resource_aws_lb_target_group_test.go +++ b/aws/resource_aws_lb_target_group_test.go @@ -897,6 +897,7 @@ func TestAccAWSLBTargetGroup_updateAppSticknessEnabled(t *testing.T) { IDRefreshName: resourceName, Providers: testAccProviders, CheckDestroy: testAccCheckAWSLBTargetGroupDestroy, + ErrorCheck: testAccErrorCheck(t, elbv2.EndpointsID), Steps: []resource.TestStep{ { Config: testAccAWSLBTargetGroupConfig_appStickiness(targetGroupName, false, false), From 338bc25a5b04469c6e4d10fb04352cd1c9f3d59e Mon Sep 17 00:00:00 2001 From: Sunil Kumar Mohanty Date: Mon, 22 Mar 2021 23:15:35 +0200 Subject: [PATCH 0013/1208] minor fixes --- aws/resource_aws_lb_target_group_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_lb_target_group_test.go b/aws/resource_aws_lb_target_group_test.go index 03be72a4a3c0..f05ff7165ded 100644 --- a/aws/resource_aws_lb_target_group_test.go +++ b/aws/resource_aws_lb_target_group_test.go @@ -1017,10 +1017,10 @@ func TestAccAWSLBTargetGroup_updateAppSticknessEnabled(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, elbv2.EndpointsID), IDRefreshName: resourceName, Providers: testAccProviders, CheckDestroy: testAccCheckAWSLBTargetGroupDestroy, - ErrorCheck: testAccErrorCheck(t, elbv2.EndpointsID), Steps: []resource.TestStep{ { Config: testAccAWSLBTargetGroupConfig_appStickiness(targetGroupName, false, false), From 82ff95dfb859da0eb5a502ad393e12645efeab0d Mon Sep 17 00:00:00 2001 From: grahamhar Date: Sun, 14 Feb 2021 11:11:46 +0000 Subject: [PATCH 0014/1208] Fix change detection relating to vpc_config As reported in https://github.com/hashicorp/terraform-provider-aws/issues/17385 a change i detected in vpc_config when there are no changes, this is caused by an issue in https://github.com/hashicorp/terraform-plugin-sdk/issues/617 The PR to provide a fix is not getting any traction. On further debuging the issue is caused by the nested elements being of type set which needs the use of Equal rather than reflect.DeepEqual to test for differences. We can work around this bug by testing for changes in the two fields within vpc_config independantly as when the item passed to HasChanges is a Set it is tested correctly. --- aws/resource_aws_lambda_function.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index 4872f036966b..32f716f41c9a 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -364,7 +364,8 @@ func hasConfigChanges(d resourceDiffer) bool { d.HasChange("layers") || d.HasChange("dead_letter_config") || d.HasChange("tracing_config") || - d.HasChange("vpc_config") || + d.HasChange("vpc_config.0.security_group_ids") || + d.HasChange("vpc_config.0.subnet_ids") || d.HasChange("runtime") || d.HasChange("environment") } From ee8fb4523f5e658a8906e5b1cb11f581362841b2 Mon Sep 17 00:00:00 2001 From: grahamhar Date: Mon, 15 Feb 2021 07:02:20 +0000 Subject: [PATCH 0015/1208] Add acceptance tests --- aws/resource_aws_lambda_function.go | 2 +- aws/resource_aws_lambda_function_test.go | 117 +++++++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index 32f716f41c9a..0971177621fe 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -998,7 +998,7 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e } } } - if d.HasChange("vpc_config") { + if d.HasChanges("vpc_config.0.security_group_ids", "vpc_config.0.subnet_ids") { configReq.VpcConfig = &lambda.VpcConfig{ SecurityGroupIds: []*string{}, SubnetIds: []*string{}, diff --git a/aws/resource_aws_lambda_function_test.go b/aws/resource_aws_lambda_function_test.go index 9d4b0e4462dd..ef0d4c5c7111 100644 --- a/aws/resource_aws_lambda_function_test.go +++ b/aws/resource_aws_lambda_function_test.go @@ -1309,6 +1309,89 @@ func TestAccAWSLambdaFunction_VPC_withInvocation(t *testing.T) { }) } +// See https://github.com/hashicorp/terraform-provider-aws/issues/17385 +// When the vpc config doesn't change the version shouldn't change +func TestAccAWSLambdaFunction_VPC_publish_No_Changes(t *testing.T) { + var conf lambda.GetFunctionOutput + + rString := acctest.RandString(8) + funcName := fmt.Sprintf("tf_acc_lambda_func_vpc_w_invc_%s", rString) + policyName := fmt.Sprintf("tf_acc_policy_lambda_func_vpc_w_invc_%s", rString) + roleName := fmt.Sprintf("tf_acc_role_lambda_func_vpc_w_invc_%s", rString) + sgName := fmt.Sprintf("tf_acc_sg_lambda_func_vpc_w_invc_%s", rString) + resourceName := "aws_lambda_function.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckLambdaFunctionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLambdaConfigWithVPCPublish(funcName, policyName, roleName, sgName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), + resource.TestCheckResourceAttr(resourceName, "version", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"filename", "publish"}, + }, + { + Config: testAccAWSLambdaConfigWithVPCPublish(funcName, policyName, roleName, sgName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), + resource.TestCheckResourceAttr(resourceName, "version", "1"), + ), + }, + }, + }) +} + +// See https://github.com/hashicorp/terraform-provider-aws/issues/17385 +// When the vpc config changes the version should change +func TestAccAWSLambdaFunction_VPC_publish_Has_Changes(t *testing.T) { + var conf lambda.GetFunctionOutput + + rString := acctest.RandString(8) + funcName := fmt.Sprintf("tf_acc_lambda_func_vpc_w_invc_%s", rString) + policyName := fmt.Sprintf("tf_acc_policy_lambda_func_vpc_w_invc_%s", rString) + roleName := fmt.Sprintf("tf_acc_role_lambda_func_vpc_w_invc_%s", rString) + sgName := fmt.Sprintf("tf_acc_sg_lambda_func_vpc_w_invc_%s", rString) + resourceName := "aws_lambda_function.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckLambdaFunctionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLambdaConfigWithVPCPublish(funcName, policyName, roleName, sgName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), + resource.TestCheckResourceAttr(resourceName, "version", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"filename", "publish"}, + }, + { + Config: testAccAWSLambdaConfigWithVPCUpdatedPublish(funcName, policyName, roleName, sgName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaFunctionExists(resourceName, funcName, &conf), + resource.TestCheckResourceAttr(resourceName, "version", "2"), + ), + }, + }, + }) +} + // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/10044 func TestAccAWSLambdaFunction_VpcConfig_ProperIamDependencies(t *testing.T) { var function lambda.GetFunctionOutput @@ -2865,6 +2948,40 @@ resource "aws_lambda_function" "test" { `, funcName) } +func testAccAWSLambdaConfigWithVPCPublish(funcName, policyName, roleName, sgName string) string { + return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+` +resource "aws_lambda_function" "test" { + filename = "test-fixtures/lambdatest.zip" + function_name = "%s" + role = aws_iam_role.iam_for_lambda.arn + handler = "exports.example" + runtime = "nodejs12.x" + publish = true + vpc_config { + subnet_ids = [aws_subnet.subnet_for_lambda.id] + security_group_ids = [aws_security_group.sg_for_lambda.id] + } +} +`, funcName) +} + +func testAccAWSLambdaConfigWithVPCUpdatedPublish(funcName, policyName, roleName, sgName string) string { + return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+` +resource "aws_lambda_function" "test" { + filename = "test-fixtures/lambdatest.zip" + function_name = "%s" + role = aws_iam_role.iam_for_lambda.arn + handler = "exports.example" + runtime = "nodejs12.x" + publish = true + vpc_config { + subnet_ids = [aws_subnet.subnet_for_lambda.id, aws_subnet.subnet_for_lambda_az2.id] + security_group_ids = [aws_security_group.sg_for_lambda.id] + } +} +`, funcName) +} + func testAccAWSLambdaConfigWithVPCUpdated(funcName, policyName, roleName, sgName, sgName2 string) string { return fmt.Sprintf(baseAccAWSLambdaConfig(policyName, roleName, sgName)+` resource "aws_lambda_function" "test" { From 622a2f4fa3789fa7834850722eb026a046bd499f Mon Sep 17 00:00:00 2001 From: grahamhar Date: Sat, 27 Mar 2021 14:23:50 +0000 Subject: [PATCH 0016/1208] Refactor test to work around ENI deletion issue Removing the VPC config is still a valid vpc config change and works around the ENI deltion issue. --- aws/resource_aws_lambda_function_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_lambda_function_test.go b/aws/resource_aws_lambda_function_test.go index ef0d4c5c7111..9d855479f0d9 100644 --- a/aws/resource_aws_lambda_function_test.go +++ b/aws/resource_aws_lambda_function_test.go @@ -1367,6 +1367,7 @@ func TestAccAWSLambdaFunction_VPC_publish_Has_Changes(t *testing.T) { ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckLambdaFunctionDestroy, + Steps: []resource.TestStep{ { Config: testAccAWSLambdaConfigWithVPCPublish(funcName, policyName, roleName, sgName), @@ -2975,8 +2976,8 @@ resource "aws_lambda_function" "test" { runtime = "nodejs12.x" publish = true vpc_config { - subnet_ids = [aws_subnet.subnet_for_lambda.id, aws_subnet.subnet_for_lambda_az2.id] - security_group_ids = [aws_security_group.sg_for_lambda.id] + security_group_ids = [] + subnet_ids = [] } } `, funcName) From 8fafcf6af35cad86369c09b59f14e71f7e054b2a Mon Sep 17 00:00:00 2001 From: Sunil Kumar Mohanty Date: Tue, 13 Apr 2021 12:59:38 +0300 Subject: [PATCH 0017/1208] formatting fixes --- aws/data_source_aws_lb_target_group.go | 33 -------------------- aws/resource_aws_lb_target_group.go | 13 -------- aws/resource_aws_lb_target_group_test.go | 1 - website/docs/r/lb_target_group.html.markdown | 1 + 4 files changed, 1 insertion(+), 47 deletions(-) diff --git a/aws/data_source_aws_lb_target_group.go b/aws/data_source_aws_lb_target_group.go index 4616a0ee9528..af5c95b6fdd5 100644 --- a/aws/data_source_aws_lb_target_group.go +++ b/aws/data_source_aws_lb_target_group.go @@ -26,39 +26,6 @@ func dataSourceAwsLbTargetGroup() *schema.Resource { Type: schema.TypeInt, Computed: true, }, - "health_check": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Computed: true, - }, - "healthy_threshold": { - Type: schema.TypeInt, - Computed: true, - }, - "app_cookie": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cookie_name": { - Type: schema.TypeString, - Computed: true, - }, - "duration_seconds": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - "health_check": { Type: schema.TypeList, Computed: true, diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index c3d5ef1a92ea..e07a965884aa 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -249,19 +249,6 @@ func resourceAwsLbTargetGroup() *schema.Resource { return false }, }, - "cookie_duration": { - Type: schema.TypeInt, - Optional: true, - Default: 86400, - ValidateFunc: validation.IntBetween(0, 604800), - DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - switch d.Get("protocol").(string) { - case elbv2.ProtocolEnumTcp, elbv2.ProtocolEnumUdp, elbv2.ProtocolEnumTcpUdp, elbv2.ProtocolEnumTls: - return true - } - return false - }, - }, "app_cookie": { Type: schema.TypeList, Optional: true, diff --git a/aws/resource_aws_lb_target_group_test.go b/aws/resource_aws_lb_target_group_test.go index 5cda4f112605..8a1edbc1c24b 100644 --- a/aws/resource_aws_lb_target_group_test.go +++ b/aws/resource_aws_lb_target_group_test.go @@ -2516,7 +2516,6 @@ resource "aws_vpc" "test" { `, targetGroupName, appSstickinessBlock) } - func testAccAWSLBTargetGroupConfig_namePrefix(rName string) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { diff --git a/website/docs/r/lb_target_group.html.markdown b/website/docs/r/lb_target_group.html.markdown index afd8bda2fda6..14da2d2d9c2c 100644 --- a/website/docs/r/lb_target_group.html.markdown +++ b/website/docs/r/lb_target_group.html.markdown @@ -103,6 +103,7 @@ Application Cookie Blocks (`app_coookie`) support the following: * `cookie_name` - (Required). Name of the application based cookie. Name of the cookie should not start with the following names: AWSALB, AWSALBAPP, and AWSALBTG. They're reserved for use by the load balancer. * `duration_seconds` - (Optional). The time period, in seconds, during which requests from a client should be routed to the same target. The range is 1 second to 1 week (604800 seconds). The default value is 1 day (86400 seconds). + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From d46cc0fcc5c036a3f6432bbc0e94f9b6e5687369 Mon Sep 17 00:00:00 2001 From: Chris Trawick Date: Tue, 26 Jan 2021 19:41:35 -0500 Subject: [PATCH 0018/1208] Added AWS Config Organization Conformance Pack resource --- aws/configservice.go | 80 +++ aws/provider.go | 1 + aws/provider_test.go | 32 ++ ...ws_config_organization_conformance_pack.go | 278 +++++++++++ ...nfig_organization_conformance_pack_test.go | 469 ++++++++++++++++++ deleteme/main.tf | 0 6 files changed, 860 insertions(+) create mode 100644 aws/resource_aws_config_organization_conformance_pack.go create mode 100644 aws/resource_aws_config_organization_conformance_pack_test.go create mode 100644 deleteme/main.tf diff --git a/aws/configservice.go b/aws/configservice.go index 712f43cf189a..7c835d3f6536 100644 --- a/aws/configservice.go +++ b/aws/configservice.go @@ -301,3 +301,83 @@ func configWaitForOrganizationRuleStatusUpdateSuccessful(conn *configservice.Con return err } + +func configDescribeOrganizationConformancePack(conn *configservice.ConfigService, name string) (*configservice.OrganizationConformancePack, error) { + input := &configservice.DescribeOrganizationConformancePacksInput{ + OrganizationConformancePackNames: []*string{aws.String(name)}, + } + + for { + output, err := conn.DescribeOrganizationConformancePacks(input) + + if err != nil { + return nil, err + } + + for _, pack := range output.OrganizationConformancePacks { + if aws.StringValue(pack.OrganizationConformancePackName) == name { + return pack, nil + } + } + + if aws.StringValue(output.NextToken) == "" { + break + } + + input.NextToken = output.NextToken + } + + return nil, nil +} + +func configDescribeOrganizationConformancePackStatus(conn *configservice.ConfigService, name string) (*configservice.OrganizationConformancePackStatus, error) { + input := &configservice.DescribeOrganizationConformancePackStatusesInput{ + OrganizationConformancePackNames: []*string{aws.String(name)}, + } + + for { + output, err := conn.DescribeOrganizationConformancePackStatuses(input) + + if err != nil { + return nil, err + } + + for _, status := range output.OrganizationConformancePackStatuses { + if aws.StringValue(status.OrganizationConformancePackName) == name { + return status, nil + } + } + + if aws.StringValue(output.NextToken) == "" { + break + } + + input.NextToken = output.NextToken + } + + return nil, nil +} + +func configDescribeOrganizationConformancePackDetailedStatus(conn *configservice.ConfigService, name string) ([]*configservice.OrganizationConformancePackDetailedStatus, error) { + input := &configservice.GetOrganizationConformancePackDetailedStatusInput{ + OrganizationConformancePackName: aws.String(name), + } + var ret []*configservice.OrganizationConformancePackDetailedStatus + for { + output, err := conn.GetOrganizationConformancePackDetailedStatus(input) + + if err != nil { + return nil, err + } + + ret = append(ret, output.OrganizationConformancePackDetailedStatuses...) + + if aws.StringValue(output.NextToken) == "" { + break + } + + input.NextToken = output.NextToken + } + + return ret, nil +} diff --git a/aws/provider.go b/aws/provider.go index 64ee387878e7..d92023439d55 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -541,6 +541,7 @@ func Provider() *schema.Provider { "aws_config_configuration_recorder_status": resourceAwsConfigConfigurationRecorderStatus(), "aws_config_conformance_pack": resourceAwsConfigConformancePack(), "aws_config_delivery_channel": resourceAwsConfigDeliveryChannel(), + "aws_config_organization_conformance_pack": resourceAwsConfigOrganizationConformancePack(), "aws_config_organization_custom_rule": resourceAwsConfigOrganizationCustomRule(), "aws_config_organization_managed_rule": resourceAwsConfigOrganizationManagedRule(), "aws_config_remediation_configuration": resourceAwsConfigRemediationConfiguration(), diff --git a/aws/provider_test.go b/aws/provider_test.go index 5a4e7a8cfa5c..5acdb1bb13cf 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -792,6 +792,38 @@ func testAccOrganizationsEnabledPreCheck(t *testing.T) { } } +func testAccOrganizationsMasterPreCheck(t *testing.T) { + conn := testAccProvider.Meta().(*AWSClient).organizationsconn + input := &organizations.DescribeOrganizationInput{} + out, err := conn.DescribeOrganization(input) + if isAWSErr(err, organizations.ErrCodeAWSOrganizationsNotInUseException, "") { + t.Skip("this AWS account must be an existing member of an AWS Organization") + } + if err != nil { + t.Fatalf("error describing AWS Organization: %s", err) + } + masterAccountId := *out.Organization.MasterAccountId + thisAccountId := testAccProvider.Meta().(*AWSClient).accountid + if masterAccountId != thisAccountId { + t.Skipf("this AWS account must be master of its AWS Organization ( %q != %q )", masterAccountId, thisAccountId) + } +} + +func testAccOrganizationsMinAccountsPreCheck(t *testing.T, minAccounts int) { + conn := testAccProvider.Meta().(*AWSClient).organizationsconn + input := &organizations.ListAccountsInput{} + out, err := conn.ListAccounts(input) + if isAWSErr(err, organizations.ErrCodeAWSOrganizationsNotInUseException, "") { + t.Skip("this AWS account must be an existing member of an AWS Organization") + } + if err != nil { + t.Fatalf("error listing accounts in AWS Organization: %s", err) + } + if len(out.Accounts) < minAccounts { + t.Skipf("this AWS account must have at least %d accounts in its organization", minAccounts) + } +} + func testAccPreCheckIamServiceLinkedRole(t *testing.T, pathPrefix string) { conn := testAccProvider.Meta().(*AWSClient).iamconn diff --git a/aws/resource_aws_config_organization_conformance_pack.go b/aws/resource_aws_config_organization_conformance_pack.go new file mode 100644 index 000000000000..7474d3693bbc --- /dev/null +++ b/aws/resource_aws_config_organization_conformance_pack.go @@ -0,0 +1,278 @@ +package aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/configservice" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "log" + "regexp" + "time" +) + +func resourceAwsConfigOrganizationConformancePack() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsConfigOrganizationConformancePackPut, + Read: resourceAwsConfigOrganizationConformancePackRead, + Update: resourceAwsConfigOrganizationConformancePackPut, + Delete: resourceAwsConfigOrganizationConformancePackDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 51200), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z][-a-zA-Z0-9]*$`), "must be a valid conformance pack name"), + ), + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "template_s3_uri": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + "template_body": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 51200), + validateStringIsJsonOrYaml), + StateFunc: func(v interface{}) string { + template, _ := normalizeJsonOrYamlString(v) + return template + }, + }, + "delivery_s3_bucket": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 63), + validation.StringMatch(regexp.MustCompile("awsconfigconforms.+"), "must start with 'awsconfigconforms'"), + ), + }, + "delivery_s3_key_prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "input_parameters": { + Type: schema.TypeMap, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + }, + "excluded_accounts": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[0-9]{12}$`), "must be a valid AWS account ID"), + }, + Optional: true, + }, + }, + } +} + +func resourceAwsConfigOrganizationConformancePackPut(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).configconn + + name := d.Get("name").(string) + input := configservice.PutOrganizationConformancePackInput{ + OrganizationConformancePackName: aws.String(name), + } + + if v, ok := d.GetOk("delivery_s3_bucket"); ok { + input.DeliveryS3Bucket = aws.String(v.(string)) + } + if v, ok := d.GetOk("delivery_s3_key_prefix"); ok { + input.DeliveryS3KeyPrefix = aws.String(v.(string)) + } + if v, ok := d.GetOk("excluded_accounts"); ok { + input.ExcludedAccounts = expandConfigConformancePackExcludedAccounts(v.([]interface{})) + } + if v, ok := d.GetOk("input_parameters"); ok { + input.ConformancePackInputParameters = expandConfigConformancePackParameters(v.(map[string]interface{})) + } + if v, ok := d.GetOk("template_body"); ok { + input.TemplateBody = aws.String(v.(string)) + } + if v, ok := d.GetOk("template_s3_uri"); ok { + input.TemplateS3Uri = aws.String(v.(string)) + } + + _, err := conn.PutOrganizationConformancePack(&input) + if err != nil { + return fmt.Errorf("failed to put AWSConfig organization conformance pack %q: %s", name, err) + } + + d.SetId(name) + conf := resource.StateChangeConf{ + Pending: []string{ + configservice.OrganizationResourceDetailedStatusCreateInProgress, + configservice.OrganizationResourceDetailedStatusUpdateInProgress, + }, + Target: []string{ + configservice.OrganizationResourceDetailedStatusCreateSuccessful, + configservice.OrganizationResourceDetailedStatusUpdateSuccessful, + }, + Timeout: 30 * time.Minute, + Refresh: refreshOrganizationConformancePackStatus(d, conn), + } + if _, err := conf.WaitForState(); err != nil { + return err + } + return resourceAwsConfigOrganizationConformancePackRead(d, meta) +} + +func expandConfigConformancePackExcludedAccounts(i []interface{}) (ret []*string) { + for _, v := range i { + ret = append(ret, aws.String(v.(string))) + } + return +} + +func expandConfigConformancePackParameters(m map[string]interface{}) (params []*configservice.ConformancePackInputParameter) { + for k, v := range m { + params = append(params, &configservice.ConformancePackInputParameter{ + ParameterName: aws.String(k), + ParameterValue: aws.String(v.(string)), + }) + } + return +} + +func refreshOrganizationConformancePackStatus(d *schema.ResourceData, conn *configservice.ConfigService) func() (interface{}, string, error) { + return func() (interface{}, string, error) { + out, err := conn.DescribeOrganizationConformancePackStatuses(&configservice.DescribeOrganizationConformancePackStatusesInput{ + OrganizationConformancePackNames: []*string{aws.String(d.Id())}, + }) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok && isAWSErr(awsErr, configservice.ErrCodeNoSuchOrganizationConformancePackException, "") { + return 42, "", nil + } + return 42, "", fmt.Errorf("failed to describe organization conformance pack %q: %s", d.Id(), err) + } + if len(out.OrganizationConformancePackStatuses) < 1 { + return 42, "", nil + } + status := out.OrganizationConformancePackStatuses[0] + return out, *status.Status, nil + } +} + +func resourceAwsConfigOrganizationConformancePackRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).configconn + + out, err := conn.DescribeOrganizationConformancePacks(&configservice.DescribeOrganizationConformancePacksInput{ + OrganizationConformancePackNames: []*string{aws.String(d.Id())}, + }) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok && isAWSErr(err, configservice.ErrCodeNoSuchOrganizationConformancePackException, "") { + log.Printf("[WARN] Organization Conformance Pack %q is gone (%s)", d.Id(), awsErr.Code()) + d.SetId("") + return nil + } + return err + } + + numberOfPacks := len(out.OrganizationConformancePacks) + if numberOfPacks < 1 { + log.Printf("[WARN] Organization Conformance Pack %q is gone (no packs found)", d.Id()) + d.SetId("") + return nil + } + + if numberOfPacks > 1 { + return fmt.Errorf("expected exactly 1 organization conformance pack, received %d: %#v", + numberOfPacks, out.OrganizationConformancePacks) + } + + log.Printf("[DEBUG] AWS Config organization conformance packs received: %s", out) + + pack := out.OrganizationConformancePacks[0] + if err = d.Set("arn", pack.OrganizationConformancePackArn); err != nil { + return err + } + if err = d.Set("name", pack.OrganizationConformancePackName); err != nil { + return err + } + if err = d.Set("delivery_s3_bucket", pack.DeliveryS3Bucket); err != nil { + return err + } + if err = d.Set("delivery_s3_key_prefix", pack.DeliveryS3KeyPrefix); err != nil { + return err + } + if err = d.Set("excluded_accounts", pack.ExcludedAccounts); err != nil { + return err + } + + if pack.ConformancePackInputParameters != nil { + if err = d.Set("input_parameters", flattenConformancePackInputParameters(pack.ConformancePackInputParameters)); err != nil { + return err + } + } + + return nil +} + +func flattenConformancePackInputParameters(parameters []*configservice.ConformancePackInputParameter) (m map[string]string) { + m = make(map[string]string) + for _, p := range parameters { + m[*p.ParameterName] = *p.ParameterValue + } + return +} + +func resourceAwsConfigOrganizationConformancePackDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).configconn + + name := d.Get("name").(string) + + log.Printf("[DEBUG] Deleting AWS Config organization conformance pack %q", name) + input := &configservice.DeleteOrganizationConformancePackInput{ + OrganizationConformancePackName: aws.String(name), + } + err := resource.Retry(30*time.Minute, func() *resource.RetryError { + _, err := conn.DeleteOrganizationConformancePack(input) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceInUseException" { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + if isResourceTimeoutError(err) { + _, err = conn.DeleteOrganizationConformancePack(input) + } + if err != nil { + return fmt.Errorf("deleting organization conformance pack failed: %s", err) + } + + conf := resource.StateChangeConf{ + Pending: []string{ + configservice.OrganizationResourceDetailedStatusDeleteInProgress, + }, + Target: []string{""}, + Timeout: 30 * time.Minute, + Refresh: refreshOrganizationConformancePackStatus(d, conn), + } + _, err = conf.WaitForState() + if err != nil { + return err + } + + log.Printf("[DEBUG] AWS organization conformance pack %q deleted", name) + + return nil +} diff --git a/aws/resource_aws_config_organization_conformance_pack_test.go b/aws/resource_aws_config_organization_conformance_pack_test.go new file mode 100644 index 000000000000..e8aaf17f5cd8 --- /dev/null +++ b/aws/resource_aws_config_organization_conformance_pack_test.go @@ -0,0 +1,469 @@ +package aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/service/configservice" + "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" + "regexp" + "testing" +) + +func TestAccConfigOrganizationConformancePack_basic(t *testing.T) { + var pack configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + rId := "IAM_PASSWORD_POLICY" + resourceName := "aws_config_organization_conformance_pack.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackConfigRuleIdentifier(rName, rId), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rName))), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", ""), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", ""), + resource.TestCheckNoResourceAttr(resourceName, "input_parameters"), + resource.TestCheckNoResourceAttr(resourceName, "excluded_accounts"), + testAccCheckConfigOrganizationConformancePackSuccessful(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_body"}, + }, + }, + }) +} + +func TestAccConfigOrganizationConformancePack_disappears(t *testing.T) { + var pack configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_config_organization_conformance_pack.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackConfigRuleIdentifier(rName, "IAM_PASSWORD_POLICY"), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + testAccCheckResourceDisappears(testAccProvider, resourceAwsConfigOrganizationConformancePack(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccConfigOrganizationConformancePack_inputParameters(t *testing.T) { + var pack configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + rId := "IAM_PASSWORD_POLICY" + pKey := "ParamKey" + pValue := "ParamValue" + resourceName := "aws_config_organization_conformance_pack.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackConfigRuleIdentifierParameter(rName, rId, pKey, pValue), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rName))), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", ""), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", ""), + resource.TestCheckResourceAttr(resourceName, "input_parameters."+pKey, pValue), + resource.TestCheckNoResourceAttr(resourceName, "excluded_accounts"), + testAccCheckConfigOrganizationConformancePackSuccessful(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_body"}, + }, + }, + }) +} + +func TestAccConfigOrganizationConformancePack_s3Delivery(t *testing.T) { + var pack configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + bName := "awsconfigconforms" + rName + rId := "IAM_PASSWORD_POLICY" + resourceName := "aws_config_organization_conformance_pack.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackConfigRuleIdentifierS3Delivery(rName, rId, bName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rName))), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", bName), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", rId), + resource.TestCheckNoResourceAttr(resourceName, "input_parameters"), + resource.TestCheckNoResourceAttr(resourceName, "excluded_accounts"), + testAccCheckConfigOrganizationConformancePackSuccessful(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_body"}, + }, + }, + }) +} + +func TestAccConfigOrganizationConformancePack_s3Template(t *testing.T) { + var pack configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + bName := rName + kName := rName + ".yaml" + rId := "IAM_PASSWORD_POLICY" + resourceName := "aws_config_organization_conformance_pack.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackConfigRuleIdentifierS3Template(rName, rId, bName, kName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rName))), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", ""), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", ""), + resource.TestCheckNoResourceAttr(resourceName, "input_parameters"), + resource.TestCheckNoResourceAttr(resourceName, "excluded_accounts"), + testAccCheckConfigOrganizationConformancePackSuccessful(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_s3_uri"}, + }, + }, + }) +} + +func TestAccConfigOrganizationConformancePack_excludedAccounts(t *testing.T) { + var pack configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + rId := "IAM_PASSWORD_POLICY" + resourceName := "aws_config_organization_conformance_pack.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccOrganizationsMasterPreCheck(t) + testAccOrganizationsMinAccountsPreCheck(t, 2) + // TODO: All accounts in the organization must also have configuration recorders in the current region, + // which is a little complicated for a precheck. If you get an 'unexpected state' error with this + // test, try enabling configuration recorders across the org. + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackConfigRuleIdentifierExcludedAccounts(rName, rId), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rName))), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", ""), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", ""), + resource.TestCheckNoResourceAttr(resourceName, "input_parameters"), + resource.TestCheckResourceAttr(resourceName, "excluded_accounts.#", "1"), + testAccCheckConfigOrganizationConformancePackSuccessful(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_body"}, + }, + }, + }) +} + +func testAccCheckConfigOrganizationConformancePackDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).configconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_config_organization_conformance_pack" { + continue + } + + rule, err := configDescribeOrganizationConformancePack(conn, rs.Primary.ID) + + if isAWSErr(err, configservice.ErrCodeNoSuchOrganizationConformancePackException, "") { + continue + } + + if err != nil { + return fmt.Errorf("error describing Config Organization Managed Rule (%s): %s", rs.Primary.ID, err) + } + + if rule != nil { + return fmt.Errorf("Config Organization Managed Rule (%s) still exists", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckConfigOrganizationConformancePackExists(resourceName string, ocr *configservice.OrganizationConformancePack) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not Found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).configconn + + pack, err := configDescribeOrganizationConformancePack(conn, rs.Primary.ID) + + if err != nil { + return fmt.Errorf("error describing organization conformance pack (%s): %s", rs.Primary.ID, err) + } + + if pack == nil { + return fmt.Errorf("organization conformance pack (%s) not found", rs.Primary.ID) + } + + *ocr = *pack + + return nil + } +} + +func testAccCheckConfigOrganizationConformancePackSuccessful(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not Found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).configconn + + packStatus, err := configDescribeOrganizationConformancePackStatus(conn, rs.Primary.ID) + if err != nil { + return fmt.Errorf("error describing organization conformance pack status (%s): %s", rs.Primary.ID, err) + } + if packStatus == nil { + return fmt.Errorf("organization conformance pack status (%s) not found", rs.Primary.ID) + } + if *packStatus.Status != configservice.OrganizationResourceStatusCreateSuccessful { + return fmt.Errorf("organization conformance pack (%s) returned %s status (%s): %s", rs.Primary.ID, *packStatus.Status, *packStatus.ErrorCode, *packStatus.ErrorMessage) + } + + detailedStatus, err := configDescribeOrganizationConformancePackDetailedStatus(conn, rs.Primary.ID) + if err != nil { + return fmt.Errorf("error describing organization conformance pack detailed status (%s): %s", rs.Primary.ID, err) + } + if detailedStatus == nil { + return fmt.Errorf("organization conformance pack detailed status (%s) not found", rs.Primary.ID) + } + for _, s := range detailedStatus { + if *s.Status != configservice.OrganizationResourceDetailedStatusCreateSuccessful { + return fmt.Errorf("organization conformance pack (%s) on account %s returned %s status (%s): %s", rs.Primary.ID, *s.Status, *s.AccountId, *s.ErrorCode, *s.ErrorMessage) + } + } + + return nil + } +} + +/*func testAccConfigOrganizationConformancePackBase(rName string) string { + return fmt.Sprintf(` + +data "aws_partition" "current" { +} + +resource "aws_config_configuration_recorder" "test" { + depends_on = [aws_iam_role_policy_attachment.test] + + name = %[1]q + role_arn = aws_iam_role.test.arn +} + +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = < Date: Tue, 26 Jan 2021 20:09:25 -0500 Subject: [PATCH 0019/1208] Added whitespace to strings --- ...nfig_organization_conformance_pack_test.go | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/aws/resource_aws_config_organization_conformance_pack_test.go b/aws/resource_aws_config_organization_conformance_pack_test.go index e8aaf17f5cd8..4d446cfeb456 100644 --- a/aws/resource_aws_config_organization_conformance_pack_test.go +++ b/aws/resource_aws_config_organization_conformance_pack_test.go @@ -310,14 +310,12 @@ data "aws_partition" "current" { resource "aws_config_configuration_recorder" "test" { depends_on = [aws_iam_role_policy_attachment.test] - - name = %[1]q - role_arn = aws_iam_role.test.arn + name = %[1]q + role_arn = aws_iam_role.test.arn } resource "aws_iam_role" "test" { - name = %[1]q - + name = %[1]q assume_role_policy = < Date: Tue, 26 Jan 2021 20:15:34 -0500 Subject: [PATCH 0020/1208] More whitespace "fixes" in strings. Seems the linter is as confused as I am. --- ...esource_aws_config_organization_conformance_pack_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_config_organization_conformance_pack_test.go b/aws/resource_aws_config_organization_conformance_pack_test.go index 4d446cfeb456..dfe07b1220b4 100644 --- a/aws/resource_aws_config_organization_conformance_pack_test.go +++ b/aws/resource_aws_config_organization_conformance_pack_test.go @@ -363,11 +363,11 @@ EOT func testAccConfigOrganizationConformancePackConfigRuleIdentifierParameter(rName, ruleIdentifier, pKey, pValue string) string { return fmt.Sprintf(` resource "aws_config_organization_conformance_pack" "test" { - name = %[1]q + name = %[1]q input_parameters = { %[3]s = %[4]q } - template_body = < Date: Tue, 26 Jan 2021 20:27:15 -0500 Subject: [PATCH 0021/1208] so many lints, so little time --- aws/resource_aws_config_organization_conformance_pack.go | 7 ++++--- ...source_aws_config_organization_conformance_pack_test.go | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_config_organization_conformance_pack.go b/aws/resource_aws_config_organization_conformance_pack.go index 7474d3693bbc..1a1c024c2b92 100644 --- a/aws/resource_aws_config_organization_conformance_pack.go +++ b/aws/resource_aws_config_organization_conformance_pack.go @@ -2,15 +2,16 @@ package aws import ( "fmt" + "log" + "regexp" + "time" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/configservice" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" - "regexp" - "time" ) func resourceAwsConfigOrganizationConformancePack() *schema.Resource { diff --git a/aws/resource_aws_config_organization_conformance_pack_test.go b/aws/resource_aws_config_organization_conformance_pack_test.go index dfe07b1220b4..3c4509001d19 100644 --- a/aws/resource_aws_config_organization_conformance_pack_test.go +++ b/aws/resource_aws_config_organization_conformance_pack_test.go @@ -2,12 +2,13 @@ package aws import ( "fmt" + "regexp" + "testing" + "github.com/aws/aws-sdk-go/service/configservice" "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" - "regexp" - "testing" ) func TestAccConfigOrganizationConformancePack_basic(t *testing.T) { From 0bbc5e7f88fdeed16ab6b77385cafa158f481f93 Mon Sep 17 00:00:00 2001 From: Chris Trawick Date: Tue, 26 Jan 2021 21:46:21 -0500 Subject: [PATCH 0022/1208] Added documentation. --- ...rganization_conformance_pack.html.markdown | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 website/docs/r/config_organization_conformance_pack.html.markdown diff --git a/website/docs/r/config_organization_conformance_pack.html.markdown b/website/docs/r/config_organization_conformance_pack.html.markdown new file mode 100644 index 000000000000..8d1e26205bf3 --- /dev/null +++ b/website/docs/r/config_organization_conformance_pack.html.markdown @@ -0,0 +1,60 @@ +--- +subcategory: "Config" +layout: "aws" +page_title: "AWS: aws_config_organization_conformance_pack" +description: |- + Manages a Config Organization Conformance Pack +--- + +# Resource: aws_config_organization_conformance_pack + +Manages a Config Organization Conformance Pack. More information about these rules can be found in the [Managing Conformance Packs Across all Accounts in Your Organization](https://docs.aws.amazon.com/config/latest/developerguide/conformance-pack-organization-apis.html) and [AWS Config Managed Rules](https://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_use-managed-rules.html) documentation. Example conformance pack templates may be found in the [AWS Config Rules Repository](https://github.com/awslabs/aws-config-rules/tree/master/aws-config-conformance-packs). + +~> **NOTE:** This resource must be created in the Organization master account or a delegate administrator account and rules will include the master account unless its ID is added to the `excluded_accounts` argument. + +~> **NOTE:** Every Organization account except those configured in the `excluded_accounts` argument must have a Configuration Recorder with proper IAM permissions before the rule will successfully create or update. See also the [`aws_config_configuration_recorder` resource](/docs/providers/aws/r/config_configuration_recorder.html). + +## Example Usage + +```hcl +resource "aws_config_organization_conformance_pack" "test" { + name = "example" + template_body = < Date: Tue, 26 Jan 2021 23:46:13 -0500 Subject: [PATCH 0023/1208] Linked tests to top level --- ..._aws_config_organization_conformance_pack_test.go | 12 ++++++------ aws/resource_aws_config_test.go | 8 ++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_config_organization_conformance_pack_test.go b/aws/resource_aws_config_organization_conformance_pack_test.go index 3c4509001d19..18670a2fa85d 100644 --- a/aws/resource_aws_config_organization_conformance_pack_test.go +++ b/aws/resource_aws_config_organization_conformance_pack_test.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func TestAccConfigOrganizationConformancePack_basic(t *testing.T) { +func testAccConfigOrganizationConformancePack_basic(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") rId := "IAM_PASSWORD_POLICY" @@ -45,7 +45,7 @@ func TestAccConfigOrganizationConformancePack_basic(t *testing.T) { }) } -func TestAccConfigOrganizationConformancePack_disappears(t *testing.T) { +func testAccConfigOrganizationConformancePack_disappears(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_config_organization_conformance_pack.test" @@ -67,7 +67,7 @@ func TestAccConfigOrganizationConformancePack_disappears(t *testing.T) { }) } -func TestAccConfigOrganizationConformancePack_inputParameters(t *testing.T) { +func testAccConfigOrganizationConformancePack_InputParameters(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") rId := "IAM_PASSWORD_POLICY" @@ -103,7 +103,7 @@ func TestAccConfigOrganizationConformancePack_inputParameters(t *testing.T) { }) } -func TestAccConfigOrganizationConformancePack_s3Delivery(t *testing.T) { +func testAccConfigOrganizationConformancePack_S3Delivery(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") bName := "awsconfigconforms" + rName @@ -138,7 +138,7 @@ func TestAccConfigOrganizationConformancePack_s3Delivery(t *testing.T) { }) } -func TestAccConfigOrganizationConformancePack_s3Template(t *testing.T) { +func testAccConfigOrganizationConformancePack_S3Template(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") bName := rName @@ -174,7 +174,7 @@ func TestAccConfigOrganizationConformancePack_s3Template(t *testing.T) { }) } -func TestAccConfigOrganizationConformancePack_excludedAccounts(t *testing.T) { +func testAccConfigOrganizationConformancePack_ExcludedAccounts(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") rId := "IAM_PASSWORD_POLICY" diff --git a/aws/resource_aws_config_test.go b/aws/resource_aws_config_test.go index ecaaeecd53ef..a97c7ba88a19 100644 --- a/aws/resource_aws_config_test.go +++ b/aws/resource_aws_config_test.go @@ -74,6 +74,14 @@ func TestAccAWSConfig_serial(t *testing.T) { "TagKeyScope": testAccConfigOrganizationManagedRule_TagKeyScope, "TagValueScope": testAccConfigOrganizationManagedRule_TagValueScope, }, + "OrganizationConformancePack": { + "basic": testAccConfigOrganizationConformancePack_basic, + "disappears": testAccConfigOrganizationConformancePack_disappears, + "InputParameters": testAccConfigOrganizationConformancePack_InputParameters, + "S3Delivery": testAccConfigOrganizationConformancePack_S3Delivery, + "S3Template": testAccConfigOrganizationConformancePack_S3Template, + "ExcludedAccounts": testAccConfigOrganizationConformancePack_ExcludedAccounts, + }, "RemediationConfiguration": { "basic": testAccConfigRemediationConfiguration_basic, "disappears": testAccConfigRemediationConfiguration_disappears, From 07cb43a1d9dad27efc24dc3a5d2e22f0ec109abd Mon Sep 17 00:00:00 2001 From: Chris Trawick Date: Wed, 27 Jan 2021 07:13:32 -0500 Subject: [PATCH 0024/1208] Added changelog --- .changelog/17298.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/17298.txt diff --git a/.changelog/17298.txt b/.changelog/17298.txt new file mode 100644 index 000000000000..dc491d05c226 --- /dev/null +++ b/.changelog/17298.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_config_organization_conformance_pack +``` \ No newline at end of file From b6b4730f5712ae5694bbe5ba6dc3ee615e21b5f7 Mon Sep 17 00:00:00 2001 From: Chris Trawick Date: Wed, 27 Jan 2021 07:15:27 -0500 Subject: [PATCH 0025/1208] Cleanup --- deleteme/main.tf | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 deleteme/main.tf diff --git a/deleteme/main.tf b/deleteme/main.tf deleted file mode 100644 index e69de29bb2d1..000000000000 From d2d14309ad4fbf34274bd988e81097f6b4b36eb8 Mon Sep 17 00:00:00 2001 From: Chris Trawick Date: Wed, 27 Jan 2021 11:17:17 -0500 Subject: [PATCH 0026/1208] Serialized tests for consistency with other config tests --- ...nfig_organization_conformance_pack_test.go | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_config_organization_conformance_pack_test.go b/aws/resource_aws_config_organization_conformance_pack_test.go index 18670a2fa85d..988926dfc587 100644 --- a/aws/resource_aws_config_organization_conformance_pack_test.go +++ b/aws/resource_aws_config_organization_conformance_pack_test.go @@ -17,7 +17,7 @@ func testAccConfigOrganizationConformancePack_basic(t *testing.T) { rId := "IAM_PASSWORD_POLICY" resourceName := "aws_config_organization_conformance_pack.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, @@ -50,7 +50,7 @@ func testAccConfigOrganizationConformancePack_disappears(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_config_organization_conformance_pack.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, @@ -75,7 +75,7 @@ func testAccConfigOrganizationConformancePack_InputParameters(t *testing.T) { pValue := "ParamValue" resourceName := "aws_config_organization_conformance_pack.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, @@ -110,7 +110,7 @@ func testAccConfigOrganizationConformancePack_S3Delivery(t *testing.T) { rId := "IAM_PASSWORD_POLICY" resourceName := "aws_config_organization_conformance_pack.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, @@ -146,7 +146,7 @@ func testAccConfigOrganizationConformancePack_S3Template(t *testing.T) { rId := "IAM_PASSWORD_POLICY" resourceName := "aws_config_organization_conformance_pack.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, @@ -180,7 +180,7 @@ func testAccConfigOrganizationConformancePack_ExcludedAccounts(t *testing.T) { rId := "IAM_PASSWORD_POLICY" resourceName := "aws_config_organization_conformance_pack.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) testAccOrganizationsMasterPreCheck(t) @@ -303,7 +303,7 @@ func testAccCheckConfigOrganizationConformancePackSuccessful(resourceName string } } -/*func testAccConfigOrganizationConformancePackBase(rName string) string { +func testAccConfigOrganizationConformancePackBase(rName string) string { return fmt.Sprintf(` data "aws_partition" "current" { @@ -341,10 +341,13 @@ resource "aws_iam_role_policy_attachment" "test" { `, rName) } -*/ + func testAccConfigOrganizationConformancePackConfigRuleIdentifier(rName, ruleIdentifier string) string { return fmt.Sprintf(` +%[3]s + resource "aws_config_organization_conformance_pack" "test" { + depends_on = [aws_config_configuration_recorder.test] name = %[1]q template_body = < Date: Wed, 27 Jan 2021 11:37:05 -0500 Subject: [PATCH 0027/1208] removed whitespace from a string, wishing the linter would make up its mind --- aws/resource_aws_config_organization_conformance_pack_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_config_organization_conformance_pack_test.go b/aws/resource_aws_config_organization_conformance_pack_test.go index 988926dfc587..b26a42d70258 100644 --- a/aws/resource_aws_config_organization_conformance_pack_test.go +++ b/aws/resource_aws_config_organization_conformance_pack_test.go @@ -369,8 +369,8 @@ func testAccConfigOrganizationConformancePackConfigRuleIdentifierParameter(rName %[5]s resource "aws_config_organization_conformance_pack" "test" { - depends_on = [aws_config_configuration_recorder.test] - name = %[1]q + depends_on = [aws_config_configuration_recorder.test] + name = %[1]q input_parameters = { %[3]s = %[4]q } From 30e33b81efeeb13701b0eef5d437226d4002be6d Mon Sep 17 00:00:00 2001 From: Chris Trawick Date: Thu, 28 Jan 2021 18:28:25 -0500 Subject: [PATCH 0028/1208] fixed a potential conflict --- aws/configservice.go | 18 ++++++++++++++++++ ...aws_config_organization_conformance_pack.go | 18 ------------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/aws/configservice.go b/aws/configservice.go index 7c835d3f6536..a395eb3b30f5 100644 --- a/aws/configservice.go +++ b/aws/configservice.go @@ -381,3 +381,21 @@ func configDescribeOrganizationConformancePackDetailedStatus(conn *configservice return ret, nil } + +func expandConfigConformancePackParameters(m map[string]interface{}) (params []*configservice.ConformancePackInputParameter) { + for k, v := range m { + params = append(params, &configservice.ConformancePackInputParameter{ + ParameterName: aws.String(k), + ParameterValue: aws.String(v.(string)), + }) + } + return +} + +func flattenConformancePackInputParameters(parameters []*configservice.ConformancePackInputParameter) (m map[string]string) { + m = make(map[string]string) + for _, p := range parameters { + m[*p.ParameterName] = *p.ParameterValue + } + return +} diff --git a/aws/resource_aws_config_organization_conformance_pack.go b/aws/resource_aws_config_organization_conformance_pack.go index 1a1c024c2b92..9954c47a4b61 100644 --- a/aws/resource_aws_config_organization_conformance_pack.go +++ b/aws/resource_aws_config_organization_conformance_pack.go @@ -142,16 +142,6 @@ func expandConfigConformancePackExcludedAccounts(i []interface{}) (ret []*string return } -func expandConfigConformancePackParameters(m map[string]interface{}) (params []*configservice.ConformancePackInputParameter) { - for k, v := range m { - params = append(params, &configservice.ConformancePackInputParameter{ - ParameterName: aws.String(k), - ParameterValue: aws.String(v.(string)), - }) - } - return -} - func refreshOrganizationConformancePackStatus(d *schema.ResourceData, conn *configservice.ConfigService) func() (interface{}, string, error) { return func() (interface{}, string, error) { out, err := conn.DescribeOrganizationConformancePackStatuses(&configservice.DescribeOrganizationConformancePackStatusesInput{ @@ -226,14 +216,6 @@ func resourceAwsConfigOrganizationConformancePackRead(d *schema.ResourceData, me return nil } -func flattenConformancePackInputParameters(parameters []*configservice.ConformancePackInputParameter) (m map[string]string) { - m = make(map[string]string) - for _, p := range parameters { - m[*p.ParameterName] = *p.ParameterValue - } - return -} - func resourceAwsConfigOrganizationConformancePackDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).configconn From f814caf758750187b56ef49f0b9ef58bbe37e01f Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Wed, 17 Feb 2021 17:11:52 -0500 Subject: [PATCH 0029/1208] CR updates; update waiter funcs, acctest coverage, and documentation --- aws/configservice.go | 278 +++++---- aws/provider_test.go | 32 -- ...ws_config_organization_conformance_pack.go | 296 +++++----- ...nfig_organization_conformance_pack_test.go | 540 +++++++++++++----- aws/resource_aws_config_test.go | 21 +- ...rganization_conformance_pack.html.markdown | 89 ++- 6 files changed, 813 insertions(+), 443 deletions(-) diff --git a/aws/configservice.go b/aws/configservice.go index a395eb3b30f5..e03ba2e69666 100644 --- a/aws/configservice.go +++ b/aws/configservice.go @@ -15,8 +15,15 @@ const ( ConfigConformancePackCreateTimeout = 5 * time.Minute ConfigConformancePackDeleteTimeout = 5 * time.Minute + ConfigOrganizationConformancePackCreateTimeout = 10 * time.Minute + ConfigOrganizationConformancePackUpdateTimeout = 10 * time.Minute + ConfigOrganizationConformancePackDeleteTimeout = 10 * time.Minute + ConfigConformancePackStatusNotFound = "NotFound" ConfigConformancePackStatusUnknown = "Unknown" + + ConfigOrganizationConformancePackStatusNotFound = "NotFound" + ConfigOrganizationConformancePackStatusUnknown = "Unknown" ) func configDescribeConformancePack(conn *configservice.ConfigService, name string) (*configservice.ConformancePackDetail, error) { @@ -135,6 +142,62 @@ func configDescribeOrganizationConfigRuleStatus(conn *configservice.ConfigServic return nil, nil } +func configDescribeOrganizationConformancePack(conn *configservice.ConfigService, name string) (*configservice.OrganizationConformancePack, error) { + input := &configservice.DescribeOrganizationConformancePacksInput{ + OrganizationConformancePackNames: []*string{aws.String(name)}, + } + + for { + output, err := conn.DescribeOrganizationConformancePacks(input) + + if err != nil { + return nil, err + } + + for _, pack := range output.OrganizationConformancePacks { + if aws.StringValue(pack.OrganizationConformancePackName) == name { + return pack, nil + } + } + + if aws.StringValue(output.NextToken) == "" { + break + } + + input.NextToken = output.NextToken + } + + return nil, nil +} + +func configDescribeOrganizationConformancePackStatus(conn *configservice.ConfigService, name string) (*configservice.OrganizationConformancePackStatus, error) { + input := &configservice.DescribeOrganizationConformancePackStatusesInput{ + OrganizationConformancePackNames: []*string{aws.String(name)}, + } + + for { + output, err := conn.DescribeOrganizationConformancePackStatuses(input) + + if err != nil { + return nil, err + } + + for _, status := range output.OrganizationConformancePackStatuses { + if aws.StringValue(status.OrganizationConformancePackName) == name { + return status, nil + } + } + + if aws.StringValue(output.NextToken) == "" { + break + } + + input.NextToken = output.NextToken + } + + return nil, nil +} + func configGetOrganizationConfigRuleDetailedStatus(conn *configservice.ConfigService, ruleName, ruleStatus string) ([]*configservice.MemberAccountStatus, error) { input := &configservice.GetOrganizationConfigRuleDetailedStatusInput{ Filters: &configservice.StatusDetailFilters{ @@ -163,6 +226,35 @@ func configGetOrganizationConfigRuleDetailedStatus(conn *configservice.ConfigSer return statuses, nil } +func configGetOrganizationConformancePackDetailedStatus(conn *configservice.ConfigService, name, status string) ([]*configservice.OrganizationConformancePackDetailedStatus, error) { + input := &configservice.GetOrganizationConformancePackDetailedStatusInput{ + Filters: &configservice.OrganizationResourceDetailedStatusFilters{ + Status: aws.String(status), + }, + OrganizationConformancePackName: aws.String(name), + } + + var statuses []*configservice.OrganizationConformancePackDetailedStatus + + for { + output, err := conn.GetOrganizationConformancePackDetailedStatus(input) + + if err != nil { + return nil, err + } + + statuses = append(statuses, output.OrganizationConformancePackDetailedStatuses...) + + if aws.StringValue(output.NextToken) == "" { + break + } + + input.NextToken = output.NextToken + } + + return statuses, nil +} + func configRefreshConformancePackStatus(conn *configservice.ConfigService, name string) resource.StateRefreshFunc { return func() (interface{}, string, error) { status, err := configDescribeConformancePackStatus(conn, name) @@ -221,6 +313,44 @@ func configRefreshOrganizationConfigRuleStatus(conn *configservice.ConfigService } } +func configRefreshOrganizationConformancePackStatus(conn *configservice.ConfigService, name string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + status, err := configDescribeOrganizationConformancePackStatus(conn, name) + + if err != nil { + return nil, ConfigOrganizationConformancePackStatusUnknown, err + } + + if status == nil { + return nil, ConfigOrganizationConformancePackStatusNotFound, nil + } + + if status.ErrorCode != nil { + return status, aws.StringValue(status.Status), fmt.Errorf("%s: %s", aws.StringValue(status.ErrorCode), aws.StringValue(status.ErrorMessage)) + } + + switch aws.StringValue(status.Status) { + case configservice.OrganizationResourceStatusCreateFailed, configservice.OrganizationResourceStatusDeleteFailed, configservice.OrganizationResourceStatusUpdateFailed: + // Display detailed errors for failed member accounts + memberAccountStatuses, err := configGetOrganizationConformancePackDetailedStatus(conn, name, aws.StringValue(status.Status)) + + if err != nil { + return status, aws.StringValue(status.Status), fmt.Errorf("unable to get Config Organization Conformance Pack detailed status for showing member account errors: %w", err) + } + + var errBuilder strings.Builder + + for _, mas := range memberAccountStatuses { + errBuilder.WriteString(fmt.Sprintf("Account ID (%s): %s: %s\n", aws.StringValue(mas.AccountId), aws.StringValue(mas.ErrorCode), aws.StringValue(mas.ErrorMessage))) + } + + return status, aws.StringValue(status.Status), fmt.Errorf("Failed in %d account(s):\n\n%s", len(memberAccountStatuses), errBuilder.String()) + } + + return status, aws.StringValue(status.Status), nil + } +} + func configWaitForConformancePackStateCreateComplete(conn *configservice.ConfigService, name string) error { stateChangeConf := resource.StateChangeConf{ Pending: []string{configservice.ConformancePackStateCreateInProgress}, @@ -231,10 +361,6 @@ func configWaitForConformancePackStateCreateComplete(conn *configservice.ConfigS _, err := stateChangeConf.WaitForState() - if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchConformancePackException) { - return nil - } - return err } @@ -256,6 +382,52 @@ func configWaitForConformancePackStateDeleteComplete(conn *configservice.ConfigS return err } +func configWaitForOrganizationConformancePackStatusCreateSuccessful(conn *configservice.ConfigService, name string) error { + stateChangeConf := resource.StateChangeConf{ + Pending: []string{configservice.OrganizationResourceStatusCreateInProgress}, + Target: []string{configservice.OrganizationResourceStatusCreateSuccessful}, + Timeout: ConfigOrganizationConformancePackCreateTimeout, + Refresh: configRefreshOrganizationConformancePackStatus(conn, name), + // Include a Delay to avoid transient error i.e. OrganizationAccessDeniedException + Delay: 1 * time.Minute, + } + + _, err := stateChangeConf.WaitForState() + + return err + +} + +func configWaitForOrganizationConformancePackStatusUpdateSuccessful(conn *configservice.ConfigService, name string) error { + stateChangeConf := resource.StateChangeConf{ + Pending: []string{configservice.OrganizationResourceStatusUpdateInProgress}, + Target: []string{configservice.OrganizationResourceStatusUpdateSuccessful}, + Timeout: ConfigOrganizationConformancePackUpdateTimeout, + Refresh: configRefreshOrganizationConformancePackStatus(conn, name), + } + + _, err := stateChangeConf.WaitForState() + + return err +} + +func configWaitForOrganizationConformancePackStatusDeleteSuccessful(conn *configservice.ConfigService, name string) error { + stateChangeConf := resource.StateChangeConf{ + Pending: []string{configservice.OrganizationResourceStatusDeleteInProgress}, + Target: []string{configservice.OrganizationResourceStatusDeleteSuccessful}, + Timeout: ConfigOrganizationConformancePackDeleteTimeout, + Refresh: configRefreshOrganizationConformancePackStatus(conn, name), + } + + _, err := stateChangeConf.WaitForState() + + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchOrganizationConformancePackException) { + return nil + } + + return err +} + func configWaitForOrganizationRuleStatusCreateSuccessful(conn *configservice.ConfigService, name string, timeout time.Duration) error { stateChangeConf := &resource.StateChangeConf{ Pending: []string{configservice.OrganizationRuleStatusCreateInProgress}, @@ -301,101 +473,3 @@ func configWaitForOrganizationRuleStatusUpdateSuccessful(conn *configservice.Con return err } - -func configDescribeOrganizationConformancePack(conn *configservice.ConfigService, name string) (*configservice.OrganizationConformancePack, error) { - input := &configservice.DescribeOrganizationConformancePacksInput{ - OrganizationConformancePackNames: []*string{aws.String(name)}, - } - - for { - output, err := conn.DescribeOrganizationConformancePacks(input) - - if err != nil { - return nil, err - } - - for _, pack := range output.OrganizationConformancePacks { - if aws.StringValue(pack.OrganizationConformancePackName) == name { - return pack, nil - } - } - - if aws.StringValue(output.NextToken) == "" { - break - } - - input.NextToken = output.NextToken - } - - return nil, nil -} - -func configDescribeOrganizationConformancePackStatus(conn *configservice.ConfigService, name string) (*configservice.OrganizationConformancePackStatus, error) { - input := &configservice.DescribeOrganizationConformancePackStatusesInput{ - OrganizationConformancePackNames: []*string{aws.String(name)}, - } - - for { - output, err := conn.DescribeOrganizationConformancePackStatuses(input) - - if err != nil { - return nil, err - } - - for _, status := range output.OrganizationConformancePackStatuses { - if aws.StringValue(status.OrganizationConformancePackName) == name { - return status, nil - } - } - - if aws.StringValue(output.NextToken) == "" { - break - } - - input.NextToken = output.NextToken - } - - return nil, nil -} - -func configDescribeOrganizationConformancePackDetailedStatus(conn *configservice.ConfigService, name string) ([]*configservice.OrganizationConformancePackDetailedStatus, error) { - input := &configservice.GetOrganizationConformancePackDetailedStatusInput{ - OrganizationConformancePackName: aws.String(name), - } - var ret []*configservice.OrganizationConformancePackDetailedStatus - for { - output, err := conn.GetOrganizationConformancePackDetailedStatus(input) - - if err != nil { - return nil, err - } - - ret = append(ret, output.OrganizationConformancePackDetailedStatuses...) - - if aws.StringValue(output.NextToken) == "" { - break - } - - input.NextToken = output.NextToken - } - - return ret, nil -} - -func expandConfigConformancePackParameters(m map[string]interface{}) (params []*configservice.ConformancePackInputParameter) { - for k, v := range m { - params = append(params, &configservice.ConformancePackInputParameter{ - ParameterName: aws.String(k), - ParameterValue: aws.String(v.(string)), - }) - } - return -} - -func flattenConformancePackInputParameters(parameters []*configservice.ConformancePackInputParameter) (m map[string]string) { - m = make(map[string]string) - for _, p := range parameters { - m[*p.ParameterName] = *p.ParameterValue - } - return -} diff --git a/aws/provider_test.go b/aws/provider_test.go index 5acdb1bb13cf..5a4e7a8cfa5c 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -792,38 +792,6 @@ func testAccOrganizationsEnabledPreCheck(t *testing.T) { } } -func testAccOrganizationsMasterPreCheck(t *testing.T) { - conn := testAccProvider.Meta().(*AWSClient).organizationsconn - input := &organizations.DescribeOrganizationInput{} - out, err := conn.DescribeOrganization(input) - if isAWSErr(err, organizations.ErrCodeAWSOrganizationsNotInUseException, "") { - t.Skip("this AWS account must be an existing member of an AWS Organization") - } - if err != nil { - t.Fatalf("error describing AWS Organization: %s", err) - } - masterAccountId := *out.Organization.MasterAccountId - thisAccountId := testAccProvider.Meta().(*AWSClient).accountid - if masterAccountId != thisAccountId { - t.Skipf("this AWS account must be master of its AWS Organization ( %q != %q )", masterAccountId, thisAccountId) - } -} - -func testAccOrganizationsMinAccountsPreCheck(t *testing.T, minAccounts int) { - conn := testAccProvider.Meta().(*AWSClient).organizationsconn - input := &organizations.ListAccountsInput{} - out, err := conn.ListAccounts(input) - if isAWSErr(err, organizations.ErrCodeAWSOrganizationsNotInUseException, "") { - t.Skip("this AWS account must be an existing member of an AWS Organization") - } - if err != nil { - t.Fatalf("error listing accounts in AWS Organization: %s", err) - } - if len(out.Accounts) < minAccounts { - t.Skipf("this AWS account must have at least %d accounts in its organization", minAccounts) - } -} - func testAccPreCheckIamServiceLinkedRole(t *testing.T, pathPrefix string) { conn := testAccProvider.Meta().(*AWSClient).iamconn diff --git a/aws/resource_aws_config_organization_conformance_pack.go b/aws/resource_aws_config_organization_conformance_pack.go index 9954c47a4b61..356423e34b21 100644 --- a/aws/resource_aws_config_organization_conformance_pack.go +++ b/aws/resource_aws_config_organization_conformance_pack.go @@ -4,21 +4,21 @@ import ( "fmt" "log" "regexp" - "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/configservice" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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/tfresource" ) func resourceAwsConfigOrganizationConformancePack() *schema.Resource { return &schema.Resource{ - Create: resourceAwsConfigOrganizationConformancePackPut, + Create: resourceAwsConfigOrganizationConformancePackCreate, Read: resourceAwsConfigOrganizationConformancePackRead, - Update: resourceAwsConfigOrganizationConformancePackPut, + Update: resourceAwsConfigOrganizationConformancePackUpdate, Delete: resourceAwsConfigOrganizationConformancePackDelete, Importer: &schema.ResourceImporter{ @@ -26,40 +26,16 @@ func resourceAwsConfigOrganizationConformancePack() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 51200), - validation.StringMatch(regexp.MustCompile(`^[a-zA-Z][-a-zA-Z0-9]*$`), "must be a valid conformance pack name"), - ), - }, "arn": { Type: schema.TypeString, Computed: true, }, - "template_s3_uri": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 256), - }, - "template_body": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 51200), - validateStringIsJsonOrYaml), - StateFunc: func(v interface{}) string { - template, _ := normalizeJsonOrYamlString(v) - return template - }, - }, "delivery_s3_bucket": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(1, 63), - validation.StringMatch(regexp.MustCompile("awsconfigconforms.+"), "must start with 'awsconfigconforms'"), + validation.StringMatch(regexp.MustCompile(`^awsconfigconforms`), `must begin with "awsconfigconforms"`), ), }, "delivery_s3_key_prefix": { @@ -67,24 +43,66 @@ func resourceAwsConfigOrganizationConformancePack() *schema.Resource { Optional: true, ValidateFunc: validation.StringLenBetween(1, 1024), }, - "input_parameters": { - Type: schema.TypeMap, - Elem: &schema.Schema{Type: schema.TypeString}, - Optional: true, - }, "excluded_accounts": { - Type: schema.TypeList, + Type: schema.TypeSet, + Optional: true, + MaxItems: 1000, Elem: &schema.Schema{ Type: schema.TypeString, - ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[0-9]{12}$`), "must be a valid AWS account ID"), + ValidateFunc: validateAwsAccountId, + }, + }, + "input_parameter": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 60, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "parameter_name": { + Type: schema.TypeString, + Required: true, + }, + "parameter_value": { + Type: schema.TypeString, + Required: true, + }, + }, }, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 128), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z]`), "must begin with alphabetic character"), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9-]+$`), "must contain only alphanumeric and hyphen characters"), + ), + }, + "template_body": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: suppressEquivalentJsonOrYamlDiffs, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 51200), + validateStringIsJsonOrYaml, + ), + ConflictsWith: []string{"template_s3_uri"}, + }, + "template_s3_uri": { + Type: schema.TypeString, Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 1024), + validation.StringMatch(regexp.MustCompile(`^s3://`), "must begin with s3://"), + ), + ConflictsWith: []string{"template_body"}, }, }, } } -func resourceAwsConfigOrganizationConformancePackPut(d *schema.ResourceData, meta interface{}) error { +func resourceAwsConfigOrganizationConformancePackCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).configconn name := d.Get("name").(string) @@ -95,167 +113,179 @@ func resourceAwsConfigOrganizationConformancePackPut(d *schema.ResourceData, met if v, ok := d.GetOk("delivery_s3_bucket"); ok { input.DeliveryS3Bucket = aws.String(v.(string)) } + if v, ok := d.GetOk("delivery_s3_key_prefix"); ok { input.DeliveryS3KeyPrefix = aws.String(v.(string)) } + if v, ok := d.GetOk("excluded_accounts"); ok { - input.ExcludedAccounts = expandConfigConformancePackExcludedAccounts(v.([]interface{})) + input.ExcludedAccounts = expandStringSet(v.(*schema.Set)) } - if v, ok := d.GetOk("input_parameters"); ok { - input.ConformancePackInputParameters = expandConfigConformancePackParameters(v.(map[string]interface{})) + + if v, ok := d.GetOk("input_parameter"); ok { + input.ConformancePackInputParameters = expandConfigConformancePackInputParameters(v.(*schema.Set).List()) } + if v, ok := d.GetOk("template_body"); ok { input.TemplateBody = aws.String(v.(string)) } + if v, ok := d.GetOk("template_s3_uri"); ok { input.TemplateS3Uri = aws.String(v.(string)) } - _, err := conn.PutOrganizationConformancePack(&input) + err := resource.Retry(ConfigOrganizationConformancePackCreateTimeout, func() *resource.RetryError { + _, err := conn.PutOrganizationConformancePack(&input) + + if err != nil { + // OrganizationAccessDeniedException seems to be a transient error + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeOrganizationAccessDeniedException) { + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + _, err = conn.PutOrganizationConformancePack(&input) + } + if err != nil { - return fmt.Errorf("failed to put AWSConfig organization conformance pack %q: %s", name, err) + return fmt.Errorf("error creating Config Organization Conformance Pack (%s): %w", name, err) } d.SetId(name) - conf := resource.StateChangeConf{ - Pending: []string{ - configservice.OrganizationResourceDetailedStatusCreateInProgress, - configservice.OrganizationResourceDetailedStatusUpdateInProgress, - }, - Target: []string{ - configservice.OrganizationResourceDetailedStatusCreateSuccessful, - configservice.OrganizationResourceDetailedStatusUpdateSuccessful, - }, - Timeout: 30 * time.Minute, - Refresh: refreshOrganizationConformancePackStatus(d, conn), - } - if _, err := conf.WaitForState(); err != nil { - return err - } - return resourceAwsConfigOrganizationConformancePackRead(d, meta) -} -func expandConfigConformancePackExcludedAccounts(i []interface{}) (ret []*string) { - for _, v := range i { - ret = append(ret, aws.String(v.(string))) + if err := configWaitForOrganizationConformancePackStatusCreateSuccessful(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Config Organization Conformance Pack (%s) to be created: %w", d.Id(), err) } - return -} -func refreshOrganizationConformancePackStatus(d *schema.ResourceData, conn *configservice.ConfigService) func() (interface{}, string, error) { - return func() (interface{}, string, error) { - out, err := conn.DescribeOrganizationConformancePackStatuses(&configservice.DescribeOrganizationConformancePackStatusesInput{ - OrganizationConformancePackNames: []*string{aws.String(d.Id())}, - }) - if err != nil { - if awsErr, ok := err.(awserr.Error); ok && isAWSErr(awsErr, configservice.ErrCodeNoSuchOrganizationConformancePackException, "") { - return 42, "", nil - } - return 42, "", fmt.Errorf("failed to describe organization conformance pack %q: %s", d.Id(), err) - } - if len(out.OrganizationConformancePackStatuses) < 1 { - return 42, "", nil - } - status := out.OrganizationConformancePackStatuses[0] - return out, *status.Status, nil - } + return resourceAwsConfigOrganizationConformancePackRead(d, meta) } func resourceAwsConfigOrganizationConformancePackRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).configconn - out, err := conn.DescribeOrganizationConformancePacks(&configservice.DescribeOrganizationConformancePacksInput{ - OrganizationConformancePackNames: []*string{aws.String(d.Id())}, - }) + pack, err := configDescribeOrganizationConformancePack(conn, d.Id()) + + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchOrganizationConformancePackException) { + log.Printf("[WARN] Config Organization Conformance Pack (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { - if awsErr, ok := err.(awserr.Error); ok && isAWSErr(err, configservice.ErrCodeNoSuchOrganizationConformancePackException, "") { - log.Printf("[WARN] Organization Conformance Pack %q is gone (%s)", d.Id(), awsErr.Code()) - d.SetId("") - return nil - } - return err + return fmt.Errorf("error describing Config Organization Conformance Pack (%s): %w", d.Id(), err) } - numberOfPacks := len(out.OrganizationConformancePacks) - if numberOfPacks < 1 { - log.Printf("[WARN] Organization Conformance Pack %q is gone (no packs found)", d.Id()) + if pack == nil { + if d.IsNewResource() { + return fmt.Errorf("error describing Config Organization Conformance Pack (%s): not found", d.Id()) + } + + log.Printf("[WARN] Config Organization Conformance Pack (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - if numberOfPacks > 1 { - return fmt.Errorf("expected exactly 1 organization conformance pack, received %d: %#v", - numberOfPacks, out.OrganizationConformancePacks) + d.Set("arn", pack.OrganizationConformancePackArn) + d.Set("name", pack.OrganizationConformancePackName) + d.Set("delivery_s3_bucket", pack.DeliveryS3Bucket) + d.Set("delivery_s3_key_prefix", pack.DeliveryS3KeyPrefix) + + if err = d.Set("excluded_accounts", flattenStringSet(pack.ExcludedAccounts)); err != nil { + return fmt.Errorf("error setting excluded_accounts: %w", err) + } + + if err = d.Set("input_parameter", flattenConfigConformancePackInputParameters(pack.ConformancePackInputParameters)); err != nil { + return fmt.Errorf("error setting input_parameter: %w", err) } - log.Printf("[DEBUG] AWS Config organization conformance packs received: %s", out) + return nil +} + +func resourceAwsConfigOrganizationConformancePackUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).configconn - pack := out.OrganizationConformancePacks[0] - if err = d.Set("arn", pack.OrganizationConformancePackArn); err != nil { - return err + input := configservice.PutOrganizationConformancePackInput{ + OrganizationConformancePackName: aws.String(d.Id()), } - if err = d.Set("name", pack.OrganizationConformancePackName); err != nil { - return err + + if v, ok := d.GetOk("delivery_s3_bucket"); ok { + input.DeliveryS3Bucket = aws.String(v.(string)) } - if err = d.Set("delivery_s3_bucket", pack.DeliveryS3Bucket); err != nil { - return err + + if v, ok := d.GetOk("delivery_s3_key_prefix"); ok { + input.DeliveryS3KeyPrefix = aws.String(v.(string)) } - if err = d.Set("delivery_s3_key_prefix", pack.DeliveryS3KeyPrefix); err != nil { - return err + + if v, ok := d.GetOk("excluded_accounts"); ok { + input.ExcludedAccounts = expandStringSet(v.(*schema.Set)) } - if err = d.Set("excluded_accounts", pack.ExcludedAccounts); err != nil { - return err + + if v, ok := d.GetOk("input_parameter"); ok { + input.ConformancePackInputParameters = expandConfigConformancePackInputParameters(v.(*schema.Set).List()) } - if pack.ConformancePackInputParameters != nil { - if err = d.Set("input_parameters", flattenConformancePackInputParameters(pack.ConformancePackInputParameters)); err != nil { - return err - } + if v, ok := d.GetOk("template_body"); ok { + input.TemplateBody = aws.String(v.(string)) } - return nil + if v, ok := d.GetOk("template_s3_uri"); ok { + input.TemplateS3Uri = aws.String(v.(string)) + } + + _, err := conn.PutOrganizationConformancePack(&input) + if err != nil { + return fmt.Errorf("error updating Config Organization Conformance Pack (%s): %w", d.Id(), err) + } + + if err := configWaitForOrganizationConformancePackStatusUpdateSuccessful(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Config Organization Conformance Pack (%s) to be updated: %w", d.Id(), err) + } + + return resourceAwsConfigOrganizationConformancePackRead(d, meta) } func resourceAwsConfigOrganizationConformancePackDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).configconn - name := d.Get("name").(string) - - log.Printf("[DEBUG] Deleting AWS Config organization conformance pack %q", name) input := &configservice.DeleteOrganizationConformancePackInput{ - OrganizationConformancePackName: aws.String(name), + OrganizationConformancePackName: aws.String(d.Id()), } - err := resource.Retry(30*time.Minute, func() *resource.RetryError { + + err := resource.Retry(ConfigOrganizationConformancePackDeleteTimeout, func() *resource.RetryError { _, err := conn.DeleteOrganizationConformancePack(input) + if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceInUseException" { + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeResourceInUseException) { return resource.RetryableError(err) } + return resource.NonRetryableError(err) } + return nil }) - if isResourceTimeoutError(err) { + + if tfresource.TimedOut(err) { _, err = conn.DeleteOrganizationConformancePack(input) } - if err != nil { - return fmt.Errorf("deleting organization conformance pack failed: %s", err) - } - conf := resource.StateChangeConf{ - Pending: []string{ - configservice.OrganizationResourceDetailedStatusDeleteInProgress, - }, - Target: []string{""}, - Timeout: 30 * time.Minute, - Refresh: refreshOrganizationConformancePackStatus(d, conn), + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchOrganizationConformancePackException) { + return nil } - _, err = conf.WaitForState() + if err != nil { - return err + return fmt.Errorf("erorr deleting Config Organization Conformance Pack (%s): %w", d.Id(), err) } - log.Printf("[DEBUG] AWS organization conformance pack %q deleted", name) + if err := configWaitForOrganizationConformancePackStatusDeleteSuccessful(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Config Organization Conformance Pack (%s) to be deleted: %w", d.Id(), err) + } return nil } diff --git a/aws/resource_aws_config_organization_conformance_pack_test.go b/aws/resource_aws_config_organization_conformance_pack_test.go index b26a42d70258..ed86946725ad 100644 --- a/aws/resource_aws_config_organization_conformance_pack_test.go +++ b/aws/resource_aws_config_organization_conformance_pack_test.go @@ -5,7 +5,9 @@ import ( "regexp" "testing" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/configservice" + "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" @@ -14,25 +16,23 @@ import ( func testAccConfigOrganizationConformancePack_basic(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") - rId := "IAM_PASSWORD_POLICY" resourceName := "aws_config_organization_conformance_pack.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ { - Config: testAccConfigOrganizationConformancePackConfigRuleIdentifier(rName, rId), + Config: testAccConfigOrganizationConformancePackBasicConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rName))), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", ""), resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", ""), - resource.TestCheckNoResourceAttr(resourceName, "input_parameters"), - resource.TestCheckNoResourceAttr(resourceName, "excluded_accounts"), - testAccCheckConfigOrganizationConformancePackSuccessful(resourceName), + resource.TestCheckResourceAttr(resourceName, "input_parameters.#", "0"), + resource.TestCheckResourceAttr(resourceName, "excluded_accounts.#", "0"), ), }, { @@ -51,12 +51,12 @@ func testAccConfigOrganizationConformancePack_disappears(t *testing.T) { resourceName := "aws_config_organization_conformance_pack.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ { - Config: testAccConfigOrganizationConformancePackConfigRuleIdentifier(rName, "IAM_PASSWORD_POLICY"), + Config: testAccConfigOrganizationConformancePackBasicConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), testAccCheckResourceDisappears(testAccProvider, resourceAwsConfigOrganizationConformancePack(), resourceName), @@ -67,30 +67,114 @@ func testAccConfigOrganizationConformancePack_disappears(t *testing.T) { }) } -func testAccConfigOrganizationConformancePack_InputParameters(t *testing.T) { +func testAccConfigOrganizationConformancePack_excludedAccounts(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") - rId := "IAM_PASSWORD_POLICY" - pKey := "ParamKey" - pValue := "ParamValue" resourceName := "aws_config_organization_conformance_pack.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ { - Config: testAccConfigOrganizationConformancePackConfigRuleIdentifierParameter(rName, rId, pKey, pValue), + Config: testAccConfigOrganizationConformancePackExcludedAccounts1Config(rName), Check: resource.ComposeTestCheckFunc( testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), - testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rName))), - resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "excluded_accounts.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_body"}, + }, + { + Config: testAccConfigOrganizationConformancePackExcludedAccounts2Config(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + resource.TestCheckResourceAttr(resourceName, "excluded_accounts.#", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_body"}, + }, + { + Config: testAccConfigOrganizationConformancePackBasicConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + resource.TestCheckResourceAttr(resourceName, "excluded_accounts.#", "0"), + ), + }, + }, + }) +} + +func testAccConfigOrganizationConformancePack_forceNew(t *testing.T) { + var before, after configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + rNameUpdated := acctest.RandomWithPrefix("tf-acc-test-update") + resourceName := "aws_config_organization_conformance_pack.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackBasicConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &before), + ), + }, + { + Config: testAccConfigOrganizationConformancePackBasicConfig(rNameUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &after), + testAccCheckConfigOrganizationConformancePackRecreated(&before, &after), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rNameUpdated))), + resource.TestCheckResourceAttr(resourceName, "name", rNameUpdated), resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", ""), resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", ""), - resource.TestCheckResourceAttr(resourceName, "input_parameters."+pKey, pValue), - resource.TestCheckNoResourceAttr(resourceName, "excluded_accounts"), - testAccCheckConfigOrganizationConformancePackSuccessful(resourceName), + resource.TestCheckResourceAttr(resourceName, "input_parameter.#", "0"), + resource.TestCheckResourceAttr(resourceName, "excluded_accounts.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_body"}, + }, + }, + }) +} + +func testAccConfigOrganizationConformancePack_inputParameters(t *testing.T) { + var pack configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + pKey := "ParamKey" + pValue := "ParamValue" + resourceName := "aws_config_organization_conformance_pack.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackInputParameterConfig(rName, pKey, pValue), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + resource.TestCheckResourceAttr(resourceName, "input_parameters.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "input_parameters.*", map[string]string{ + "parameter_name": pKey, + "parameter_value": pValue, + }), ), }, { @@ -106,26 +190,20 @@ func testAccConfigOrganizationConformancePack_InputParameters(t *testing.T) { func testAccConfigOrganizationConformancePack_S3Delivery(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") - bName := "awsconfigconforms" + rName - rId := "IAM_PASSWORD_POLICY" + bucketName := acctest.RandomWithPrefix("awsconfigconforms") resourceName := "aws_config_organization_conformance_pack.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ { - Config: testAccConfigOrganizationConformancePackConfigRuleIdentifierS3Delivery(rName, rId, bName), + Config: testAccConfigOrganizationConformancePackS3DeliveryConfig(rName, bucketName), Check: resource.ComposeTestCheckFunc( testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), - testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rName))), - resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", bName), - resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", rId), - resource.TestCheckNoResourceAttr(resourceName, "input_parameters"), - resource.TestCheckNoResourceAttr(resourceName, "excluded_accounts"), - testAccCheckConfigOrganizationConformancePackSuccessful(resourceName), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", bucketName), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", rName), ), }, { @@ -141,27 +219,23 @@ func testAccConfigOrganizationConformancePack_S3Delivery(t *testing.T) { func testAccConfigOrganizationConformancePack_S3Template(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") - bName := rName - kName := rName + ".yaml" - rId := "IAM_PASSWORD_POLICY" resourceName := "aws_config_organization_conformance_pack.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccOrganizationsMasterPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ { - Config: testAccConfigOrganizationConformancePackConfigRuleIdentifierS3Template(rName, rId, bName, kName), + Config: testAccConfigOrganizationConformancePackS3TemplateConfig(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rName))), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", ""), resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", ""), - resource.TestCheckNoResourceAttr(resourceName, "input_parameters"), - resource.TestCheckNoResourceAttr(resourceName, "excluded_accounts"), - testAccCheckConfigOrganizationConformancePackSuccessful(resourceName), + resource.TestCheckResourceAttr(resourceName, "input_parameters.#", "0"), + resource.TestCheckResourceAttr(resourceName, "excluded_accounts.#", "0"), ), }, { @@ -174,35 +248,145 @@ func testAccConfigOrganizationConformancePack_S3Template(t *testing.T) { }) } -func testAccConfigOrganizationConformancePack_ExcludedAccounts(t *testing.T) { +func testAccConfigOrganizationConformancePack_updateInputParameters(t *testing.T) { var pack configservice.OrganizationConformancePack rName := acctest.RandomWithPrefix("tf-acc-test") - rId := "IAM_PASSWORD_POLICY" resourceName := "aws_config_organization_conformance_pack.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccOrganizationsMasterPreCheck(t) - testAccOrganizationsMinAccountsPreCheck(t, 2) - // TODO: All accounts in the organization must also have configuration recorders in the current region, - // which is a little complicated for a precheck. If you get an 'unexpected state' error with this - // test, try enabling configuration recorders across the org. + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackInputParameterConfig(rName, "TestKey", "TestValue"), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + ), + }, + { + Config: testAccConfigOrganizationConformancePackUpdateInputParameterConfig(rName, "TestKey1", "TestKey2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + resource.TestCheckResourceAttr(resourceName, "input_parameter.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "input_parameter.*", map[string]string{ + "parameter_name": "TestKey1", + "parameter_value": "TestValue1", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "input_parameter.*", map[string]string{ + "parameter_name": "TestKey2", + "parameter_value": "TestValue2", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_body"}, + }, + { + Config: testAccConfigOrganizationConformancePackBasicConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + resource.TestCheckResourceAttr(resourceName, "input_parameter.#", "0"), + ), + }, }, + }) +} + +func testAccConfigOrganizationConformancePack_updateS3Delivery(t *testing.T) { + var pack configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + bucketName := acctest.RandomWithPrefix("awsconfigconforms") + updatedBucketName := fmt.Sprintf("%s-update", bucketName) + resourceName := "aws_config_organization_conformance_pack.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ { - Config: testAccConfigOrganizationConformancePackConfigRuleIdentifierExcludedAccounts(rName, rId), + Config: testAccConfigOrganizationConformancePackS3DeliveryConfig(rName, bucketName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", bucketName), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", rName), + ), + }, + { + Config: testAccConfigOrganizationConformancePackS3DeliveryConfig(rName, updatedBucketName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", updatedBucketName), + resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", rName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_body"}, + }, + }, + }) +} + +func testAccConfigOrganizationConformancePack_updateS3Template(t *testing.T) { + var pack configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + bucketName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_config_organization_conformance_pack.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackS3TemplateConfig(rName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + ), + }, + { + Config: testAccConfigOrganizationConformancePackS3TemplateConfig(rName, bucketName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"template_s3_uri"}, + }, + }, + }) +} + +func testAccConfigOrganizationConformancePack_updateTemplateBody(t *testing.T) { + var pack configservice.OrganizationConformancePack + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_config_organization_conformance_pack.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, + Steps: []resource.TestStep{ + { + Config: testAccConfigOrganizationConformancePackBasicConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), + ), + }, + { + Config: testAccConfigOrganizationConformancePackUpdateConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), - testAccMatchResourceAttrRegionalARN(resourceName, "arn", "config", regexp.MustCompile(fmt.Sprintf("organization-conformance-pack/%s-.+", rName))), - resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", ""), - resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", ""), - resource.TestCheckNoResourceAttr(resourceName, "input_parameters"), - resource.TestCheckResourceAttr(resourceName, "excluded_accounts.#", "1"), - testAccCheckConfigOrganizationConformancePackSuccessful(resourceName), ), }, { @@ -223,25 +407,25 @@ func testAccCheckConfigOrganizationConformancePackDestroy(s *terraform.State) er continue } - rule, err := configDescribeOrganizationConformancePack(conn, rs.Primary.ID) + pack, err := configDescribeOrganizationConformancePack(conn, rs.Primary.ID) - if isAWSErr(err, configservice.ErrCodeNoSuchOrganizationConformancePackException, "") { + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchOrganizationConformancePackException) { continue } if err != nil { - return fmt.Errorf("error describing Config Organization Managed Rule (%s): %s", rs.Primary.ID, err) + return fmt.Errorf("error describing Config Organization Conformance Pack (%s): %w", rs.Primary.ID, err) } - if rule != nil { - return fmt.Errorf("Config Organization Managed Rule (%s) still exists", rs.Primary.ID) + if pack != nil { + return fmt.Errorf("Config Organization Conformance Pack (%s) still exists", rs.Primary.ID) } } return nil } -func testAccCheckConfigOrganizationConformancePackExists(resourceName string, ocr *configservice.OrganizationConformancePack) resource.TestCheckFunc { +func testAccCheckConfigOrganizationConformancePackExists(resourceName string, ocp *configservice.OrganizationConformancePack) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -253,61 +437,31 @@ func testAccCheckConfigOrganizationConformancePackExists(resourceName string, oc pack, err := configDescribeOrganizationConformancePack(conn, rs.Primary.ID) if err != nil { - return fmt.Errorf("error describing organization conformance pack (%s): %s", rs.Primary.ID, err) + return fmt.Errorf("error describing Config Organization Conformance Pack (%s): %w", rs.Primary.ID, err) } if pack == nil { - return fmt.Errorf("organization conformance pack (%s) not found", rs.Primary.ID) + return fmt.Errorf("Config Organization Conformance Pack (%s) not found", rs.Primary.ID) } - *ocr = *pack + *ocp = *pack return nil } } -func testAccCheckConfigOrganizationConformancePackSuccessful(resourceName string) resource.TestCheckFunc { +func testAccCheckConfigOrganizationConformancePackRecreated(before, after *configservice.OrganizationConformancePack) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[resourceName] - if !ok { - return fmt.Errorf("Not Found: %s", resourceName) - } - - conn := testAccProvider.Meta().(*AWSClient).configconn - - packStatus, err := configDescribeOrganizationConformancePackStatus(conn, rs.Primary.ID) - if err != nil { - return fmt.Errorf("error describing organization conformance pack status (%s): %s", rs.Primary.ID, err) + if aws.StringValue(before.OrganizationConformancePackArn) == aws.StringValue(after.OrganizationConformancePackArn) { + return fmt.Errorf("AWS Config Organization Conformance Pack was not recreated") } - if packStatus == nil { - return fmt.Errorf("organization conformance pack status (%s) not found", rs.Primary.ID) - } - if *packStatus.Status != configservice.OrganizationResourceStatusCreateSuccessful { - return fmt.Errorf("organization conformance pack (%s) returned %s status (%s): %s", rs.Primary.ID, *packStatus.Status, *packStatus.ErrorCode, *packStatus.ErrorMessage) - } - - detailedStatus, err := configDescribeOrganizationConformancePackDetailedStatus(conn, rs.Primary.ID) - if err != nil { - return fmt.Errorf("error describing organization conformance pack detailed status (%s): %s", rs.Primary.ID, err) - } - if detailedStatus == nil { - return fmt.Errorf("organization conformance pack detailed status (%s) not found", rs.Primary.ID) - } - for _, s := range detailedStatus { - if *s.Status != configservice.OrganizationResourceDetailedStatusCreateSuccessful { - return fmt.Errorf("organization conformance pack (%s) on account %s returned %s status (%s): %s", rs.Primary.ID, *s.Status, *s.AccountId, *s.ErrorCode, *s.ErrorMessage) - } - } - return nil } } func testAccConfigOrganizationConformancePackBase(rName string) string { return fmt.Sprintf(` - -data "aws_partition" "current" { -} +data "aws_partition" "current" {} resource "aws_config_configuration_recorder" "test" { depends_on = [aws_iam_role_policy_attachment.test] @@ -339,15 +493,19 @@ resource "aws_iam_role_policy_attachment" "test" { role = aws_iam_role.test.name } +resource "aws_organizations_organization" "test" { + aws_service_access_principals = ["config-multiaccountsetup.${data.aws_partition.current.dns_suffix}"] + feature_set = "ALL" +} `, rName) } -func testAccConfigOrganizationConformancePackConfigRuleIdentifier(rName, ruleIdentifier string) string { - return fmt.Sprintf(` -%[3]s - +func testAccConfigOrganizationConformancePackBasicConfig(rName string) string { + return composeConfig( + testAccConfigOrganizationConformancePackBase(rName), + fmt.Sprintf(` resource "aws_config_organization_conformance_pack" "test" { - depends_on = [aws_config_configuration_recorder.test] + depends_on = [aws_config_configuration_recorder.test, aws_organizations_organization.test] name = %[1]q template_body = < **NOTE:** This resource must be created in the Organization master account or a delegate administrator account and rules will include the master account unless its ID is added to the `excluded_accounts` argument. +~> **NOTE:** This resource must be created in the Organization master account or a delegated administrator account, and the Organization must have all features enabled. Every Organization account except those configured in the `excluded_accounts` argument must have a Configuration Recorder with proper IAM permissions before the Organization Conformance Pack will successfully create or update. See also the [`aws_config_configuration_recorder` resource](/docs/providers/aws/r/config_configuration_recorder.html). -~> **NOTE:** Every Organization account except those configured in the `excluded_accounts` argument must have a Configuration Recorder with proper IAM permissions before the rule will successfully create or update. See also the [`aws_config_configuration_recorder` resource](/docs/providers/aws/r/config_configuration_recorder.html). - -## Example Usage +## Example Usage with Template Body ```hcl -resource "aws_config_organization_conformance_pack" "test" { - name = "example" +resource "aws_config_organization_conformance_pack" "example" { + name = "example" + + input_parameter { + parameter_name = "AccessKeysRotatedParameterMaxAccessKeyAge" + parameter_value = "90" + } + template_body = < Date: Fri, 16 Apr 2021 01:34:37 -0400 Subject: [PATCH 0030/1208] additional exception handling --- aws/config.go | 14 +++++++++++++ aws/configservice.go | 11 ++++------ ...ws_config_organization_conformance_pack.go | 20 ++----------------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/aws/config.go b/aws/config.go index 6ccc48f11429..f9111cfd21a5 100644 --- a/aws/config.go +++ b/aws/config.go @@ -705,6 +705,20 @@ func (c *Config) Client() (interface{}, error) { return } + // We only want to retry briefly as the default max retry count would + // excessively retry when the error could be legitimate. + // We currently depend on the DefaultRetryer exponential backoff here. + // ~10 retries gives a fair backoff of a few seconds. + if r.RetryCount < 9 { + r.Retryable = aws.Bool(true) + } else { + r.Retryable = aws.Bool(false) + } + case "PutOrganizationConformancePack", "DeleteOrganizationConformancePack", "DescribeOrganizationConformancePackStatuses": + if !tfawserr.ErrCodeEquals(r.Error, configservice.ErrCodeOrganizationAccessDeniedException) { + return + } + // We only want to retry briefly as the default max retry count would // excessively retry when the error could be legitimate. // We currently depend on the DefaultRetryer exponential backoff here. diff --git a/aws/configservice.go b/aws/configservice.go index e03ba2e69666..124a5728c9a7 100644 --- a/aws/configservice.go +++ b/aws/configservice.go @@ -21,9 +21,6 @@ const ( ConfigConformancePackStatusNotFound = "NotFound" ConfigConformancePackStatusUnknown = "Unknown" - - ConfigOrganizationConformancePackStatusNotFound = "NotFound" - ConfigOrganizationConformancePackStatusUnknown = "Unknown" ) func configDescribeConformancePack(conn *configservice.ConfigService, name string) (*configservice.ConformancePackDetail, error) { @@ -318,11 +315,11 @@ func configRefreshOrganizationConformancePackStatus(conn *configservice.ConfigSe status, err := configDescribeOrganizationConformancePackStatus(conn, name) if err != nil { - return nil, ConfigOrganizationConformancePackStatusUnknown, err + return nil, "", err } if status == nil { - return nil, ConfigOrganizationConformancePackStatusNotFound, nil + return nil, "", nil } if status.ErrorCode != nil { @@ -388,8 +385,8 @@ func configWaitForOrganizationConformancePackStatusCreateSuccessful(conn *config Target: []string{configservice.OrganizationResourceStatusCreateSuccessful}, Timeout: ConfigOrganizationConformancePackCreateTimeout, Refresh: configRefreshOrganizationConformancePackStatus(conn, name), - // Include a Delay to avoid transient error i.e. OrganizationAccessDeniedException - Delay: 1 * time.Minute, + // Include a Delay to avoid transient error + Delay: 30 * time.Second, } _, err := stateChangeConf.WaitForState() diff --git a/aws/resource_aws_config_organization_conformance_pack.go b/aws/resource_aws_config_organization_conformance_pack.go index 356423e34b21..7f98d636f952 100644 --- a/aws/resource_aws_config_organization_conformance_pack.go +++ b/aws/resource_aws_config_organization_conformance_pack.go @@ -134,24 +134,7 @@ func resourceAwsConfigOrganizationConformancePackCreate(d *schema.ResourceData, input.TemplateS3Uri = aws.String(v.(string)) } - err := resource.Retry(ConfigOrganizationConformancePackCreateTimeout, func() *resource.RetryError { - _, err := conn.PutOrganizationConformancePack(&input) - - if err != nil { - // OrganizationAccessDeniedException seems to be a transient error - if tfawserr.ErrCodeEquals(err, configservice.ErrCodeOrganizationAccessDeniedException) { - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) - } - - return nil - }) - - if tfresource.TimedOut(err) { - _, err = conn.PutOrganizationConformancePack(&input) - } + _, err := conn.PutOrganizationConformancePack(&input) if err != nil { return fmt.Errorf("error creating Config Organization Conformance Pack (%s): %w", name, err) @@ -239,6 +222,7 @@ func resourceAwsConfigOrganizationConformancePackUpdate(d *schema.ResourceData, } _, err := conn.PutOrganizationConformancePack(&input) + if err != nil { return fmt.Errorf("error updating Config Organization Conformance Pack (%s): %w", d.Id(), err) } From 23adde265773d1e624e10c02b252e2c12e92622e Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Fri, 16 Apr 2021 02:02:49 -0400 Subject: [PATCH 0031/1208] add test ErrorChecks; docs --- ...e_aws_config_organization_conformance_pack_test.go | 11 +++++++++++ ...config_organization_conformance_pack.html.markdown | 8 +++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_config_organization_conformance_pack_test.go b/aws/resource_aws_config_organization_conformance_pack_test.go index ed86946725ad..d4ac03ea8d7b 100644 --- a/aws/resource_aws_config_organization_conformance_pack_test.go +++ b/aws/resource_aws_config_organization_conformance_pack_test.go @@ -20,6 +20,7 @@ func testAccConfigOrganizationConformancePack_basic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ @@ -52,6 +53,7 @@ func testAccConfigOrganizationConformancePack_disappears(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ @@ -74,6 +76,7 @@ func testAccConfigOrganizationConformancePack_excludedAccounts(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ @@ -122,6 +125,7 @@ func testAccConfigOrganizationConformancePack_forceNew(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ @@ -163,6 +167,7 @@ func testAccConfigOrganizationConformancePack_inputParameters(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ @@ -195,6 +200,7 @@ func testAccConfigOrganizationConformancePack_S3Delivery(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ @@ -223,6 +229,7 @@ func testAccConfigOrganizationConformancePack_S3Template(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ @@ -255,6 +262,7 @@ func testAccConfigOrganizationConformancePack_updateInputParameters(t *testing.T resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ @@ -305,6 +313,7 @@ func testAccConfigOrganizationConformancePack_updateS3Delivery(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ @@ -342,6 +351,7 @@ func testAccConfigOrganizationConformancePack_updateS3Template(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ @@ -374,6 +384,7 @@ func testAccConfigOrganizationConformancePack_updateTemplateBody(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, configservice.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckConfigOrganizationConformancePackDestroy, Steps: []resource.TestStep{ diff --git a/website/docs/r/config_organization_conformance_pack.html.markdown b/website/docs/r/config_organization_conformance_pack.html.markdown index 843f793b53bb..b37989965586 100644 --- a/website/docs/r/config_organization_conformance_pack.html.markdown +++ b/website/docs/r/config_organization_conformance_pack.html.markdown @@ -12,7 +12,9 @@ Manages a Config Organization Conformance Pack. More information can be found in ~> **NOTE:** This resource must be created in the Organization master account or a delegated administrator account, and the Organization must have all features enabled. Every Organization account except those configured in the `excluded_accounts` argument must have a Configuration Recorder with proper IAM permissions before the Organization Conformance Pack will successfully create or update. See also the [`aws_config_configuration_recorder` resource](/docs/providers/aws/r/config_configuration_recorder.html). -## Example Usage with Template Body +## Example Usage + +### Using Template Body ```hcl resource "aws_config_organization_conformance_pack" "example" { @@ -46,7 +48,7 @@ resource "aws_organizations_organization" "example" { } ``` -## Example Usage with Template S3 URI +### Using Template S3 URI ```hcl resource "aws_config_organization_conformance_pack" "example" { @@ -102,7 +104,7 @@ The `input_parameter` configuration block supports the following arguments: ## Attributes Reference -In addition to all arguments above (except for `template_body` and `template_s3_uri`), the following attributes are exported: +In addition to all arguments above, the following attributes are exported: * `arn` - Amazon Resource Name (ARN) of the organization conformance pack. From 6f86f40a931bf14bc15363fa3cfe259dbc228f23 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Mon, 10 May 2021 21:20:24 +0900 Subject: [PATCH 0032/1208] feat: add a resource aws_appconfig_environment --- aws/provider.go | 1 + aws/resource_aws_appconfig_environment.go | 167 ++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 aws/resource_aws_appconfig_environment.go diff --git a/aws/provider.go b/aws/provider.go index 7d7c14c9309b..2d574e62657c 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -457,6 +457,7 @@ func Provider() *schema.Provider { "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), "aws_appautoscaling_scheduled_action": resourceAwsAppautoscalingScheduledAction(), "aws_appconfig_application": resourceAwsAppconfigApplication(), + "aws_appconfig_environment": resourceAwsAppconfigEnvironment(), "aws_appmesh_gateway_route": resourceAwsAppmeshGatewayRoute(), "aws_appmesh_mesh": resourceAwsAppmeshMesh(), "aws_appmesh_route": resourceAwsAppmeshRoute(), diff --git a/aws/resource_aws_appconfig_environment.go b/aws/resource_aws_appconfig_environment.go new file mode 100644 index 000000000000..bce9b0874882 --- /dev/null +++ b/aws/resource_aws_appconfig_environment.go @@ -0,0 +1,167 @@ +package aws + +import ( + "fmt" + "log" + "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 resourceAwsAppconfigEnvironment() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAppconfigEnvironmentCreate, + Read: resourceAwsAppconfigEnvironmentRead, + Update: resourceAwsAppconfigEnvironmentUpdate, + Delete: resourceAwsAppconfigEnvironmentDelete, + Importer: &schema.ResourceImporter{ + State: resourceAwsAppconfigEnvironmentImport, + }, + + 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), + ), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(0, 1024), + ), + }, + // TODO monitors + "tags": tagsSchema(), + }, + } +} + +func resourceAwsAppconfigEnvironmentCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + input := &appconfig.CreateEnvironmentInput{ + Name: aws.String(d.Get("name").(string)), + Description: aws.String(d.Get("description").(string)), + ApplicationId: aws.String(d.Get("application_id").(string)), + // TODO tags + // TODO monitors + } + + environment, err := conn.CreateEnvironment(input) + if err != nil { + return fmt.Errorf("Error creating AppConfig Environment: %s", err) + } + + d.SetId(aws.StringValue(environment.Id)) + + return resourceAwsAppconfigEnvironmentRead(d, meta) +} + +func resourceAwsAppconfigEnvironmentRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + input := &appconfig.GetEnvironmentInput{ + ApplicationId: aws.String(d.Get("application_id").(string)), + EnvironmentId: aws.String(d.Id()), + } + + output, err := conn.GetEnvironment(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Appconfig Environment (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error getting AppConfig Environment (%s): %s", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting AppConfig Environment (%s): empty response", d.Id()) + } + + d.Set("name", output.Name) + d.Set("description", output.Description) + d.Set("application_id", output.ApplicationId) + // TODO tags + // TODO monitors + + return nil +} + +func resourceAwsAppconfigEnvironmentUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + updateInput := &appconfig.UpdateEnvironmentInput{ + EnvironmentId: aws.String(d.Id()), + ApplicationId: aws.String(d.Get("application_id").(string)), + } + + if d.HasChange("description") { + _, n := d.GetChange("description") + updateInput.Description = aws.String(n.(string)) + } + + if d.HasChange("name") { + _, n := d.GetChange("name") + updateInput.Name = aws.String(n.(string)) + } + + // TODO tags + // TODO monitors + + _, err := conn.UpdateEnvironment(updateInput) + if err != nil { + return fmt.Errorf("error updating AppConfig Environment(%s): %s", d.Id(), err) + } + + return resourceAwsAppconfigEnvironmentRead(d, meta) +} + +func resourceAwsAppconfigEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appconfigconn + + input := &appconfig.DeleteEnvironmentInput{ + EnvironmentId: aws.String(d.Id()), + ApplicationId: aws.String(d.Get("application_id").(string)), + } + + _, err := conn.DeleteEnvironment(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Appconfig Environment (%s): %s", d.Id(), err) + } + + return nil +} + +func resourceAwsAppconfigEnvironmentImport(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/environment-id'", d.Id()) + } + + d.SetId(parts[1]) + d.Set("application_id", parts[0]) + + return []*schema.ResourceData{d}, nil +} From 542f15184dfb048004832a368057741709d9b58c Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Mon, 10 May 2021 22:34:52 +0900 Subject: [PATCH 0033/1208] feat: support tags of AppConfig Environment --- aws/resource_aws_appconfig_environment.go | 39 ++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_appconfig_environment.go b/aws/resource_aws_appconfig_environment.go index bce9b0874882..ea757c151e30 100644 --- a/aws/resource_aws_appconfig_environment.go +++ b/aws/resource_aws_appconfig_environment.go @@ -6,9 +6,11 @@ import ( "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 resourceAwsAppconfigEnvironment() *schema.Resource { @@ -46,6 +48,10 @@ func resourceAwsAppconfigEnvironment() *schema.Resource { }, // TODO monitors "tags": tagsSchema(), + "arn": { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -57,7 +63,7 @@ func resourceAwsAppconfigEnvironmentCreate(d *schema.ResourceData, meta interfac Name: aws.String(d.Get("name").(string)), Description: aws.String(d.Get("description").(string)), ApplicationId: aws.String(d.Get("application_id").(string)), - // TODO tags + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), // TODO monitors } @@ -73,9 +79,12 @@ func resourceAwsAppconfigEnvironmentCreate(d *schema.ResourceData, meta interfac func resourceAwsAppconfigEnvironmentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + appID := d.Get("application_id").(string) input := &appconfig.GetEnvironmentInput{ - ApplicationId: aws.String(d.Get("application_id").(string)), + ApplicationId: aws.String(appID), EnvironmentId: aws.String(d.Id()), } @@ -98,9 +107,26 @@ func resourceAwsAppconfigEnvironmentRead(d *schema.ResourceData, meta interface{ d.Set("name", output.Name) d.Set("description", output.Description) d.Set("application_id", output.ApplicationId) - // TODO tags // TODO monitors + environmentARN := arn.ARN{ + AccountID: meta.(*AWSClient).accountid, + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("application/%s/environment/%s", appID, d.Id()), + Service: "appconfig", + }.String() + d.Set("arn", environmentARN) + + tags, err := keyvaluetags.AppconfigListTags(conn, environmentARN) + if err != nil { + return fmt.Errorf("error getting tags for AppConfig Environment (%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 } @@ -122,7 +148,12 @@ func resourceAwsAppconfigEnvironmentUpdate(d *schema.ResourceData, meta interfac updateInput.Name = aws.String(n.(string)) } - // TODO tags + 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) + } + } // TODO monitors _, err := conn.UpdateEnvironment(updateInput) From 7f31e81c2828a4be53a0264616e20ca9fc1107e5 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Mon, 10 May 2021 23:14:56 +0900 Subject: [PATCH 0034/1208] feat: support monitors of AppConfig Environment --- aws/resource_aws_appconfig_environment.go | 62 ++++++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_appconfig_environment.go b/aws/resource_aws_appconfig_environment.go index ea757c151e30..8ac430b4df63 100644 --- a/aws/resource_aws_appconfig_environment.go +++ b/aws/resource_aws_appconfig_environment.go @@ -46,12 +46,34 @@ func resourceAwsAppconfigEnvironment() *schema.Resource { validation.StringLenBetween(0, 1024), ), }, - // TODO monitors "tags": tagsSchema(), "arn": { Type: schema.TypeString, Computed: true, }, + "monitors": { + Type: schema.TypeList, + Optional: true, + MaxItems: 5, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "alarm_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(20, 2048), + ), + }, + "alarm_role_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.All( + validation.StringLenBetween(20, 2048), + ), + }, + }, + }, + }, }, } } @@ -64,7 +86,7 @@ func resourceAwsAppconfigEnvironmentCreate(d *schema.ResourceData, meta interfac Description: aws.String(d.Get("description").(string)), ApplicationId: aws.String(d.Get("application_id").(string)), Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), - // TODO monitors + Monitors: expandAppconfigEnvironmentMonitors(d.Get("monitors").([]interface{})), } environment, err := conn.CreateEnvironment(input) @@ -77,6 +99,29 @@ func resourceAwsAppconfigEnvironmentCreate(d *schema.ResourceData, meta interfac return resourceAwsAppconfigEnvironmentRead(d, meta) } +func expandAppconfigEnvironmentMonitors(list []interface{}) []*appconfig.Monitor { + monitors := make([]*appconfig.Monitor, len(list)) + for i, monitorInterface := range list { + m := monitorInterface.(map[string]interface{}) + monitors[i] = &appconfig.Monitor{ + AlarmArn: aws.String(m["alarm_arn"].(string)), + AlarmRoleArn: aws.String(m["alarm_role_arn"].(string)), + } + } + return monitors +} + +func flattenAwsAppconfigEnvironmentMonitors(monitors []*appconfig.Monitor) []interface{} { + list := make([]interface{}, len(monitors)) + for i, monitor := range monitors { + list[i] = map[string]interface{}{ + "alarm_arn": aws.StringValue(monitor.AlarmArn), + "alarm_role_arn": aws.StringValue(monitor.AlarmRoleArn), + } + } + return list +} + func resourceAwsAppconfigEnvironmentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig @@ -107,7 +152,7 @@ func resourceAwsAppconfigEnvironmentRead(d *schema.ResourceData, meta interface{ d.Set("name", output.Name) d.Set("description", output.Description) d.Set("application_id", output.ApplicationId) - // TODO monitors + d.Set("monitors", flattenAwsAppconfigEnvironmentMonitors(output.Monitors)) environmentARN := arn.ARN{ AccountID: meta.(*AWSClient).accountid, @@ -139,13 +184,11 @@ func resourceAwsAppconfigEnvironmentUpdate(d *schema.ResourceData, meta interfac } if d.HasChange("description") { - _, n := d.GetChange("description") - updateInput.Description = aws.String(n.(string)) + updateInput.Description = aws.String(d.Get("description").(string)) } if d.HasChange("name") { - _, n := d.GetChange("name") - updateInput.Name = aws.String(n.(string)) + updateInput.Name = aws.String(d.Get("name").(string)) } if d.HasChange("tags") { @@ -154,7 +197,10 @@ func resourceAwsAppconfigEnvironmentUpdate(d *schema.ResourceData, meta interfac return fmt.Errorf("error updating AppConfig (%s) tags: %s", d.Id(), err) } } - // TODO monitors + + if d.HasChange("monitors") { + updateInput.Monitors = expandAppconfigEnvironmentMonitors(d.Get("monitors").([]interface{})) + } _, err := conn.UpdateEnvironment(updateInput) if err != nil { From 3b973d5915886f4132c1bd281ed4ba7a1cb0b08a Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Mon, 10 May 2021 23:31:33 +0900 Subject: [PATCH 0035/1208] docs: add document for aws_appconfig_environment --- .../r/appconfig_environment.html.markdown | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 website/docs/r/appconfig_environment.html.markdown diff --git a/website/docs/r/appconfig_environment.html.markdown b/website/docs/r/appconfig_environment.html.markdown new file mode 100644 index 000000000000..8b4b9135e807 --- /dev/null +++ b/website/docs/r/appconfig_environment.html.markdown @@ -0,0 +1,68 @@ +--- +subcategory: "AppConfig" +layout: "aws" +page_title: "AWS: aws_appconfig_environment" +description: |- + Provides an AppConfig Environment resource. +--- + +# Resource: aws_appconfig_environment + +Provides an AppConfig Environment resource. + +## Example Usage + +### AppConfig Environment + +```hcl +resource "aws_appconfig_environment" "production" { + name = "production" + description = "Production" + application_id = aws_appconfig_application.test.id + tags = { + Type = "Production" + } + monitors { + alarm_arn = "arn:aws:cloudwatch:us-east-1:111111111111:alarm:test-appconfig" + alarm_role_arn = "arn:aws:iam::111111111111:role/service-role/test-appconfig" + } +} + +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. +- `monitors` - (Optional) Amazon CloudWatch alarms to monitor during the deployment process. Detailed below. +- `tags` - (Optional) A map of tags to assign to the resource. + +### monitor + +- `alarm_arn` - (Optional) ARN of the Amazon CloudWatch alarm. Must be between 20 and 2048 characters in length. +- `alarm_role_arn` - (Optional) ARN of an IAM role for AWS AppConfig to monitor AlarmArn. Must be between 20 and 2048 characters in length. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +- `arn` - The Amazon Resource Name (ARN) of the AppConfig Environment. +- `id` - The AppConfig Environment ID + +## Import + +`aws_appconfig_environment` can be imported by the Application ID and Environment ID, e.g. + +``` +$ terraform import aws_appconfig_environment.production 71abcde/11xxxxx +``` From 543c60c0dda07dba353bd870d12abd206a21baf1 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 08:14:06 +0900 Subject: [PATCH 0036/1208] test: add tests of aws_appconfig_environment --- ...resource_aws_appconfig_environment_test.go | 287 ++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 aws/resource_aws_appconfig_environment_test.go diff --git a/aws/resource_aws_appconfig_environment_test.go b/aws/resource_aws_appconfig_environment_test.go new file mode 100644 index 000000000000..17d2da94047b --- /dev/null +++ b/aws/resource_aws_appconfig_environment_test.go @@ -0,0 +1,287 @@ +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 TestAccAWSAppConfigEnvironment_basic(t *testing.T) { + var environment appconfig.GetEnvironmentOutput + roleName := acctest.RandomWithPrefix("tf-acc-test") + alarmName := acctest.RandomWithPrefix("tf-acc-test") + appName := acctest.RandomWithPrefix("tf-acc-test") + appDesc := acctest.RandomWithPrefix("desc") + envName := acctest.RandomWithPrefix("tf-acc-test") + envDesc := acctest.RandomWithPrefix("desc") + resourceName := "aws_appconfig_environment.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigEnvironmentWithMonitors(roleName, alarmName, appName, appDesc, envName, envDesc), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName, &environment), + resource.TestCheckResourceAttr(resourceName, "name", envName), + testAccCheckAWSAppConfigEnvironmentARN(resourceName, &environment), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "description", envDesc), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigEnvironment_disappears(t *testing.T) { + var environment appconfig.GetEnvironmentOutput + + appName := acctest.RandomWithPrefix("tf-acc-test") + appDesc := acctest.RandomWithPrefix("desc") + envName := acctest.RandomWithPrefix("tf-acc-test") + envDesc := acctest.RandomWithPrefix("desc") + resourceName := "aws_appconfig_application.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigEnvironment(appName, appDesc, envName, envDesc), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName, &environment), + testAccCheckAWSAppConfigEnvironmentDisappears(&environment), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSAppConfigEnvironment_Tags(t *testing.T) { + var environment appconfig.GetEnvironmentOutput + + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appconfig_environment.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigEnvironmentTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName, &environment), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigEnvironmentTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName, &environment), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSAppConfigEnvironmentTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName, &environment), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func testAccCheckAppConfigEnvironmentDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_appconfig_environment" { + continue + } + + input := &appconfig.GetEnvironmentInput{ + ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), + EnvironmentId: aws.String(rs.Primary.ID), + } + + output, err := conn.GetEnvironment(input) + + if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + continue + } + + if err != nil { + return err + } + + if output != nil { + return fmt.Errorf("AppConfig Environment (%s) still exists", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckAWSAppConfigEnvironmentDisappears(environment *appconfig.GetEnvironmentOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).appconfigconn + + _, err := conn.DeleteEnvironment(&appconfig.DeleteEnvironmentInput{ + ApplicationId: environment.ApplicationId, + EnvironmentId: environment.Id, + }) + + return err + } +} + +func testAccCheckAWSAppConfigEnvironmentExists(resourceName string, environment *appconfig.GetEnvironmentOutput) 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.GetEnvironment(&appconfig.GetEnvironmentInput{ + ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), + EnvironmentId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + *environment = *output + + return nil + } +} + +func testAccCheckAWSAppConfigEnvironmentARN(resourceName string, environment *appconfig.GetEnvironmentOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + return testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appconfig", fmt.Sprintf("application/%s/environment/%s", aws.StringValue(environment.ApplicationId), aws.StringValue(environment.Id)))(s) + } +} + +func testAccAWSAppConfigEnvironmentWithMonitors(roleName, alarmName, appName, appDesc, envName, envDesc string) string { + return testAccAWSAppConfigMonitor_ServiceRole(roleName) + testAccAWSCloudWatchMetricAlarmConfig(alarmName) + testAccAWSAppConfigApplicationName(appName, appDesc) + fmt.Sprintf(` +resource "aws_appconfig_environment" "test" { + name = %[1]q + description = %[2]q + application_id = aws_appconfig_application.test + + monitors { + alarm_arn = aws_cloudwatch_metric_alarm.test.arn + alarm_role_arn = aws_iam_role.test.arn + } +} +`, envName, envDesc) +} + +func testAccAWSAppConfigEnvironment(appName, appDesc, envName, envDesc string) string { + return testAccAWSAppConfigApplicationName(appName, appDesc) + fmt.Sprintf(` +resource "aws_appconfig_environment" "test" { + name = %[1]q + description = %[2]q + application_id = aws_appconfig_application.test +} +`, envName, envDesc) +} + +func testAccAWSAppConfigEnvironmentTags1(rName, tagKey1, tagValue1 string) string { + return testAccAWSAppConfigApplicationTags1(rName, tagKey1, tagValue1) + fmt.Sprintf(` +resource "aws_appconfig_environment" "test" { + name = %[1]q + application_id = aws_appconfig_application.test.id + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccAWSAppConfigEnvironmentTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return testAccAWSAppConfigApplicationTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2) + fmt.Sprintf(` +resource "aws_appconfig_environment" "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 testAccAWSAppConfigMonitor_ServiceRole(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "test" { + name = "%s" + + assume_role_policy = < Date: Tue, 11 May 2021 09:48:47 +0900 Subject: [PATCH 0037/1208] fix: fix tests --- aws/resource_aws_appconfig_environment_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_appconfig_environment_test.go b/aws/resource_aws_appconfig_environment_test.go index 17d2da94047b..a663c90ecfdc 100644 --- a/aws/resource_aws_appconfig_environment_test.go +++ b/aws/resource_aws_appconfig_environment_test.go @@ -197,7 +197,7 @@ func testAccAWSAppConfigEnvironmentWithMonitors(roleName, alarmName, appName, ap resource "aws_appconfig_environment" "test" { name = %[1]q description = %[2]q - application_id = aws_appconfig_application.test + application_id = aws_appconfig_application.test.id monitors { alarm_arn = aws_cloudwatch_metric_alarm.test.arn @@ -212,7 +212,7 @@ func testAccAWSAppConfigEnvironment(appName, appDesc, envName, envDesc string) s resource "aws_appconfig_environment" "test" { name = %[1]q description = %[2]q - application_id = aws_appconfig_application.test + application_id = aws_appconfig_application.test.id } `, envName, envDesc) } @@ -221,7 +221,7 @@ func testAccAWSAppConfigEnvironmentTags1(rName, tagKey1, tagValue1 string) strin return testAccAWSAppConfigApplicationTags1(rName, tagKey1, tagValue1) + fmt.Sprintf(` resource "aws_appconfig_environment" "test" { name = %[1]q - application_id = aws_appconfig_application.test.id + application_id = aws_appconfig_application.test.id tags = { %[2]q = %[3]q @@ -234,7 +234,7 @@ func testAccAWSAppConfigEnvironmentTags2(rName, tagKey1, tagValue1, tagKey2, tag return testAccAWSAppConfigApplicationTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2) + fmt.Sprintf(` resource "aws_appconfig_environment" "test" { name = %[1]q - application_id = aws_appconfig_application.test.id + application_id = aws_appconfig_application.test.id tags = { %[2]q = %[3]q From 45d2f09168cfabe3553b0906523b961682ab5fb6 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 09:52:32 +0900 Subject: [PATCH 0038/1208] docs: add change log --- .changelog/19307.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19307.txt diff --git a/.changelog/19307.txt b/.changelog/19307.txt new file mode 100644 index 000000000000..446c1c8af699 --- /dev/null +++ b/.changelog/19307.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_appconfig_environment +``` From fd94cb278e33924486b3c6f1c6efdf07742b6aff Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 18:04:35 +0900 Subject: [PATCH 0039/1208] fix: specify ErrorCheck https://github.com/bflad/tfproviderlint/tree/main/xpasses/XAT001 https://github.com/hashicorp/terraform-provider-aws/pull/19307/checks?check_run_id=2551044817 --- aws/resource_aws_appconfig_application_test.go | 3 +++ aws/resource_aws_appconfig_environment_test.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/aws/resource_aws_appconfig_application_test.go b/aws/resource_aws_appconfig_application_test.go index 1721363742a1..41ff1c820310 100644 --- a/aws/resource_aws_appconfig_application_test.go +++ b/aws/resource_aws_appconfig_application_test.go @@ -18,6 +18,7 @@ func TestAccAWSAppConfigApplication_basic(t *testing.T) { resourceName := "aws_appconfig_application.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAppConfigApplicationDestroy, Steps: []resource.TestStep{ @@ -49,6 +50,7 @@ func TestAccAWSAppConfigApplication_disappears(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAppConfigApplicationDestroy, Steps: []resource.TestStep{ @@ -72,6 +74,7 @@ func TestAccAWSAppConfigApplication_Tags(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAppConfigApplicationDestroy, Steps: []resource.TestStep{ diff --git a/aws/resource_aws_appconfig_environment_test.go b/aws/resource_aws_appconfig_environment_test.go index a663c90ecfdc..6e32abf03026 100644 --- a/aws/resource_aws_appconfig_environment_test.go +++ b/aws/resource_aws_appconfig_environment_test.go @@ -22,6 +22,7 @@ func TestAccAWSAppConfigEnvironment_basic(t *testing.T) { resourceName := "aws_appconfig_environment.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, Steps: []resource.TestStep{ @@ -55,6 +56,7 @@ func TestAccAWSAppConfigEnvironment_disappears(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, Steps: []resource.TestStep{ @@ -78,6 +80,7 @@ func TestAccAWSAppConfigEnvironment_Tags(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, Steps: []resource.TestStep{ From b47ccb62dfd46185ab4a7451ebd38d82d57c31df Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 18:25:12 +0900 Subject: [PATCH 0040/1208] fix: check !d.IsNewResource() before d.SetId("") https://github.com/hashicorp/terraform-provider-aws/issues/16796 https://github.com/hashicorp/terraform-provider-aws/pull/19307/checks?check_run_id=2554016542 ``` Calling `d.SetId("")` should ensure `!d.IsNewResource()` is checked first ``` --- aws/resource_aws_appconfig_application.go | 2 +- aws/resource_aws_appconfig_environment.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_appconfig_application.go b/aws/resource_aws_appconfig_application.go index 743b609df61b..adcd5c9a8de5 100644 --- a/aws/resource_aws_appconfig_application.go +++ b/aws/resource_aws_appconfig_application.go @@ -81,7 +81,7 @@ func resourceAwsAppconfigApplicationRead(d *schema.ResourceData, meta interface{ output, err := conn.GetApplication(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if !d.IsNewResource() && isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { log.Printf("[WARN] Appconfig Application (%s) not found, removing from state", d.Id()) d.SetId("") return nil diff --git a/aws/resource_aws_appconfig_environment.go b/aws/resource_aws_appconfig_environment.go index 8ac430b4df63..3a66831f2698 100644 --- a/aws/resource_aws_appconfig_environment.go +++ b/aws/resource_aws_appconfig_environment.go @@ -135,7 +135,7 @@ func resourceAwsAppconfigEnvironmentRead(d *schema.ResourceData, meta interface{ output, err := conn.GetEnvironment(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if !d.IsNewResource() && isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { log.Printf("[WARN] Appconfig Environment (%s) not found, removing from state", d.Id()) d.SetId("") return nil From 4eb7092aafb803ef6502f8ce5b068a02f7909617 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Tue, 11 May 2021 20:46:14 +0900 Subject: [PATCH 0041/1208] test: specify ImportStateIdFunc --- aws/resource_aws_appconfig_environment_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/aws/resource_aws_appconfig_environment_test.go b/aws/resource_aws_appconfig_environment_test.go index 6e32abf03026..c833513097ec 100644 --- a/aws/resource_aws_appconfig_environment_test.go +++ b/aws/resource_aws_appconfig_environment_test.go @@ -38,6 +38,7 @@ func TestAccAWSAppConfigEnvironment_basic(t *testing.T) { }, { ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAppConfigEnvironmentImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -94,6 +95,7 @@ func TestAccAWSAppConfigEnvironment_Tags(t *testing.T) { }, { ResourceName: resourceName, + ImportStateIdFunc: testAccAWSAppConfigEnvironmentImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -288,3 +290,14 @@ POLICY } `, rName) } + +func testAccAWSAppConfigEnvironmentImportStateIdFunc(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 e99712be0cee90d9ff73b9be6ec33d07b1feb041 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Tue, 11 May 2021 20:46:45 +0900 Subject: [PATCH 0042/1208] test: fix resourceName --- aws/resource_aws_appconfig_environment_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_appconfig_environment_test.go b/aws/resource_aws_appconfig_environment_test.go index c833513097ec..fff5d3affa1f 100644 --- a/aws/resource_aws_appconfig_environment_test.go +++ b/aws/resource_aws_appconfig_environment_test.go @@ -53,7 +53,7 @@ func TestAccAWSAppConfigEnvironment_disappears(t *testing.T) { appDesc := acctest.RandomWithPrefix("desc") envName := acctest.RandomWithPrefix("tf-acc-test") envDesc := acctest.RandomWithPrefix("desc") - resourceName := "aws_appconfig_application.test" + resourceName := "aws_appconfig_environment.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, From 5e7cac18b695eba27ee0473c982df9931c6b397e Mon Sep 17 00:00:00 2001 From: philof Date: Mon, 24 May 2021 11:22:27 -0400 Subject: [PATCH 0043/1208] new resource: aws_elasticsearch_domain_saml_options --- aws/elasticsearch_domain_structure.go | 94 ++++++ aws/provider.go | 1 + ...e_aws_elasticsearch_domain_saml_options.go | 218 ++++++++++++ ..._elasticsearch_domain_saml_options_test.go | 311 ++++++++++++++++++ aws/resource_aws_elasticsearch_domain_test.go | 14 +- 5 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 aws/resource_aws_elasticsearch_domain_saml_options.go create mode 100644 aws/resource_aws_elasticsearch_domain_saml_options_test.go diff --git a/aws/elasticsearch_domain_structure.go b/aws/elasticsearch_domain_structure.go index 4762b4654561..28b2c570c798 100644 --- a/aws/elasticsearch_domain_structure.go +++ b/aws/elasticsearch_domain_structure.go @@ -44,6 +44,57 @@ func expandAdvancedSecurityOptions(m []interface{}) *elasticsearch.AdvancedSecur return &config } +func expandESSAMLOptions(data []interface{}) *elasticsearch.SAMLOptionsInput { + if len(data) == 0 || data[0] == nil { + return nil + } + + options := elasticsearch.SAMLOptionsInput{} + group := data[0].(map[string]interface{}) + + if SAMLEnabled, ok := group["enabled"]; ok { + options.Enabled = aws.Bool(SAMLEnabled.(bool)) + + if SAMLEnabled.(bool) { + options.Idp = expandSAMLOptionsIdp(group["idp"].([]interface{})) + if v, ok := group["master_backend_role"].(string); ok && v != "" { + options.MasterBackendRole = aws.String(v) + } + if v, ok := group["master_user_name"].(string); ok && v != "" { + options.MasterUserName = aws.String(v) + } + if v, ok := group["roles_key"].(string); ok { + options.RolesKey = aws.String(v) + } + if v, ok := group["session_timeout_minutes"].(int); ok { + options.SessionTimeoutMinutes = aws.Int64(int64(v)) + } + if v, ok := group["subject_key"].(string); ok { + options.SubjectKey = aws.String(v) + } + } + } + + return &options +} + +func expandSAMLOptionsIdp(l []interface{}) *elasticsearch.SAMLIdp { + if len(l) == 0 { + return nil + } + + if l[0] == nil { + return &elasticsearch.SAMLIdp{} + } + + m := l[0].(map[string]interface{}) + + return &elasticsearch.SAMLIdp{ + EntityId: aws.String(m["entity_id"].(string)), + MetadataContent: aws.String(m["metadata_content"].(string)), + } +} + func flattenAdvancedSecurityOptions(advancedSecurityOptions *elasticsearch.AdvancedSecurityOptions) []map[string]interface{} { if advancedSecurityOptions == nil { return []map[string]interface{}{} @@ -58,6 +109,49 @@ func flattenAdvancedSecurityOptions(advancedSecurityOptions *elasticsearch.Advan return []map[string]interface{}{m} } +func flattenESSAMLOptions(d *schema.ResourceData, samlOptions *elasticsearch.SAMLOptionsOutput) []interface{} { + if samlOptions == nil { + return nil + } + + m := map[string]interface{}{ + "enabled": aws.BoolValue(samlOptions.Enabled), + "idp": flattenESSAMLIdpOptions(samlOptions.Idp), + } + + if samlOptions.RolesKey != nil { + m["roles_key"] = aws.StringValue(samlOptions.RolesKey) + } + if samlOptions.SessionTimeoutMinutes != nil { + m["session_timeout_minutes"] = aws.Int64Value(samlOptions.SessionTimeoutMinutes) + } + if samlOptions.SubjectKey != nil { + m["subject_key"] = aws.StringValue(samlOptions.SubjectKey) + } + + // samlOptions.master_backend_role and samlOptions.master_user_name will be added to the + // all_access role in kibana's security manager. These values cannot be read or + // modified by the elasticsearch API. So, we ignore it on read and let persist + // the value already in the state. + m["master_backend_role"] = d.Get("saml_options.0.master_backend_role").(string) + m["master_user_name"] = d.Get("saml_options.0.master_user_name").(string) + + return []interface{}{m} +} + +func flattenESSAMLIdpOptions(SAMLIdp *elasticsearch.SAMLIdp) []interface{} { + if SAMLIdp == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "entity_id": aws.StringValue(SAMLIdp.EntityId), + "metadata_content": aws.StringValue(SAMLIdp.MetadataContent), + } + + return []interface{}{m} +} + func getMasterUserOptions(d *schema.ResourceData) []interface{} { if v, ok := d.GetOk("advanced_security_options"); ok { options := v.([]interface{}) diff --git a/aws/provider.go b/aws/provider.go index 347b1ad81775..c93710874111 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -723,6 +723,7 @@ func Provider() *schema.Provider { "aws_elastic_beanstalk_environment": resourceAwsElasticBeanstalkEnvironment(), "aws_elasticsearch_domain": resourceAwsElasticSearchDomain(), "aws_elasticsearch_domain_policy": resourceAwsElasticSearchDomainPolicy(), + "aws_elasticsearch_domain_saml_options": resourceAwsElasticSearchDomainSAMLOptions(), "aws_elastictranscoder_pipeline": resourceAwsElasticTranscoderPipeline(), "aws_elastictranscoder_preset": resourceAwsElasticTranscoderPreset(), "aws_elb": resourceAwsElb(), diff --git a/aws/resource_aws_elasticsearch_domain_saml_options.go b/aws/resource_aws_elasticsearch_domain_saml_options.go new file mode 100644 index 000000000000..b9601a9b2c0a --- /dev/null +++ b/aws/resource_aws_elasticsearch_domain_saml_options.go @@ -0,0 +1,218 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceAwsElasticSearchDomainSAMLOptions() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsElasticSearchDomainSAMLOptionsPut, + Read: resourceAwsElasticSearchDomainSAMLOptionsRead, + Update: resourceAwsElasticSearchDomainSAMLOptionsPut, + Delete: resourceAwsElasticSearchDomainSAMLOptionsDelete, + + Schema: map[string]*schema.Schema{ + "domain_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "saml_options": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "idp": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "entity_id": { + Type: schema.TypeString, + Required: true, + }, + "metadata_content": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + "master_backend_role": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "master_user_name": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "roles_key": { + Type: schema.TypeString, + Optional: true, + }, + "session_timeout_minutes": { + Type: schema.TypeInt, + Optional: true, + Default: 60, + ValidateFunc: validation.IntBetween(1, 1440), + }, + "subject_key": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + } +} + +func resourceAwsElasticSearchDomainSAMLOptionsRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).esconn + + input := &elasticsearch.DescribeElasticsearchDomainInput{ + DomainName: aws.String(d.Get("domain_name").(string)), + } + + domain, err := conn.DescribeElasticsearchDomain(input) + + if err != nil { + if !d.IsNewResource() { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" { + log.Printf("[WARN] ElasticSearch Domain %q not found, removing from state", d.Id()) + d.SetId("") + return nil + } + } + return err + } + + log.Printf("[DEBUG] Received ElasticSearch domain: %s", domain) + + ds := domain.DomainStatus + options := ds.AdvancedSecurityOptions.SAMLOptions + + if err := d.Set("saml_options", flattenESSAMLOptions(d, options)); err != nil { + return fmt.Errorf("error setting saml_options for ElasticSearch Configuration: %w", err) + } + + return nil +} + +func resourceAwsElasticSearchDomainSAMLOptionsPut(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).esconn + + domainName := d.Get("domain_name").(string) + config := elasticsearch.AdvancedSecurityOptionsInput{} + config.SetSAMLOptions(expandESSAMLOptions(d.Get("saml_options").([]interface{}))) + + log.Printf("[DEBUG] Updating ElasticSearch domain SAML Options %s", config) + + _, err := conn.UpdateElasticsearchDomainConfig(&elasticsearch.UpdateElasticsearchDomainConfigInput{ + DomainName: aws.String(domainName), + AdvancedSecurityOptions: &config, + }) + + if err != nil { + return err + } + + d.SetId("esd-saml-options-" + domainName) + + input := &elasticsearch.DescribeElasticsearchDomainInput{ + DomainName: aws.String(d.Get("domain_name").(string)), + } + var out *elasticsearch.DescribeElasticsearchDomainOutput + err = resource.Retry(50*time.Minute, func() *resource.RetryError { + var err error + out, err = conn.DescribeElasticsearchDomain(input) + if err != nil { + return resource.NonRetryableError(err) + } + + if !*out.DomainStatus.Processing { + return nil + } + + return resource.RetryableError( + fmt.Errorf("%q: Timeout while waiting for changes to be processed", d.Id())) + }) + if isResourceTimeoutError(err) { + out, err = conn.DescribeElasticsearchDomain(input) + if err == nil && !*out.DomainStatus.Processing { + return nil + } + } + if err != nil { + return fmt.Errorf("Error updating Elasticsearch domain SAML Options: %s", err) + } + + return resourceAwsElasticSearchDomainSAMLOptionsRead(d, meta) +} + +func resourceAwsElasticSearchDomainSAMLOptionsDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).esconn + + domainName := d.Get("domain_name").(string) + config := elasticsearch.AdvancedSecurityOptionsInput{} + config.SetSAMLOptions(nil) + + _, err := conn.UpdateElasticsearchDomainConfig(&elasticsearch.UpdateElasticsearchDomainConfigInput{ + DomainName: aws.String(domainName), + AdvancedSecurityOptions: &config, + }) + if err != nil { + return err + } + + log.Printf("[DEBUG] Waiting for ElasticSearch domain SAML Options %q to be deleted", d.Get("domain_name").(string)) + + input := &elasticsearch.DescribeElasticsearchDomainInput{ + DomainName: aws.String(d.Get("domain_name").(string)), + } + var out *elasticsearch.DescribeElasticsearchDomainOutput + err = resource.Retry(60*time.Minute, func() *resource.RetryError { + var err error + out, err = conn.DescribeElasticsearchDomain(input) + if err != nil { + return resource.NonRetryableError(err) + } + + if !*out.DomainStatus.Processing { + return nil + } + + return resource.RetryableError( + fmt.Errorf("%q: Timeout while waiting for SAML Options to be deleted", d.Id())) + }) + if isResourceTimeoutError(err) { + out, err := conn.DescribeElasticsearchDomain(input) + if err == nil && !*out.DomainStatus.Processing { + return nil + } + } + if err != nil { + return fmt.Errorf("Error deleting Elasticsearch domain SAML Options: %s", err) + } + return nil +} diff --git a/aws/resource_aws_elasticsearch_domain_saml_options_test.go b/aws/resource_aws_elasticsearch_domain_saml_options_test.go new file mode 100644 index 000000000000..2899f0fb2177 --- /dev/null +++ b/aws/resource_aws_elasticsearch_domain_saml_options_test.go @@ -0,0 +1,311 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice" + "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 TestAccAWSElasticSearchDomainSAMLOptions_basic(t *testing.T) { + var domain elasticsearch.ElasticsearchDomainStatus + + rName := acctest.RandomWithPrefix("acc-test") + rUserName := acctest.RandomWithPrefix("es-master-user") + resourceName := "aws_elasticsearch_domain_saml_options.main" + esDomainResourceName := "aws_elasticsearch_domain.example" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, elasticsearch.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckESDomainSAMLOptionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccESDomainSAMLOptionsConfig(rUserName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckESDomainExists(esDomainResourceName, &domain), + testAccCheckESDomainSAMLOptions(esDomainResourceName, resourceName), + resource.TestCheckResourceAttr(resourceName, "saml_options.#", "1"), + ), + }, + }, + }) +} + +func TestAccAWSElasticSearchDomainSAMLOptions_disappears(t *testing.T) { + rName := acctest.RandomWithPrefix("acc-test") + rUserName := acctest.RandomWithPrefix("es-master-user") + resourceName := "aws_elasticsearch_domain_saml_options.main" + esDomainResourceName := "aws_elasticsearch_domain.example" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, elasticsearch.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckESDomainSAMLOptionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccESDomainSAMLOptionsConfig(rUserName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckESDomainSAMLOptions(esDomainResourceName, resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsElasticSearchDomainSAMLOptions(), resourceName), + ), + }, + }, + }) +} + +func TestAccAWSElasticSearchDomainSAMLOptions_disappears_Domain(t *testing.T) { + rName := acctest.RandomWithPrefix("acc-test") + rUserName := acctest.RandomWithPrefix("es-master-user") + resourceName := "aws_elasticsearch_domain_saml_options.main" + esDomainResourceName := "aws_elasticsearch_domain.example" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, elasticsearch.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckESDomainSAMLOptionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccESDomainSAMLOptionsConfig(rUserName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckESDomainSAMLOptions(esDomainResourceName, resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsElasticSearchDomain(), esDomainResourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSElasticSearchDomainSAMLOptions_Update(t *testing.T) { + rName := acctest.RandomWithPrefix("acc-test") + rUserName := acctest.RandomWithPrefix("es-master-user") + resourceName := "aws_elasticsearch_domain_saml_options.main" + esDomainResourceName := "aws_elasticsearch_domain.example" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, elasticsearch.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckESDomainSAMLOptionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccESDomainSAMLOptionsConfig(rUserName, rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "saml_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "saml_options.0.session_timeout_minutes", "60"), + testAccCheckESDomainSAMLOptions(esDomainResourceName, resourceName), + ), + }, + { + Config: testAccESDomainSAMLOptionsConfigUpdate(rUserName, rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "saml_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "saml_options.0.session_timeout_minutes", "180"), + testAccCheckESDomainSAMLOptions(esDomainResourceName, resourceName), + ), + }, + }, + }) +} + +func testAccCheckESDomainSAMLOptionsDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).esconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_elasticsearch_domain_saml_options" { + continue + } + + resp, err := conn.DescribeElasticsearchDomain(&elasticsearch.DescribeElasticsearchDomainInput{ + DomainName: aws.String(rs.Primary.Attributes["domain_name"]), + }) + + if err == nil { + return fmt.Errorf("Elasticsearch Domain still exists %s", resp) + } + + awsErr, ok := err.(awserr.Error) + if !ok { + return err + } + if awsErr.Code() != "ResourceNotFoundException" { + return err + } + + } + + return nil +} + +func testAccCheckESDomainSAMLOptionsDisappears(domainName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).esconn + + input := elasticsearch.AdvancedSecurityOptionsInput{} + input.SetSAMLOptions(nil) + _, err := conn.UpdateElasticsearchDomainConfig(&elasticsearch.UpdateElasticsearchDomainConfigInput{ + DomainName: aws.String(domainName), + AdvancedSecurityOptions: &input, + }) + + return err + } +} + +func testAccCheckESDomainSAMLOptions(esResource string, samlOptionsResource string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[esResource] + if !ok { + return fmt.Errorf("Not found: %s", esResource) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + options, ok := s.RootModule().Resources[samlOptionsResource] + if !ok { + return fmt.Errorf("Not found: %s", samlOptionsResource) + } + + conn := testAccProvider.Meta().(*AWSClient).esconn + _, err := conn.DescribeElasticsearchDomain(&elasticsearch.DescribeElasticsearchDomainInput{ + DomainName: aws.String(options.Primary.Attributes["domain_name"]), + }) + + return err + } +} + +func testAccESDomainSAMLOptionsConfig(userName string, domainName string) string { + return fmt.Sprintf(` +resource "aws_iam_user" "es_master_user" { + name = "%s" +} + +resource "aws_elasticsearch_domain" "example" { + domain_name = "%s" + elasticsearch_version = "7.10" + + cluster_config { + instance_type = "r5.large.elasticsearch" + } + + # Advanced security option must be enabled to configure SAML. + advanced_security_options { + enabled = true + internal_user_database_enabled = false + master_user_options { + master_user_arn = aws_iam_user.es_master_user.arn + } + } + + # You must enable node-to-node encryption to use advanced security options. + encrypt_at_rest { + enabled = true + } + + domain_endpoint_options { + enforce_https = true + tls_security_policy = "Policy-Min-TLS-1-2-2019-07" + } + + node_to_node_encryption { + enabled = true + } + + ebs_options { + ebs_enabled = true + volume_size = 10 + } +} + +resource "aws_elasticsearch_domain_saml_options" "main" { + domain_name = aws_elasticsearch_domain.example.domain_name + + saml_options { + # enabled = true + idp { + entity_id = "https://terraform-dev-ed.my.salesforce.com" + metadata_content = file("./test-fixtures/saml-metadata.xml") + } + # master_backend_role = "my-idp-group-or-role" + # master_user_name = "my-idp-user" + # roles_key = "optional-roles-key" + # session_timeout_minutes = 60 + # subject_key = "optional-subject-key" + } +} +`, userName, domainName) +} + +func testAccESDomainSAMLOptionsConfigUpdate(userName string, domainName string) string { + return fmt.Sprintf(` +resource "aws_iam_user" "es_master_user" { + name = "%s" +} + +resource "aws_elasticsearch_domain" "example" { + domain_name = "%s" + elasticsearch_version = "7.10" + + cluster_config { + instance_type = "r5.large.elasticsearch" + } + + # Advanced security option must be enabled to configure SAML. + advanced_security_options { + enabled = true + internal_user_database_enabled = false + master_user_options { + master_user_arn = aws_iam_user.es_master_user.arn + } + } + + # You must enable node-to-node encryption to use advanced security options. + encrypt_at_rest { + enabled = true + } + + domain_endpoint_options { + enforce_https = true + tls_security_policy = "Policy-Min-TLS-1-2-2019-07" + } + + node_to_node_encryption { + enabled = true + } + + ebs_options { + ebs_enabled = true + volume_size = 10 + } +} + +resource "aws_elasticsearch_domain_saml_options" "main" { + domain_name = aws_elasticsearch_domain.example.domain_name + + saml_options { + # enabled = true + idp { + entity_id = "https://terraform-dev-ed.my.salesforce.com" + metadata_content = file("./test-fixtures/saml-metadata.xml") + } + # master_backend_role = "my-idp-group-or-role" + # master_user_name = "my-idp-user" + # roles_key = "optional-roles-key" + session_timeout_minutes = 180 + # subject_key = "optional-subject-key" + } +} +`, userName, domainName) +} diff --git a/aws/resource_aws_elasticsearch_domain_test.go b/aws/resource_aws_elasticsearch_domain_test.go index f2baad9c4a94..5d332813673d 100644 --- a/aws/resource_aws_elasticsearch_domain_test.go +++ b/aws/resource_aws_elasticsearch_domain_test.go @@ -11,7 +11,7 @@ import ( "github.com/aws/aws-sdk-go/aws/awserr" elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice" "github.com/aws/aws-sdk-go/service/iam" - "github.com/hashicorp/go-multierror" + multierror "github.com/hashicorp/go-multierror" "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" @@ -1457,6 +1457,18 @@ func testAccPreCheckIamServiceLinkedRoleEs(t *testing.T) { } } +func testAccCheckESDomainDisappears(domainName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).esconn + + _, err := conn.DeleteElasticsearchDomain(&elasticsearch.DeleteElasticsearchDomainInput{ + DomainName: aws.String(domainName), + }) + + return err + } +} + func testAccESDomainConfig(randInt int) string { return fmt.Sprintf(` resource "aws_elasticsearch_domain" "test" { From da67222e09ed10cb27f1520dda701b42e97c0acf Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 11:55:51 -0400 Subject: [PATCH 0044/1208] provider: New data source --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index 347b1ad81775..6aece9c9ea0f 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -386,6 +386,7 @@ func Provider() *schema.Provider { "aws_secretsmanager_secret": dataSourceAwsSecretsManagerSecret(), "aws_secretsmanager_secret_rotation": dataSourceAwsSecretsManagerSecretRotation(), "aws_secretsmanager_secret_version": dataSourceAwsSecretsManagerSecretVersion(), + "aws_servicecatalog_constraint": dataSourceAwsServiceCatalogConstraint(), "aws_servicequotas_service": dataSourceAwsServiceQuotasService(), "aws_servicequotas_service_quota": dataSourceAwsServiceQuotasServiceQuota(), "aws_service_discovery_dns_namespace": dataSourceServiceDiscoveryDnsNamespace(), From f998e7a64c8408f5f0d14b8d34b3719b2091c06b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 11:56:22 -0400 Subject: [PATCH 0045/1208] ds/servicecat_constraint: New data source --- ...ta_source_aws_servicecatalog_constraint.go | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 aws/data_source_aws_servicecatalog_constraint.go diff --git a/aws/data_source_aws_servicecatalog_constraint.go b/aws/data_source_aws_servicecatalog_constraint.go new file mode 100644 index 000000000000..98bf3aa8c126 --- /dev/null +++ b/aws/data_source_aws_servicecatalog_constraint.go @@ -0,0 +1,104 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func dataSourceAwsServiceCatalogConstraint() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsServiceCatalogConstraintRead, + + Schema: map[string]*schema.Schema{ + "accept_language": { + Type: schema.TypeString, + Optional: true, + Default: "en", + ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), + }, + "description": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Required: true, + }, + "owner": { + Type: schema.TypeString, + Computed: true, + }, + "parameters": { + Type: schema.TypeString, + Computed: true, + }, + "portfolio_id": { + Type: schema.TypeString, + Computed: true, + }, + "product_id": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceAwsServiceCatalogConstraintRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + output, err := waiter.ConstraintReady(conn, d.Get("accept_language").(string), d.Get("id").(string)) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Service Catalog Constraint (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error describing Service Catalog Constraint (%s): %w", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting Service Catalog Constraint (%s): empty response", d.Id()) + } + + acceptLanguage := d.Get("accept_language").(string) + + if acceptLanguage == "" { + acceptLanguage = "en" + } + + d.Set("accept_language", acceptLanguage) + + d.Set("parameters", output.ConstraintParameters) + d.Set("status", output.Status) + + detail := output.ConstraintDetail + + d.Set("description", detail.Description) + d.Set("owner", detail.Owner) + d.Set("portfolio_id", detail.PortfolioId) + d.Set("product_id", detail.ProductId) + d.Set("type", detail.Type) + + d.SetId(aws.StringValue(detail.ConstraintId)) + + return nil +} From c9259d987f8aea445db82aa954035509250e6cfa Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 11:56:40 -0400 Subject: [PATCH 0046/1208] tests/ds/servicecat_constraint: New data source --- ...urce_aws_servicecatalog_constraint_test.go | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 aws/data_source_aws_servicecatalog_constraint_test.go diff --git a/aws/data_source_aws_servicecatalog_constraint_test.go b/aws/data_source_aws_servicecatalog_constraint_test.go new file mode 100644 index 000000000000..aa176fcce5e3 --- /dev/null +++ b/aws/data_source_aws_servicecatalog_constraint_test.go @@ -0,0 +1,45 @@ +package aws + +import ( + "testing" + + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSServiceCatalogConstraintDataSource_basic(t *testing.T) { + resourceName := "aws_servicecatalog_constraint.test" + dataSourceName := "data.aws_servicecatalog_constraint.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogConstraintDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogConstraintDataSourceConfig_basic(rName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogConstraintExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "description", dataSourceName, "description"), + resource.TestCheckResourceAttrPair(resourceName, "owner", dataSourceName, "owner"), + resource.TestCheckResourceAttrPair(resourceName, "parameters", dataSourceName, "parameters"), + resource.TestCheckResourceAttrPair(resourceName, "portfolio_id", dataSourceName, "portfolio_id"), + resource.TestCheckResourceAttrPair(resourceName, "product_id", dataSourceName, "product_id"), + resource.TestCheckResourceAttrPair(resourceName, "status", dataSourceName, "status"), + resource.TestCheckResourceAttrPair(resourceName, "type", dataSourceName, "type"), + ), + }, + }, + }) +} + +func testAccAWSServiceCatalogConstraintDataSourceConfig_basic(rName, description string) string { + return composeConfig(testAccAWSServiceCatalogConstraintConfig_basic(rName, description), ` +data "aws_servicecatalog_constraint" "test" { + id = aws_servicecatalog_constraint.test.id +} +`) +} From e865510babd1a74299383aac75564c39cd2677a1 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 11:57:06 -0400 Subject: [PATCH 0047/1208] docs/ds/servicecat_constraint: New data source --- .../d/servicecatalog_constraint.html.markdown | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 website/docs/d/servicecatalog_constraint.html.markdown diff --git a/website/docs/d/servicecatalog_constraint.html.markdown b/website/docs/d/servicecatalog_constraint.html.markdown new file mode 100644 index 000000000000..6f1708c7915a --- /dev/null +++ b/website/docs/d/servicecatalog_constraint.html.markdown @@ -0,0 +1,93 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_constraint" +description: |- + Manages a Service Catalog Constraint +--- + +# Data source: aws_servicecatalog_constraint + +Manages a Service Catalog Constraint. + +~> **NOTE:** This resource does not associate a Service Catalog product and portfolio. However, the product and portfolio must be associated (see the `aws_servicecatalog_product_portfolio_association` resource) prior to creating a constraint or you will receive an error. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_servicecatalog_constraint" "example" { + description = "Back off, man. I'm a scientist." + portfolio_id = aws_servicecatalog_portfolio.example.id + product_id = aws_servicecatalog_product.example.id + type = "LAUNCH" + + parameters = jsonencode({ + "RoleArn" : "arn:aws:iam::123456789012:role/LaunchRole" + }) +} +``` + +## Argument Reference + +The following arguments are required: + +* `parameters` - (Required) Constraint parameters in JSON format. The syntax depends on the constraint type. See details below. +* `portfolio_id` - (Required) Portfolio identifier. +* `product_id` - (Required) Product identifier. +* `type` - (Required) Type of constraint. Valid values are `LAUNCH`, `NOTIFICATION`, `RESOURCE_UPDATE`, `STACKSET`, and `TEMPLATE`. + +The following arguments are optional: + +* `accept_language` - (Optional) Language code. Valid values: `en` (English), `jp` (Japanese), `zh` (Chinese). Default value is `en`. +* `description` - (Optional) Description of the constraint. + +### `parameters` + +The `type` you specify determines what must be included in the `parameters` JSON: + +* `LAUNCH`: You are required to specify either the RoleArn or the LocalRoleName but can't use both. If you specify the `LocalRoleName` property, when an account uses the launch constraint, the IAM role with that name in the account will be used. This allows launch-role constraints to be account-agnostic so the administrator can create fewer resources per shared account. The given role name must exist in the account used to create the launch constraint and the account of the user who launches a product with this launch constraint. You cannot have both a `LAUNCH` and a `STACKSET` constraint. You also cannot have more than one `LAUNCH` constraint on an `aws_servicecatalog_product` and `aws_servicecatalog_portfolio`. Specify the `RoleArn` and `LocalRoleName` properties as follows: + +```json +{ "RoleArn" : "arn:aws:iam::123456789012:role/LaunchRole" } +``` + +```json +{ "LocalRoleName" : "SCBasicLaunchRole" } +``` + +* `NOTIFICATION`: Specify the `NotificationArns` property as follows: + +```json +{ "NotificationArns" : ["arn:aws:sns:us-east-1:123456789012:Topic"] } +``` + +* `RESOURCE_UPDATE`: Specify the `TagUpdatesOnProvisionedProduct` property as follows. The `TagUpdatesOnProvisionedProduct` property accepts a string value of `ALLOWED` or `NOT_ALLOWED`. + +```json +{ "Version" : "2.0","Properties" :{ "TagUpdateOnProvisionedProduct" : "String" }} +``` + +* `STACKSET`: Specify the Parameters property as follows. You cannot have both a `LAUNCH` and a `STACKSET` constraint. You also cannot have more than one `STACKSET` constraint on on an `aws_servicecatalog_product` and `aws_servicecatalog_portfolio`. Products with a `STACKSET` constraint will launch an AWS CloudFormation stack set. + +```json +{ "Version" : "String", "Properties" : { "AccountList" : [ "String" ], "RegionList" : [ "String" ], "AdminRole" : "String", "ExecutionRole" : "String" }} +``` + +* `TEMPLATE`: Specify the Rules property. For more information, see [Template Constraint Rules](http://docs.aws.amazon.com/servicecatalog/latest/adminguide/reference-template_constraint_rules.html). + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - Constraint identifier. +* `owner` - Owner of the constraint. + +## Import + +`aws_servicecatalog_constraint` can be imported using the constraint ID, e.g. + +``` +$ terraform import aws_servicecatalog_constraint.example cons-nmdkb6cgxfcrs +``` From 286eb4a8dedbac7085ce337eea192769e7bbe810 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 11:59:31 -0400 Subject: [PATCH 0048/1208] ds/servicecat_constraint: Add changelog --- .changelog/19499.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19499.txt diff --git a/.changelog/19499.txt b/.changelog/19499.txt new file mode 100644 index 000000000000..92a274598bbc --- /dev/null +++ b/.changelog/19499.txt @@ -0,0 +1,3 @@ +```release-notes:new-data-source +aws_servicecatalog_constraint +``` \ No newline at end of file From 2e9f983fbcc1423db5b61311a4a9e7961b42ecf6 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 12:03:23 -0400 Subject: [PATCH 0049/1208] ds/servicecat_constraint: Lint --- aws/data_source_aws_servicecatalog_constraint_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/data_source_aws_servicecatalog_constraint_test.go b/aws/data_source_aws_servicecatalog_constraint_test.go index aa176fcce5e3..025966ef59aa 100644 --- a/aws/data_source_aws_servicecatalog_constraint_test.go +++ b/aws/data_source_aws_servicecatalog_constraint_test.go @@ -39,7 +39,7 @@ func TestAccAWSServiceCatalogConstraintDataSource_basic(t *testing.T) { func testAccAWSServiceCatalogConstraintDataSourceConfig_basic(rName, description string) string { return composeConfig(testAccAWSServiceCatalogConstraintConfig_basic(rName, description), ` data "aws_servicecatalog_constraint" "test" { - id = aws_servicecatalog_constraint.test.id + id = aws_servicecatalog_constraint.test.id } `) } From 7ecd95175fccc16fb945ec2a9055a554a45cb187 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 13:01:47 -0400 Subject: [PATCH 0050/1208] docs/ds/servicecat_constraint: Fix docs for DS --- .../d/servicecatalog_constraint.html.markdown | 73 +++---------------- 1 file changed, 12 insertions(+), 61 deletions(-) diff --git a/website/docs/d/servicecatalog_constraint.html.markdown b/website/docs/d/servicecatalog_constraint.html.markdown index 6f1708c7915a..bf69c9b30677 100644 --- a/website/docs/d/servicecatalog_constraint.html.markdown +++ b/website/docs/d/servicecatalog_constraint.html.markdown @@ -3,29 +3,21 @@ subcategory: "Service Catalog" layout: "aws" page_title: "AWS: aws_servicecatalog_constraint" description: |- - Manages a Service Catalog Constraint + Provides information on a Service Catalog Constraint --- # Data source: aws_servicecatalog_constraint -Manages a Service Catalog Constraint. - -~> **NOTE:** This resource does not associate a Service Catalog product and portfolio. However, the product and portfolio must be associated (see the `aws_servicecatalog_product_portfolio_association` resource) prior to creating a constraint or you will receive an error. +Provides information on a Service Catalog Constraint. ## Example Usage ### Basic Usage ```terraform -resource "aws_servicecatalog_constraint" "example" { - description = "Back off, man. I'm a scientist." - portfolio_id = aws_servicecatalog_portfolio.example.id - product_id = aws_servicecatalog_product.example.id - type = "LAUNCH" - - parameters = jsonencode({ - "RoleArn" : "arn:aws:iam::123456789012:role/LaunchRole" - }) +data "aws_servicecatalog_constraint" "example" { + accept_language = "en" + id = "cons-hrvy0335" } ``` @@ -33,61 +25,20 @@ resource "aws_servicecatalog_constraint" "example" { The following arguments are required: -* `parameters` - (Required) Constraint parameters in JSON format. The syntax depends on the constraint type. See details below. -* `portfolio_id` - (Required) Portfolio identifier. -* `product_id` - (Required) Product identifier. -* `type` - (Required) Type of constraint. Valid values are `LAUNCH`, `NOTIFICATION`, `RESOURCE_UPDATE`, `STACKSET`, and `TEMPLATE`. +* `id` - Constraint identifier. The following arguments are optional: * `accept_language` - (Optional) Language code. Valid values: `en` (English), `jp` (Japanese), `zh` (Chinese). Default value is `en`. -* `description` - (Optional) Description of the constraint. - -### `parameters` - -The `type` you specify determines what must be included in the `parameters` JSON: - -* `LAUNCH`: You are required to specify either the RoleArn or the LocalRoleName but can't use both. If you specify the `LocalRoleName` property, when an account uses the launch constraint, the IAM role with that name in the account will be used. This allows launch-role constraints to be account-agnostic so the administrator can create fewer resources per shared account. The given role name must exist in the account used to create the launch constraint and the account of the user who launches a product with this launch constraint. You cannot have both a `LAUNCH` and a `STACKSET` constraint. You also cannot have more than one `LAUNCH` constraint on an `aws_servicecatalog_product` and `aws_servicecatalog_portfolio`. Specify the `RoleArn` and `LocalRoleName` properties as follows: - -```json -{ "RoleArn" : "arn:aws:iam::123456789012:role/LaunchRole" } -``` - -```json -{ "LocalRoleName" : "SCBasicLaunchRole" } -``` - -* `NOTIFICATION`: Specify the `NotificationArns` property as follows: - -```json -{ "NotificationArns" : ["arn:aws:sns:us-east-1:123456789012:Topic"] } -``` - -* `RESOURCE_UPDATE`: Specify the `TagUpdatesOnProvisionedProduct` property as follows. The `TagUpdatesOnProvisionedProduct` property accepts a string value of `ALLOWED` or `NOT_ALLOWED`. - -```json -{ "Version" : "2.0","Properties" :{ "TagUpdateOnProvisionedProduct" : "String" }} -``` - -* `STACKSET`: Specify the Parameters property as follows. You cannot have both a `LAUNCH` and a `STACKSET` constraint. You also cannot have more than one `STACKSET` constraint on on an `aws_servicecatalog_product` and `aws_servicecatalog_portfolio`. Products with a `STACKSET` constraint will launch an AWS CloudFormation stack set. - -```json -{ "Version" : "String", "Properties" : { "AccountList" : [ "String" ], "RegionList" : [ "String" ], "AdminRole" : "String", "ExecutionRole" : "String" }} -``` - -* `TEMPLATE`: Specify the Rules property. For more information, see [Template Constraint Rules](http://docs.aws.amazon.com/servicecatalog/latest/adminguide/reference-template_constraint_rules.html). ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `id` - Constraint identifier. +* `description` - Description of the constraint. * `owner` - Owner of the constraint. - -## Import - -`aws_servicecatalog_constraint` can be imported using the constraint ID, e.g. - -``` -$ terraform import aws_servicecatalog_constraint.example cons-nmdkb6cgxfcrs -``` +* `parameters` - Constraint parameters in JSON format. +* `portfolio_id` - Portfolio identifier. +* `product_id` - Product identifier. +* `status` - Constraint status. +* `type` - Type of constraint. Valid values are `LAUNCH`, `NOTIFICATION`, `RESOURCE_UPDATE`, `STACKSET`, and `TEMPLATE`. From 7d970041143744d02429d78ae2e8aa9eb759e738 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 13:05:23 -0400 Subject: [PATCH 0051/1208] ds/servicecat_constraint: Fix for DS --- aws/data_source_aws_servicecatalog_constraint.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/aws/data_source_aws_servicecatalog_constraint.go b/aws/data_source_aws_servicecatalog_constraint.go index 98bf3aa8c126..771b877ea367 100644 --- a/aws/data_source_aws_servicecatalog_constraint.go +++ b/aws/data_source_aws_servicecatalog_constraint.go @@ -2,14 +2,12 @@ package aws import ( "fmt" - "log" "github.com/aws/aws-sdk-go/aws" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func dataSourceAwsServiceCatalogConstraint() *schema.Resource { @@ -65,18 +63,12 @@ func dataSourceAwsServiceCatalogConstraintRead(d *schema.ResourceData, meta inte output, err := waiter.ConstraintReady(conn, d.Get("accept_language").(string), d.Get("id").(string)) - if !d.IsNewResource() && tfresource.NotFound(err) { - log.Printf("[WARN] Service Catalog Constraint (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - if err != nil { - return fmt.Errorf("error describing Service Catalog Constraint (%s): %w", d.Id(), err) + return fmt.Errorf("error describing Service Catalog Constraint: %w", err) } if output == nil { - return fmt.Errorf("error getting Service Catalog Constraint (%s): empty response", d.Id()) + return fmt.Errorf("error getting Service Catalog Constraint: empty response") } acceptLanguage := d.Get("accept_language").(string) From f69c0d7d09358dadb420219234f31e44a0aa4820 Mon Sep 17 00:00:00 2001 From: Robert Christ Date: Mon, 17 May 2021 17:03:03 -0700 Subject: [PATCH 0052/1208] Initial implementation of self_managed_event_source for aws_lambda_event_source_mapping. --- ...esource_aws_lambda_event_source_mapping.go | 104 ++++++++++- ...ce_aws_lambda_event_source_mapping_test.go | 167 ++++++++++++++++++ aws/structure.go | 80 +++++++++ 3 files changed, 343 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index c32af92e210b..56de42572b93 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -34,7 +34,7 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { Schema: map[string]*schema.Schema{ "event_source_arn": { Type: schema.TypeString, - Required: true, + Optional: true, ForceNew: true, }, "function_name": { @@ -80,12 +80,19 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { return false } - eventSourceARN, err := arn.Parse(d.Get("event_source_arn").(string)) - if err != nil { - return false + serviceName := "" + if v, ok := d.GetOk("event_source_arn"); ok { + eventSourceARN, err := arn.Parse(v.(string)) + if err != nil { + return false + } + serviceName = eventSourceARN.Service + } else { + // self managed kafka does not have an event_source_arn + serviceName = "kafka" } - switch eventSourceARN.Service { - // kafka.ServiceName is "Kafka". + switch serviceName { + // kafka.ServiceName is "kafka". case dynamodb.ServiceName, kinesis.ServiceName, "kafka": if old == "100" { return true @@ -156,6 +163,66 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { }, }, }, + /* + "self_managed_event_source": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoints": { + Type: schema.TypeMap, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + */ + "self_managed_event_source": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoints": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kafka_bootstrap_servers": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "source_access_configuration": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + }, + "uri": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, "function_arn": { Type: schema.TypeString, Computed: true, @@ -190,8 +257,11 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte conn := meta.(*AWSClient).lambdaconn input := &lambda.CreateEventSourceMappingInput{ - Enabled: aws.Bool(d.Get("enabled").(bool)), - FunctionName: aws.String(d.Get("function_name").(string)), + Enabled: aws.Bool(d.Get("enabled").(bool)), + } + + if v, ok := d.GetOk("function_name"); ok { + input.FunctionName = aws.String(v.(string)) } if v, ok := d.GetOk("batch_size"); ok { @@ -236,6 +306,14 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte input.StartingPositionTimestamp = aws.Time(t) } + if v, ok := d.GetOk("self_managed_event_source"); ok { + input.SelfManagedEventSource = expandLambdaEventSourceMappingSelfManagedEventSource(v.([]interface{})) + } + + if v, ok := d.GetOk("source_access_configuration"); ok { + input.SourceAccessConfigurations = expandLambdaEventSourceMappingSourceAccessConfigurations(v.([]interface{})) + } + if v, ok := d.GetOk("topics"); ok && v.(*schema.Set).Len() > 0 { input.Topics = expandStringSet(v.(*schema.Set)) } @@ -322,6 +400,12 @@ func resourceAwsLambdaEventSourceMappingRead(d *schema.ResourceData, meta interf if err := d.Set("topics", flattenStringSet(eventSourceMappingConfiguration.Topics)); err != nil { return fmt.Errorf("error setting topics: %w", err) } + if err := d.Set("self_managed_event_source", flattenLambdaEventSourceMappingSelfManagedEventSource(eventSourceMappingConfiguration.SelfManagedEventSource)); err != nil { + return fmt.Errorf("error setting self_managed_event_source: %w", err) + } + if err := d.Set("source_access_configuration", flattenLambdaEventSourceMappingSourceAccessConfigurations(eventSourceMappingConfiguration.SourceAccessConfigurations, d)); err != nil { + return fmt.Errorf("error setting source_access_configuration: %w", err) + } d.Set("starting_position", eventSourceMappingConfiguration.StartingPosition) if eventSourceMappingConfiguration.StartingPositionTimestamp != nil { @@ -439,6 +523,10 @@ func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta inte input.ParallelizationFactor = aws.Int64(int64(d.Get("parallelization_factor").(int))) } + if d.HasChange("source_access_configuration") { + input.SourceAccessConfigurations = expandLambdaEventSourceMappingSourceAccessConfigurations(d.Get("source_access_configuration").([]interface{})) + } + err := resource.Retry(waiter.EventSourceMappingPropagationTimeout, func() *resource.RetryError { _, err := conn.UpdateEventSourceMapping(input) diff --git a/aws/resource_aws_lambda_event_source_mapping_test.go b/aws/resource_aws_lambda_event_source_mapping_test.go index f3113da2e39d..9a8bed4a96ca 100644 --- a/aws/resource_aws_lambda_event_source_mapping_test.go +++ b/aws/resource_aws_lambda_event_source_mapping_test.go @@ -665,6 +665,52 @@ func TestAccAWSLambdaEventSourceMapping_MSK(t *testing.T) { }) } +func TestAccAWSLambdaEventSourceMapping_SelfManagedKafka(t *testing.T) { + var v lambda.EventSourceMappingConfiguration + resourceName := "aws_lambda_event_source_mapping.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID, "kafka"), //using kafka.EndpointsID will import kafka and make linters sad + Providers: testAccProviders, + CheckDestroy: testAccCheckLambdaEventSourceMappingDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLambdaEventSourceMappingConfigSelfManagedKafka(rName, "100"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaEventSourceMappingExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "batch_size", "100"), + resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.#", "1"), + + resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.0.endpoints.#", "1"), + resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.0.endpoints.0.kafka_bootstrap_servers.#", "1"), + resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.0.endpoints.0.kafka_bootstrap_servers.0", "test:9092"), + resource.TestCheckResourceAttr(resourceName, "source_access_configuration.#", "3"), + resource.TestCheckResourceAttr(resourceName, "source_access_configuration.0.type", "VPC_SUBNET"), + resource.TestCheckResourceAttr(resourceName, "source_access_configuration.1.type", "VPC_SUBNET"), + resource.TestCheckResourceAttr(resourceName, "source_access_configuration.2.type", "VPC_SECURITY_GROUP"), + testAccCheckResourceAttrRfc3339(resourceName, "last_modified"), + resource.TestCheckResourceAttr(resourceName, "topics.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "topics.*", "test"), + ), + }, + // batch_size became optional. Ensure that if the user supplies the default + // value, but then moves to not providing the value, that we don't consider this + // a diff. + { + PlanOnly: true, + Config: testAccAWSLambdaEventSourceMappingConfigSelfManagedKafka(rName, "null"), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAWSLambdaEventSourceMappingIsBeingDisabled(conf *lambda.EventSourceMappingConfiguration) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).lambdaconn @@ -1185,6 +1231,127 @@ resource "aws_lambda_event_source_mapping" "test" { `, rName, batchSize)) } +func testAccAWSLambdaEventSourceMappingConfigSelfManagedKafka(rName, batchSize string) string { + if batchSize == "" { + batchSize = "null" + } + + return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(` +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = < 0 { + if config, ok := vSource[0].(map[string]interface{}); ok { + if vEndpoints, ok := config["endpoints"].([]interface{}); ok { + mEndpoints := vEndpoints[0].(map[string]interface{}) + if kafkaBootstrapServers, ok := mEndpoints["kafka_bootstrap_servers"]; ok { + source.Endpoints["KAFKA_BOOTSTRAP_SERVERS"] = expandStringList(kafkaBootstrapServers.([]interface{})) + } + } + } + } + return source +} + +func flattenLambdaEventSourceMappingSelfManagedEventSource(source *lambda.SelfManagedEventSource) []interface{} { + mSource := map[string]interface{}{} + mEndpoints := map[string]interface{}{} + if source != nil { + if source.Endpoints != nil { + if kafkaBootstrapBrokers, ok := source.Endpoints["KAFKA_BOOTSTRAP_SERVERS"]; ok { + mEndpoints["kafka_bootstrap_servers"] = flattenStringList(kafkaBootstrapBrokers) + mSource["endpoints"] = []interface{}{mEndpoints} + } + } + } + + if len(mSource) == 0 { + return nil + } + + return []interface{}{mSource} +} + +func expandLambdaEventSourceMappingSourceAccessConfigurations(v []interface{}) []*lambda.SourceAccessConfiguration { + accesses := make([]*lambda.SourceAccessConfiguration, 0, len(v)) + for _, m := range v { + config := m.(map[string]interface{}) + accesses = append(accesses, &lambda.SourceAccessConfiguration{ + Type: aws.String(config["type"].(string)), + URI: aws.String(config["uri"].(string)), + }) + } + return accesses +} + +func flattenLambdaEventSourceMappingSourceAccessConfigurations(accesses []*lambda.SourceAccessConfiguration, d *schema.ResourceData) []map[string]interface{} { + if accesses == nil { + return nil + } + settings := make([]map[string]interface{}, len(accesses)) + + for i, access := range accesses { + setting := make(map[string]interface{}) + setting["type"] = access.Type + setting["uri"] = access.URI + settings[i] = setting + } + // The result returned from AWS is sorted so try to order it like the original to prevent spurious diffs + if curCount, ok := d.Get("source_access_configuration.#").(int); ok { + for i := 0; i < curCount; i++ { + if curSetting, ok := d.Get("source_access_configuration." + strconv.Itoa(i)).(map[string]interface{}); ok { + for j := 0; j < len(settings); j++ { + if curSetting["type"] == *settings[j]["type"].(*string) && + curSetting["uri"] == *settings[j]["uri"].(*string) { + settings[i], settings[j] = settings[j], settings[i] + } + } + } + } + } + return settings +} + func flattenLambdaLayers(layers []*lambda.Layer) []interface{} { arns := make([]*string, len(layers)) for i, layer := range layers { From baa30dbeacf022e9036b15b8805a4b0cfd76c9ba Mon Sep 17 00:00:00 2001 From: Robert Christ Date: Tue, 18 May 2021 09:42:58 -0700 Subject: [PATCH 0053/1208] Remove the import test for the moment. --- aws/resource_aws_lambda_event_source_mapping_test.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_lambda_event_source_mapping_test.go b/aws/resource_aws_lambda_event_source_mapping_test.go index 9a8bed4a96ca..d8b2fec6b171 100644 --- a/aws/resource_aws_lambda_event_source_mapping_test.go +++ b/aws/resource_aws_lambda_event_source_mapping_test.go @@ -48,11 +48,13 @@ func TestAccAWSLambdaEventSourceMapping_Kinesis_basic(t *testing.T) { PlanOnly: true, Config: testAccAWSLambdaEventSourceMappingConfigKinesisBatchSize(rName, "null"), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, + /* + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + */ { Config: testAccAWSLambdaEventSourceMappingConfigKinesisUpdateFunctionName(rName), Check: resource.ComposeTestCheckFunc( From 0926eeec8ba7098413e6c395993aea06809c5e50 Mon Sep 17 00:00:00 2001 From: Robert Christ Date: Tue, 18 May 2021 09:50:34 -0700 Subject: [PATCH 0054/1208] Add changelog entry for PR#19425 --- .changelog/19425.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19425.txt diff --git a/.changelog/19425.txt b/.changelog/19425.txt new file mode 100644 index 000000000000..8fd11e459b3e --- /dev/null +++ b/.changelog/19425.txt @@ -0,0 +1,3 @@ +```release-notes:enhancement +resource/aws_lambda_event_source_mapping: Add `self_managed_event_source`, `source_access_configuration` to allow for self managed kafka cluster. +``` From 37007a37862a8c6d3e14e7f02d000c27d068f9ad Mon Sep 17 00:00:00 2001 From: Robert Christ Date: Wed, 19 May 2021 10:38:44 -0700 Subject: [PATCH 0055/1208] Switch the self_managed_event_source endpoints to a map[string]string. Add some documentation updates. --- ...esource_aws_lambda_event_source_mapping.go | 35 +------- ...ce_aws_lambda_event_source_mapping_test.go | 26 ++---- aws/structure.go | 83 +++++++++++++------ .../lambda_event_source_mapping.html.markdown | 43 +++++++++- 4 files changed, 110 insertions(+), 77 deletions(-) diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index 56de42572b93..d412cf5c62c5 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -163,23 +163,6 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { }, }, }, - /* - "self_managed_event_source": { - Type: schema.TypeList, - Optional: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "endpoints": { - Type: schema.TypeMap, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - }, - */ "self_managed_event_source": { Type: schema.TypeList, Optional: true, @@ -188,20 +171,10 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "endpoints": { - Type: schema.TypeList, + Type: schema.TypeMap, Required: true, - MaxItems: 1, - MinItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "kafka_bootstrap_servers": { - Type: schema.TypeList, - Required: true, - ForceNew: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, }, }, }, @@ -400,7 +373,7 @@ func resourceAwsLambdaEventSourceMappingRead(d *schema.ResourceData, meta interf if err := d.Set("topics", flattenStringSet(eventSourceMappingConfiguration.Topics)); err != nil { return fmt.Errorf("error setting topics: %w", err) } - if err := d.Set("self_managed_event_source", flattenLambdaEventSourceMappingSelfManagedEventSource(eventSourceMappingConfiguration.SelfManagedEventSource)); err != nil { + if err := d.Set("self_managed_event_source", flattenLambdaEventSourceMappingSelfManagedEventSource(eventSourceMappingConfiguration.SelfManagedEventSource, d)); err != nil { return fmt.Errorf("error setting self_managed_event_source: %w", err) } if err := d.Set("source_access_configuration", flattenLambdaEventSourceMappingSourceAccessConfigurations(eventSourceMappingConfiguration.SourceAccessConfigurations, d)); err != nil { diff --git a/aws/resource_aws_lambda_event_source_mapping_test.go b/aws/resource_aws_lambda_event_source_mapping_test.go index d8b2fec6b171..94367b53e60b 100644 --- a/aws/resource_aws_lambda_event_source_mapping_test.go +++ b/aws/resource_aws_lambda_event_source_mapping_test.go @@ -48,13 +48,11 @@ func TestAccAWSLambdaEventSourceMapping_Kinesis_basic(t *testing.T) { PlanOnly: true, Config: testAccAWSLambdaEventSourceMappingConfigKinesisBatchSize(rName, "null"), }, - /* - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - */ + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccAWSLambdaEventSourceMappingConfigKinesisUpdateFunctionName(rName), Check: resource.ComposeTestCheckFunc( @@ -684,10 +682,7 @@ func TestAccAWSLambdaEventSourceMapping_SelfManagedKafka(t *testing.T) { testAccCheckAwsLambdaEventSourceMappingExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "batch_size", "100"), resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.#", "1"), - - resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.0.endpoints.#", "1"), - resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.0.endpoints.0.kafka_bootstrap_servers.#", "1"), - resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.0.endpoints.0.kafka_bootstrap_servers.0", "test:9092"), + resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.0.endpoints.KAFKA_BOOTSTRAP_SERVERS", "test2:9092,test1:9092"), resource.TestCheckResourceAttr(resourceName, "source_access_configuration.#", "3"), resource.TestCheckResourceAttr(resourceName, "source_access_configuration.0.type", "VPC_SUBNET"), resource.TestCheckResourceAttr(resourceName, "source_access_configuration.1.type", "VPC_SUBNET"), @@ -704,11 +699,6 @@ func TestAccAWSLambdaEventSourceMapping_SelfManagedKafka(t *testing.T) { PlanOnly: true, Config: testAccAWSLambdaEventSourceMappingConfigSelfManagedKafka(rName, "null"), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, }, }) } @@ -1333,8 +1323,8 @@ resource "aws_lambda_event_source_mapping" "test" { starting_position = "TRIM_HORIZON" self_managed_event_source { - endpoints { - kafka_bootstrap_servers = [ "test:9092" ] + endpoints = { + KAFKA_BOOTSTRAP_SERVERS = "test2:9092,test1:9092" } } diff --git a/aws/structure.go b/aws/structure.go index 9d68d11998a7..0cb141ede4eb 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -1674,20 +1674,22 @@ func flattenLambdaEventSourceMappingDestinationConfig(dest *lambda.DestinationCo return []interface{}{mDest} } -func expandLambdaEventSourceMappingSelfManagedEventSource(vSource []interface{}) *lambda.SelfManagedEventSource { - if len(vSource) == 0 { +func expandLambdaEventSourceMappingSelfManagedEventSource(configured []interface{}) *lambda.SelfManagedEventSource { + if len(configured) == 0 { return nil } source := &lambda.SelfManagedEventSource{} source.Endpoints = map[string][]*string{} - if len(vSource) > 0 { - if config, ok := vSource[0].(map[string]interface{}); ok { - if vEndpoints, ok := config["endpoints"].([]interface{}); ok { - mEndpoints := vEndpoints[0].(map[string]interface{}) - if kafkaBootstrapServers, ok := mEndpoints["kafka_bootstrap_servers"]; ok { - source.Endpoints["KAFKA_BOOTSTRAP_SERVERS"] = expandStringList(kafkaBootstrapServers.([]interface{})) + if config, ok := configured[0].(map[string]interface{}); ok { + if endpoints, ok := config["endpoints"].(map[string]interface{}); ok { + for key, value := range endpoints { + values := strings.Split(value.(string), ",") + source.Endpoints[key] = make([]*string, len(values)) + for i, value := range values { + valueCopy := value + source.Endpoints[key][i] = &valueCopy } } } @@ -1695,28 +1697,54 @@ func expandLambdaEventSourceMappingSelfManagedEventSource(vSource []interface{}) return source } -func flattenLambdaEventSourceMappingSelfManagedEventSource(source *lambda.SelfManagedEventSource) []interface{} { - mSource := map[string]interface{}{} - mEndpoints := map[string]interface{}{} - if source != nil { - if source.Endpoints != nil { - if kafkaBootstrapBrokers, ok := source.Endpoints["KAFKA_BOOTSTRAP_SERVERS"]; ok { - mEndpoints["kafka_bootstrap_servers"] = flattenStringList(kafkaBootstrapBrokers) - mSource["endpoints"] = []interface{}{mEndpoints} +func flattenLambdaEventSourceMappingSelfManagedEventSource(source *lambda.SelfManagedEventSource, d *schema.ResourceData) []interface{} { + if source == nil { + return nil + } + + if source.Endpoints == nil { + return nil + } + + endpoints := map[string]string{} + for key, values := range source.Endpoints { + sValues := make([]string, len(values)) + for i, value := range values { + sValues[i] = *value + } + // The AWS API sorts the list of brokers so try to order the string by what + // is in the TF file to prevent spurious diffs. + curValue, ok := d.Get("self_managed_event_source.0.endpoints." + key).(string) + if !ok { + curValue = "" + } + curValues := strings.Split(curValue, ",") + if len(sValues) == len(curValues) { + for i := 0; i < len(curValues); i++ { + for j := 0; j < len(sValues); j++ { + if curValues[i] == sValues[j] { + sValues[i], sValues[j] = sValues[j], sValues[i] + break + } + } } } + endpoints[key] = strings.Join(sValues, ",") } - if len(mSource) == 0 { + if len(endpoints) == 0 { return nil } - return []interface{}{mSource} + config := map[string]interface{}{} + config["endpoints"] = endpoints + + return []interface{}{config} } -func expandLambdaEventSourceMappingSourceAccessConfigurations(v []interface{}) []*lambda.SourceAccessConfiguration { - accesses := make([]*lambda.SourceAccessConfiguration, 0, len(v)) - for _, m := range v { +func expandLambdaEventSourceMappingSourceAccessConfigurations(configured []interface{}) []*lambda.SourceAccessConfiguration { + accesses := make([]*lambda.SourceAccessConfiguration, 0, len(configured)) + for _, m := range configured { config := m.(map[string]interface{}) accesses = append(accesses, &lambda.SourceAccessConfiguration{ Type: aws.String(config["type"].(string)), @@ -1740,12 +1768,13 @@ func flattenLambdaEventSourceMappingSourceAccessConfigurations(accesses []*lambd } // The result returned from AWS is sorted so try to order it like the original to prevent spurious diffs if curCount, ok := d.Get("source_access_configuration.#").(int); ok { - for i := 0; i < curCount; i++ { - if curSetting, ok := d.Get("source_access_configuration." + strconv.Itoa(i)).(map[string]interface{}); ok { - for j := 0; j < len(settings); j++ { - if curSetting["type"] == *settings[j]["type"].(*string) && - curSetting["uri"] == *settings[j]["uri"].(*string) { - settings[i], settings[j] = settings[j], settings[i] + if curCount == len(settings) { + for i := 0; i < curCount; i++ { + if curSetting, ok := d.Get("source_access_configuration." + strconv.Itoa(i)).(map[string]interface{}); ok { + for j := 0; j < len(settings); j++ { + if curSetting["type"] == *settings[j]["type"].(*string) && curSetting["uri"] == *settings[j]["uri"].(*string) { + settings[i], settings[j] = settings[j], settings[i] + } } } } diff --git a/website/docs/r/lambda_event_source_mapping.html.markdown b/website/docs/r/lambda_event_source_mapping.html.markdown index 9ffda81bef36..923a93fe0c50 100644 --- a/website/docs/r/lambda_event_source_mapping.html.markdown +++ b/website/docs/r/lambda_event_source_mapping.html.markdown @@ -46,6 +46,36 @@ resource "aws_lambda_event_source_mapping" "example" { } ``` +### Self Managed Apache Kafka + +```terraform +resource "aws_lambda_event_source_mapping" "example" { + function_name = aws_lambda_function.example.arn + topics = ["Example"] + starting_position = "TRIM_HORIZON" + + self_managed_event_source { + endpoints = { + KAFKA_BOOTSTRAP_SERVERS = "kafka1.example.com:9092,kafka2.example.com:9092" + } + } + + source_access_configuration { + type = "VPC_SUBNET" + uri = "subnet:subnet-example1" + } + + source_access_configuration { + type = "VPC_SUBNET" + uri = "subnet:subnet-example2" + } + + source_access_configuration { + type = "VPC_SECURITY_GROUP" + uri = "security_group:sg-example" + } +}``` + ### SQS ```terraform @@ -59,7 +89,7 @@ resource "aws_lambda_event_source_mapping" "example" { * `batch_size` - (Optional) The largest number of records that Lambda will retrieve from your event source at the time of invocation. Defaults to `100` for DynamoDB, Kinesis and MSK, `10` for SQS. * `maximum_batching_window_in_seconds` - (Optional) The maximum amount of time to gather records before invoking the function, in seconds (between 0 and 300). Records will continue to buffer (or accumulate in the case of an SQS queue event source) until either `maximum_batching_window_in_seconds` expires or `batch_size` has been met. For streaming event sources, defaults to as soon as records are available in the stream. If the batch it reads from the stream/queue only has one record in it, Lambda only sends one record to the function. Only available for stream sources (DynamoDB and Kinesis) and SQS standard queues. -* `event_source_arn` - (Required) The event source ARN - can be a Kinesis stream, DynamoDB stream, SQS queue or MSK cluster. +* `event_source_arn` - (Optional) The event source ARN - this is required for Kinesis stream, DynamoDB stream, SQS queue or MSK cluster. It is incompatible with a Self Managed Kafka source. * `enabled` - (Optional) Determines if the mapping will be enabled on creation. Defaults to `true`. * `function_name` - (Required) The name or the ARN of the Lambda function that will be subscribing to events. * `starting_position` - (Optional) The position in the stream where AWS Lambda should start reading. Must be one of `AT_TIMESTAMP` (Kinesis only), `LATEST` or `TRIM_HORIZON` if getting events from Kinesis, DynamoDB or MSK. Must not be provided if getting events from SQS. More information about these positions can be found in the [AWS DynamoDB Streams API Reference](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_GetShardIterator.html) and [AWS Kinesis API Reference](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html#Kinesis-GetShardIterator-request-ShardIteratorType). @@ -70,6 +100,8 @@ resource "aws_lambda_event_source_mapping" "example" { * `bisect_batch_on_function_error`: - (Optional) If the function returns an error, split the batch in two and retry. Only available for stream sources (DynamoDB and Kinesis). Defaults to `false`. * `topics` - (Optional) The name of the Kafka topics. Only available for MSK sources. A single topic name must be specified. * `destination_config`: - (Optional) An Amazon SQS queue or Amazon SNS topic destination for failed records. Only available for stream sources (DynamoDB and Kinesis). Detailed below. +* `self_managed_event_source`: - (Optional) For Self Managed Kafka sources, the location of the self managed cluster. Detailed below. +* `source_access_configuration`: (Optional) For Self Managed Kafka sources, the access configuration for the source. Detailed below. ### destination_config Configuration Block @@ -79,6 +111,15 @@ resource "aws_lambda_event_source_mapping" "example" { * `destination_arn` - (Required) The Amazon Resource Name (ARN) of the destination resource. +### self_managed_event_source Configuration Block + +* `endpoints` - (Required) A map of endpoints for the self managed source. For Kafka self-managed sources, the key should be `KAFKA_BOOTSTRAP_SERVERS` and the value should be a string with a comma separated list of broker endpoints. + +### source_access_configuration Configuration Block + +* `type` - (Required) The type of this configuration. For Self Managed Kafka you will need to supply blocks for type `VPC_SUBNET` and `VPC_SECURITY_GROUP`. +* `uri` - (Required) The URI for this configuration. For type `VPC_SUBNET` the value should be `subnet:subnet_id` where `subnet_id` is the value you would find in an aws_subnet resource's id attribute. For type `VPC_SECURITY_GROUP` the value should be `security_group:security_group_id` where `security_group_id` is the value you would find in an aws_security_group resource's id attribute. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From b6266c16712054d4ead6d2fcef0dfc6ead541a0f Mon Sep 17 00:00:00 2001 From: Robert Christ Date: Wed, 19 May 2021 15:15:20 -0700 Subject: [PATCH 0056/1208] Add ExactlyOneOf to both event_source_arn and self_managed_event_source. --- aws/resource_aws_lambda_event_source_mapping.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index d412cf5c62c5..1aa480b3e175 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -33,9 +33,10 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { Schema: map[string]*schema.Schema{ "event_source_arn": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ExactlyOneOf: []string{"event_source_arn", "self_managed_event_source"}, }, "function_name": { Type: schema.TypeString, @@ -164,10 +165,11 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { }, }, "self_managed_event_source": { - Type: schema.TypeList, - Optional: true, - MinItems: 1, - MaxItems: 1, + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + ExactlyOneOf: []string{"event_source_arn", "self_managed_event_source"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "endpoints": { From bfe1b734c3c1b7127dd7ef37a3dd3eaaf5391e4f Mon Sep 17 00:00:00 2001 From: Robert Christ Date: Thu, 20 May 2021 09:50:46 -0700 Subject: [PATCH 0057/1208] Move the expands and flatten functions to resource_aws_lambda_event_source_mapping.go from structure.go. Add RequiredWith schema constraing to self_managed_event_source and source_access_configuration. --- ...esource_aws_lambda_event_source_mapping.go | 119 +++++++++++++++++- aws/structure.go | 109 ---------------- 2 files changed, 116 insertions(+), 112 deletions(-) diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index 1aa480b3e175..1fdbeca07b2c 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -3,6 +3,8 @@ package aws import ( "fmt" "log" + "strconv" + "strings" "time" "github.com/aws/aws-sdk-go/aws" @@ -170,6 +172,7 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { MinItems: 1, MaxItems: 1, ExactlyOneOf: []string{"event_source_arn", "self_managed_event_source"}, + RequiredWith: []string{"self_managed_event_source", "source_access_configuration"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "endpoints": { @@ -182,9 +185,10 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { }, }, "source_access_configuration": { - Type: schema.TypeList, - Optional: true, - MinItems: 1, + Type: schema.TypeList, + Optional: true, + MinItems: 1, + RequiredWith: []string{"self_managed_event_source", "source_access_configuration"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "type": { @@ -534,3 +538,112 @@ func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta inte return resourceAwsLambdaEventSourceMappingRead(d, meta) } + +func expandLambdaEventSourceMappingSelfManagedEventSource(configured []interface{}) *lambda.SelfManagedEventSource { + if len(configured) == 0 { + return nil + } + + source := &lambda.SelfManagedEventSource{} + source.Endpoints = map[string][]*string{} + + if config, ok := configured[0].(map[string]interface{}); ok { + if endpoints, ok := config["endpoints"].(map[string]interface{}); ok { + for key, value := range endpoints { + values := strings.Split(value.(string), ",") + source.Endpoints[key] = make([]*string, len(values)) + for i, value := range values { + valueCopy := value + source.Endpoints[key][i] = &valueCopy + } + } + } + } + return source +} + +func flattenLambdaEventSourceMappingSelfManagedEventSource(source *lambda.SelfManagedEventSource, d *schema.ResourceData) []interface{} { + if source == nil { + return nil + } + + if source.Endpoints == nil { + return nil + } + + endpoints := map[string]string{} + for key, values := range source.Endpoints { + sValues := make([]string, len(values)) + for i, value := range values { + sValues[i] = *value + } + // The AWS API sorts the list of brokers so try to order the string by what + // is in the TF file to prevent spurious diffs. + curValue, ok := d.Get("self_managed_event_source.0.endpoints." + key).(string) + if !ok { + curValue = "" + } + curValues := strings.Split(curValue, ",") + if len(sValues) == len(curValues) { + for i := 0; i < len(curValues); i++ { + for j := 0; j < len(sValues); j++ { + if curValues[i] == sValues[j] { + sValues[i], sValues[j] = sValues[j], sValues[i] + break + } + } + } + } + endpoints[key] = strings.Join(sValues, ",") + } + + if len(endpoints) == 0 { + return nil + } + + config := map[string]interface{}{} + config["endpoints"] = endpoints + + return []interface{}{config} +} + +func expandLambdaEventSourceMappingSourceAccessConfigurations(configured []interface{}) []*lambda.SourceAccessConfiguration { + accesses := make([]*lambda.SourceAccessConfiguration, 0, len(configured)) + for _, m := range configured { + config := m.(map[string]interface{}) + accesses = append(accesses, &lambda.SourceAccessConfiguration{ + Type: aws.String(config["type"].(string)), + URI: aws.String(config["uri"].(string)), + }) + } + return accesses +} + +func flattenLambdaEventSourceMappingSourceAccessConfigurations(accesses []*lambda.SourceAccessConfiguration, d *schema.ResourceData) []map[string]interface{} { + if accesses == nil { + return nil + } + settings := make([]map[string]interface{}, len(accesses)) + + for i, access := range accesses { + setting := make(map[string]interface{}) + setting["type"] = access.Type + setting["uri"] = access.URI + settings[i] = setting + } + // The result returned from AWS is sorted so try to order it like the original to prevent spurious diffs + if curCount, ok := d.Get("source_access_configuration.#").(int); ok { + if curCount == len(settings) { + for i := 0; i < curCount; i++ { + if curSetting, ok := d.Get("source_access_configuration." + strconv.Itoa(i)).(map[string]interface{}); ok { + for j := 0; j < len(settings); j++ { + if curSetting["type"] == *settings[j]["type"].(*string) && curSetting["uri"] == *settings[j]["uri"].(*string) { + settings[i], settings[j] = settings[j], settings[i] + } + } + } + } + } + } + return settings +} diff --git a/aws/structure.go b/aws/structure.go index 0cb141ede4eb..f515bceca76a 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -1674,115 +1674,6 @@ func flattenLambdaEventSourceMappingDestinationConfig(dest *lambda.DestinationCo return []interface{}{mDest} } -func expandLambdaEventSourceMappingSelfManagedEventSource(configured []interface{}) *lambda.SelfManagedEventSource { - if len(configured) == 0 { - return nil - } - - source := &lambda.SelfManagedEventSource{} - source.Endpoints = map[string][]*string{} - - if config, ok := configured[0].(map[string]interface{}); ok { - if endpoints, ok := config["endpoints"].(map[string]interface{}); ok { - for key, value := range endpoints { - values := strings.Split(value.(string), ",") - source.Endpoints[key] = make([]*string, len(values)) - for i, value := range values { - valueCopy := value - source.Endpoints[key][i] = &valueCopy - } - } - } - } - return source -} - -func flattenLambdaEventSourceMappingSelfManagedEventSource(source *lambda.SelfManagedEventSource, d *schema.ResourceData) []interface{} { - if source == nil { - return nil - } - - if source.Endpoints == nil { - return nil - } - - endpoints := map[string]string{} - for key, values := range source.Endpoints { - sValues := make([]string, len(values)) - for i, value := range values { - sValues[i] = *value - } - // The AWS API sorts the list of brokers so try to order the string by what - // is in the TF file to prevent spurious diffs. - curValue, ok := d.Get("self_managed_event_source.0.endpoints." + key).(string) - if !ok { - curValue = "" - } - curValues := strings.Split(curValue, ",") - if len(sValues) == len(curValues) { - for i := 0; i < len(curValues); i++ { - for j := 0; j < len(sValues); j++ { - if curValues[i] == sValues[j] { - sValues[i], sValues[j] = sValues[j], sValues[i] - break - } - } - } - } - endpoints[key] = strings.Join(sValues, ",") - } - - if len(endpoints) == 0 { - return nil - } - - config := map[string]interface{}{} - config["endpoints"] = endpoints - - return []interface{}{config} -} - -func expandLambdaEventSourceMappingSourceAccessConfigurations(configured []interface{}) []*lambda.SourceAccessConfiguration { - accesses := make([]*lambda.SourceAccessConfiguration, 0, len(configured)) - for _, m := range configured { - config := m.(map[string]interface{}) - accesses = append(accesses, &lambda.SourceAccessConfiguration{ - Type: aws.String(config["type"].(string)), - URI: aws.String(config["uri"].(string)), - }) - } - return accesses -} - -func flattenLambdaEventSourceMappingSourceAccessConfigurations(accesses []*lambda.SourceAccessConfiguration, d *schema.ResourceData) []map[string]interface{} { - if accesses == nil { - return nil - } - settings := make([]map[string]interface{}, len(accesses)) - - for i, access := range accesses { - setting := make(map[string]interface{}) - setting["type"] = access.Type - setting["uri"] = access.URI - settings[i] = setting - } - // The result returned from AWS is sorted so try to order it like the original to prevent spurious diffs - if curCount, ok := d.Get("source_access_configuration.#").(int); ok { - if curCount == len(settings) { - for i := 0; i < curCount; i++ { - if curSetting, ok := d.Get("source_access_configuration." + strconv.Itoa(i)).(map[string]interface{}); ok { - for j := 0; j < len(settings); j++ { - if curSetting["type"] == *settings[j]["type"].(*string) && curSetting["uri"] == *settings[j]["uri"].(*string) { - settings[i], settings[j] = settings[j], settings[i] - } - } - } - } - } - } - return settings -} - func flattenLambdaLayers(layers []*lambda.Layer) []interface{} { arns := make([]*string, len(layers)) for i, layer := range layers { From 76d894ab6ed1d4980a0d5f8b3c9f4c84e1758a70 Mon Sep 17 00:00:00 2001 From: Robert Christ Date: Thu, 20 May 2021 09:53:49 -0700 Subject: [PATCH 0058/1208] Update document to indicate schema requirement that self_managed_event_source and source_acccess_configuration must be set together. --- website/docs/r/lambda_event_source_mapping.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/lambda_event_source_mapping.html.markdown b/website/docs/r/lambda_event_source_mapping.html.markdown index 923a93fe0c50..13d956116c18 100644 --- a/website/docs/r/lambda_event_source_mapping.html.markdown +++ b/website/docs/r/lambda_event_source_mapping.html.markdown @@ -100,8 +100,8 @@ resource "aws_lambda_event_source_mapping" "example" { * `bisect_batch_on_function_error`: - (Optional) If the function returns an error, split the batch in two and retry. Only available for stream sources (DynamoDB and Kinesis). Defaults to `false`. * `topics` - (Optional) The name of the Kafka topics. Only available for MSK sources. A single topic name must be specified. * `destination_config`: - (Optional) An Amazon SQS queue or Amazon SNS topic destination for failed records. Only available for stream sources (DynamoDB and Kinesis). Detailed below. -* `self_managed_event_source`: - (Optional) For Self Managed Kafka sources, the location of the self managed cluster. Detailed below. -* `source_access_configuration`: (Optional) For Self Managed Kafka sources, the access configuration for the source. Detailed below. +* `self_managed_event_source`: - (Optional) For Self Managed Kafka sources, the location of the self managed cluster. Detailed below. If set, configuration must also include `source_access_configuration`. +* `source_access_configuration`: (Optional) For Self Managed Kafka sources, the access configuration for the source. Detailed below. If set, configuration must also include `self_managed_event_source`. ### destination_config Configuration Block From 9f16299e76645bb5f8941e45ad429e53ce1d2e35 Mon Sep 17 00:00:00 2001 From: Robert Christ Date: Thu, 20 May 2021 10:00:27 -0700 Subject: [PATCH 0059/1208] Documentation formatting. --- website/docs/r/lambda_event_source_mapping.html.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/r/lambda_event_source_mapping.html.markdown b/website/docs/r/lambda_event_source_mapping.html.markdown index 13d956116c18..a0833359aca0 100644 --- a/website/docs/r/lambda_event_source_mapping.html.markdown +++ b/website/docs/r/lambda_event_source_mapping.html.markdown @@ -74,7 +74,8 @@ resource "aws_lambda_event_source_mapping" "example" { type = "VPC_SECURITY_GROUP" uri = "security_group:sg-example" } -}``` +} +``` ### SQS From 4a42925e1ee3476f782449f09672ddfe03eb5153 Mon Sep 17 00:00:00 2001 From: Robert Christ Date: Thu, 20 May 2021 10:02:19 -0700 Subject: [PATCH 0060/1208] Documentation word ordering. --- website/docs/r/lambda_event_source_mapping.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/lambda_event_source_mapping.html.markdown b/website/docs/r/lambda_event_source_mapping.html.markdown index a0833359aca0..6bb1476364f4 100644 --- a/website/docs/r/lambda_event_source_mapping.html.markdown +++ b/website/docs/r/lambda_event_source_mapping.html.markdown @@ -101,8 +101,8 @@ resource "aws_lambda_event_source_mapping" "example" { * `bisect_batch_on_function_error`: - (Optional) If the function returns an error, split the batch in two and retry. Only available for stream sources (DynamoDB and Kinesis). Defaults to `false`. * `topics` - (Optional) The name of the Kafka topics. Only available for MSK sources. A single topic name must be specified. * `destination_config`: - (Optional) An Amazon SQS queue or Amazon SNS topic destination for failed records. Only available for stream sources (DynamoDB and Kinesis). Detailed below. -* `self_managed_event_source`: - (Optional) For Self Managed Kafka sources, the location of the self managed cluster. Detailed below. If set, configuration must also include `source_access_configuration`. -* `source_access_configuration`: (Optional) For Self Managed Kafka sources, the access configuration for the source. Detailed below. If set, configuration must also include `self_managed_event_source`. +* `self_managed_event_source`: - (Optional) For Self Managed Kafka sources, the location of the self managed cluster. If set, configuration must also include `source_access_configuration`. Detailed below. +* `source_access_configuration`: (Optional) For Self Managed Kafka sources, the access configuration for the source. If set, configuration must also include `self_managed_event_source`. Detailed below. ### destination_config Configuration Block From 31540bfe7c7e14f44d535599064f183b9854e1da Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 26 May 2021 09:15:12 -0400 Subject: [PATCH 0061/1208] r/aws_lambda_event_source_mapping: Change 'source_access_configuration' to TypeSet and add DiffSuppressFunc for 'self_managed_event_source.endpoints.KAFKA_BOOTSTRAP_SERVERS'. --- ...esource_aws_lambda_event_source_mapping.go | 655 ++++++++++-------- ...ce_aws_lambda_event_source_mapping_test.go | 528 ++++++-------- aws/structure.go | 39 -- 3 files changed, 597 insertions(+), 625 deletions(-) diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index 1fdbeca07b2c..5752cad2b956 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -3,16 +3,14 @@ package aws import ( "fmt" "log" - "strconv" + "reflect" + "sort" "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/service/dynamodb" - "github.com/aws/aws-sdk-go/service/kinesis" "github.com/aws/aws-sdk-go/service/lambda" - "github.com/aws/aws-sdk-go/service/sqs" "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -34,42 +32,6 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "event_source_arn": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ExactlyOneOf: []string{"event_source_arn", "self_managed_event_source"}, - }, - "function_name": { - Type: schema.TypeString, - Required: true, - DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - // Using function name or ARN should not be shown as a diff. - // Try to convert the old and new values from ARN to function name - oldFunctionName, oldFunctionNameErr := getFunctionNameFromLambdaArn(old) - newFunctionName, newFunctionNameErr := getFunctionNameFromLambdaArn(new) - return (oldFunctionName == new && oldFunctionNameErr == nil) || (newFunctionName == old && newFunctionNameErr == nil) - }, - }, - "starting_position": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice(lambda.EventSourcePosition_Values(), false), - }, - "starting_position_timestamp": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ValidateFunc: validation.IsRFC3339Time, - }, - "topics": { - Type: schema.TypeSet, - Optional: true, - ForceNew: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, "batch_size": { Type: schema.TypeInt, Optional: true, @@ -83,69 +45,37 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { return false } - serviceName := "" + var serviceName string if v, ok := d.GetOk("event_source_arn"); ok { eventSourceARN, err := arn.Parse(v.(string)) if err != nil { return false } + serviceName = eventSourceARN.Service - } else { - // self managed kafka does not have an event_source_arn + } else if _, ok := d.GetOk("self_managed_event_source"); ok { serviceName = "kafka" } + switch serviceName { - // kafka.ServiceName is "kafka". - case dynamodb.ServiceName, kinesis.ServiceName, "kafka": - if old == "100" { - return true - } - case sqs.ServiceName: - if old == "10" { - return true - } + case "dynamodb", "kinesis", "kafka": + return old == "100" + case "sqs": + return old == "10" } - return false + + return old == new }, }, - "enabled": { - Type: schema.TypeBool, - Optional: true, - Default: true, - }, - "maximum_batching_window_in_seconds": { - Type: schema.TypeInt, - Optional: true, - }, - "parallelization_factor": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IntBetween(1, 10), - Computed: true, - }, - "maximum_retry_attempts": { - Type: schema.TypeInt, - Optional: true, - Computed: true, - ValidateFunc: validation.IntBetween(-1, 10_000), - }, - "maximum_record_age_in_seconds": { - Type: schema.TypeInt, - Optional: true, - Computed: true, - ValidateFunc: validation.Any( - validation.IntInSlice([]int{-1}), - validation.IntBetween(60, 604_800), - ), - }, + "bisect_batch_on_function_error": { Type: schema.TypeBool, Optional: true, }, + "destination_config": { Type: schema.TypeList, Optional: true, - MinItems: 1, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -165,14 +95,83 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { }, }, }, + DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, }, - "self_managed_event_source": { - Type: schema.TypeList, + + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "event_source_arn": { + Type: schema.TypeString, Optional: true, - MinItems: 1, - MaxItems: 1, + ForceNew: true, ExactlyOneOf: []string{"event_source_arn", "self_managed_event_source"}, - RequiredWith: []string{"self_managed_event_source", "source_access_configuration"}, + }, + + "function_arn": { + Type: schema.TypeString, + Computed: true, + }, + + "function_name": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // Using function name or ARN should not be shown as a diff. + // Try to convert the old and new values from ARN to function name + oldFunctionName, oldFunctionNameErr := getFunctionNameFromLambdaArn(old) + newFunctionName, newFunctionNameErr := getFunctionNameFromLambdaArn(new) + return (oldFunctionName == new && oldFunctionNameErr == nil) || (newFunctionName == old && newFunctionNameErr == nil) + }, + }, + + "last_modified": { + Type: schema.TypeString, + Computed: true, + }, + + "last_processing_result": { + Type: schema.TypeString, + Computed: true, + }, + + "maximum_batching_window_in_seconds": { + Type: schema.TypeInt, + Optional: true, + }, + + "maximum_record_age_in_seconds": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.Any( + validation.IntInSlice([]int{-1}), + validation.IntBetween(60, 604_800), + ), + }, + + "maximum_retry_attempts": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(-1, 10_000), + }, + + "parallelization_factor": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 10), + Computed: true, + }, + + "self_managed_event_source": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "endpoints": { @@ -180,20 +179,36 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { Required: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if k == "self_managed_event_source.0.endpoints.KAFKA_BOOTSTRAP_SERVERS" { + // AWS returns the bootstrap brokers in sorted order. + olds := strings.Split(old, ",") + sort.Strings(olds) + news := strings.Split(new, ",") + sort.Strings(news) + + return reflect.DeepEqual(olds, news) + } + + return old == new + }, }, }, }, + ExactlyOneOf: []string{"event_source_arn", "self_managed_event_source"}, + RequiredWith: []string{"source_access_configuration"}, }, + "source_access_configuration": { - Type: schema.TypeList, - Optional: true, - MinItems: 1, - RequiredWith: []string{"self_managed_event_source", "source_access_configuration"}, + Type: schema.TypeSet, + Optional: true, + MaxItems: 22, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "type": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(lambda.SourceAccessType_Values(), false), }, "uri": { Type: schema.TypeString, @@ -201,27 +216,40 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { }, }, }, + RequiredWith: []string{"self_managed_event_source"}, }, - "function_arn": { - Type: schema.TypeString, - Computed: true, - }, - "last_modified": { - Type: schema.TypeString, - Computed: true, + + "starting_position": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(lambda.EventSourcePosition_Values(), false), }, - "last_processing_result": { - Type: schema.TypeString, - Computed: true, + + "starting_position_timestamp": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IsRFC3339Time, }, + "state": { Type: schema.TypeString, Computed: true, }, + "state_transition_reason": { Type: schema.TypeString, Computed: true, }, + + "topics": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "uuid": { Type: schema.TypeString, Computed: true, @@ -230,18 +258,16 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { } } -// resourceAwsLambdaEventSourceMappingCreate maps to: -// CreateEventSourceMapping in the API / SDK func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).lambdaconn + functionName := d.Get("function_name").(string) input := &lambda.CreateEventSourceMappingInput{ - Enabled: aws.Bool(d.Get("enabled").(bool)), + Enabled: aws.Bool(d.Get("enabled").(bool)), + FunctionName: aws.String(functionName), } - if v, ok := d.GetOk("function_name"); ok { - input.FunctionName = aws.String(v.(string)) - } + var target string if v, ok := d.GetOk("batch_size"); ok { input.BatchSize = aws.Int64(int64(v.(int))) @@ -251,12 +277,15 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte input.BisectBatchOnFunctionError = aws.Bool(v.(bool)) } - if vDest, ok := d.GetOk("destination_config"); ok { - input.DestinationConfig = expandLambdaEventSourceMappingDestinationConfig(vDest.([]interface{})) + if v, ok := d.GetOk("destination_config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DestinationConfig = expandLambdaDestinationConfig(v.([]interface{})[0].(map[string]interface{})) } if v, ok := d.GetOk("event_source_arn"); ok { - input.EventSourceArn = aws.String(v.(string)) + v := v.(string) + + input.EventSourceArn = aws.String(v) + target = v } if v, ok := d.GetOk("maximum_batching_window_in_seconds"); ok { @@ -275,6 +304,16 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte input.ParallelizationFactor = aws.Int64(int64(v.(int))) } + if v, ok := d.GetOk("self_managed_event_source"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.SelfManagedEventSource = expandLambdaSelfManagedEventSource(v.([]interface{})[0].(map[string]interface{})) + + target = "Self-Managed Apache Kafka" + } + + if v, ok := d.GetOk("source_access_configuration"); ok && v.(*schema.Set).Len() > 0 { + input.SourceAccessConfigurations = expandLambdaSourceAccessConfigurations(v.(*schema.Set).List()) + } + if v, ok := d.GetOk("starting_position"); ok { input.StartingPosition = aws.String(v.(string)) } @@ -285,21 +324,10 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte input.StartingPositionTimestamp = aws.Time(t) } - if v, ok := d.GetOk("self_managed_event_source"); ok { - input.SelfManagedEventSource = expandLambdaEventSourceMappingSelfManagedEventSource(v.([]interface{})) - } - - if v, ok := d.GetOk("source_access_configuration"); ok { - input.SourceAccessConfigurations = expandLambdaEventSourceMappingSourceAccessConfigurations(v.([]interface{})) - } - if v, ok := d.GetOk("topics"); ok && v.(*schema.Set).Len() > 0 { input.Topics = expandStringSet(v.(*schema.Set)) } - // When non-ARN targets are supported, set target to the non-nil value. - target := input.EventSourceArn - log.Printf("[DEBUG] Creating Lambda Event Source Mapping: %s", input) // IAM profiles and roles can take some time to propagate in AWS: @@ -330,7 +358,7 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte } if err != nil { - return fmt.Errorf("error creating Lambda Event Source Mapping (%s): %w", aws.StringValue(target), err) + return fmt.Errorf("error creating Lambda Event Source Mapping (%s): %w", target, err) } d.SetId(aws.StringValue(eventSourceMappingConfiguration.UUID)) @@ -342,8 +370,6 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte return resourceAwsLambdaEventSourceMappingRead(d, meta) } -// resourceAwsLambdaEventSourceMappingRead maps to: -// GetEventSourceMapping in the API / SDK func resourceAwsLambdaEventSourceMappingRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).lambdaconn @@ -360,103 +386,61 @@ func resourceAwsLambdaEventSourceMappingRead(d *schema.ResourceData, meta interf } d.Set("batch_size", eventSourceMappingConfiguration.BatchSize) - d.Set("maximum_batching_window_in_seconds", eventSourceMappingConfiguration.MaximumBatchingWindowInSeconds) + d.Set("bisect_batch_on_function_error", eventSourceMappingConfiguration.BisectBatchOnFunctionError) + if eventSourceMappingConfiguration.DestinationConfig != nil { + if err := d.Set("destination_config", []interface{}{flattenLambdaDestinationConfig(eventSourceMappingConfiguration.DestinationConfig)}); err != nil { + return fmt.Errorf("error setting destination_config: %w", err) + } + } else { + d.Set("destination_config", nil) + } d.Set("event_source_arn", eventSourceMappingConfiguration.EventSourceArn) d.Set("function_arn", eventSourceMappingConfiguration.FunctionArn) - d.Set("last_modified", aws.TimeValue(eventSourceMappingConfiguration.LastModified).Format(time.RFC3339)) - d.Set("last_processing_result", eventSourceMappingConfiguration.LastProcessingResult) - d.Set("state", eventSourceMappingConfiguration.State) - d.Set("state_transition_reason", eventSourceMappingConfiguration.StateTransitionReason) - d.Set("uuid", eventSourceMappingConfiguration.UUID) d.Set("function_name", eventSourceMappingConfiguration.FunctionArn) - d.Set("parallelization_factor", eventSourceMappingConfiguration.ParallelizationFactor) - d.Set("maximum_retry_attempts", eventSourceMappingConfiguration.MaximumRetryAttempts) - d.Set("maximum_record_age_in_seconds", eventSourceMappingConfiguration.MaximumRecordAgeInSeconds) - d.Set("bisect_batch_on_function_error", eventSourceMappingConfiguration.BisectBatchOnFunctionError) - if err := d.Set("destination_config", flattenLambdaEventSourceMappingDestinationConfig(eventSourceMappingConfiguration.DestinationConfig)); err != nil { - return fmt.Errorf("error setting destination_config: %w", err) - } - if err := d.Set("topics", flattenStringSet(eventSourceMappingConfiguration.Topics)); err != nil { - return fmt.Errorf("error setting topics: %w", err) + if eventSourceMappingConfiguration.LastModified != nil { + d.Set("last_modified", aws.TimeValue(eventSourceMappingConfiguration.LastModified).Format(time.RFC3339)) + } else { + d.Set("last_modified", nil) } - if err := d.Set("self_managed_event_source", flattenLambdaEventSourceMappingSelfManagedEventSource(eventSourceMappingConfiguration.SelfManagedEventSource, d)); err != nil { - return fmt.Errorf("error setting self_managed_event_source: %w", err) + d.Set("last_processing_result", eventSourceMappingConfiguration.LastProcessingResult) + d.Set("maximum_batching_window_in_seconds", eventSourceMappingConfiguration.MaximumBatchingWindowInSeconds) + d.Set("maximum_record_age_in_seconds", eventSourceMappingConfiguration.MaximumRecordAgeInSeconds) + d.Set("maximum_retry_attempts", eventSourceMappingConfiguration.MaximumRetryAttempts) + d.Set("parallelization_factor", eventSourceMappingConfiguration.ParallelizationFactor) + if eventSourceMappingConfiguration.SelfManagedEventSource != nil { + if err := d.Set("self_managed_event_source", []interface{}{flattenLambdaSelfManagedEventSource(eventSourceMappingConfiguration.SelfManagedEventSource)}); err != nil { + return fmt.Errorf("error setting self_managed_event_source: %w", err) + } + } else { + d.Set("self_managed_event_source", nil) } - if err := d.Set("source_access_configuration", flattenLambdaEventSourceMappingSourceAccessConfigurations(eventSourceMappingConfiguration.SourceAccessConfigurations, d)); err != nil { + if err := d.Set("source_access_configuration", flattenLambdaSourceAccessConfigurations(eventSourceMappingConfiguration.SourceAccessConfigurations)); err != nil { return fmt.Errorf("error setting source_access_configuration: %w", err) } - d.Set("starting_position", eventSourceMappingConfiguration.StartingPosition) if eventSourceMappingConfiguration.StartingPositionTimestamp != nil { d.Set("starting_position_timestamp", aws.TimeValue(eventSourceMappingConfiguration.StartingPositionTimestamp).Format(time.RFC3339)) } else { d.Set("starting_position_timestamp", nil) } + d.Set("state", eventSourceMappingConfiguration.State) + d.Set("state_transition_reason", eventSourceMappingConfiguration.StateTransitionReason) + d.Set("topics", aws.StringValueSlice(eventSourceMappingConfiguration.Topics)) + d.Set("uuid", eventSourceMappingConfiguration.UUID) - state := aws.StringValue(eventSourceMappingConfiguration.State) - - switch state { + switch state := d.Get("state").(string); state { case waiter.EventSourceMappingStateEnabled, waiter.EventSourceMappingStateEnabling: d.Set("enabled", true) case waiter.EventSourceMappingStateDisabled, waiter.EventSourceMappingStateDisabling: d.Set("enabled", false) default: - log.Printf("[WARN] Lambda Event Source Mapping is neither enabled nor disabled but %s", state) - } - - return nil -} - -// resourceAwsLambdaEventSourceMappingDelete maps to: -// DeleteEventSourceMapping in the API / SDK -func resourceAwsLambdaEventSourceMappingDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).lambdaconn - - log.Printf("[INFO] Deleting Lambda Event Source Mapping: %s", d.Id()) - - input := &lambda.DeleteEventSourceMappingInput{ - UUID: aws.String(d.Id()), - } - - err := resource.Retry(waiter.EventSourceMappingPropagationTimeout, func() *resource.RetryError { - _, err := conn.DeleteEventSourceMapping(input) - - if tfawserr.ErrCodeEquals(err, lambda.ErrCodeResourceNotFoundException) { - return nil - } - - if tfawserr.ErrCodeEquals(err, lambda.ErrCodeResourceInUseException) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return nil - }) - - if tfresource.TimedOut(err) { - _, err = conn.DeleteEventSourceMapping(input) - } - - if tfawserr.ErrCodeEquals(err, lambda.ErrCodeResourceNotFoundException) { - return nil - } - - if err != nil { - return fmt.Errorf("error deleting Lambda Event Source Mapping (%s): %w", d.Id(), err) - } - - if _, err := waiter.EventSourceMappingDelete(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for Lambda Event Source Mapping (%s) to delete: %w", d.Id(), err) + log.Printf("[WARN] Lambda Event Source Mapping (%s) is neither enabled nor disabled, but %s", d.Id(), state) + d.Set("enabled", nil) } return nil } -// resourceAwsLambdaEventSourceMappingUpdate maps to: -// UpdateEventSourceMapping in the API / SDK func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).lambdaconn @@ -475,7 +459,9 @@ func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta inte } if d.HasChange("destination_config") { - input.DestinationConfig = expandLambdaEventSourceMappingDestinationConfig(d.Get("destination_config").([]interface{})) + if v, ok := d.GetOk("destination_config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DestinationConfig = expandLambdaDestinationConfig(v.([]interface{})[0].(map[string]interface{})) + } } if d.HasChange("enabled") { @@ -503,7 +489,9 @@ func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta inte } if d.HasChange("source_access_configuration") { - input.SourceAccessConfigurations = expandLambdaEventSourceMappingSourceAccessConfigurations(d.Get("source_access_configuration").([]interface{})) + if v, ok := d.GetOk("source_access_configuration"); ok && v.(*schema.Set).Len() > 0 { + input.SourceAccessConfigurations = expandLambdaSourceAccessConfigurations(v.(*schema.Set).List()) + } } err := resource.Retry(waiter.EventSourceMappingPropagationTimeout, func() *resource.RetryError { @@ -539,111 +527,220 @@ func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta inte return resourceAwsLambdaEventSourceMappingRead(d, meta) } -func expandLambdaEventSourceMappingSelfManagedEventSource(configured []interface{}) *lambda.SelfManagedEventSource { - if len(configured) == 0 { - return nil +func resourceAwsLambdaEventSourceMappingDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lambdaconn + + log.Printf("[INFO] Deleting Lambda Event Source Mapping: %s", d.Id()) + + input := &lambda.DeleteEventSourceMappingInput{ + UUID: aws.String(d.Id()), } - source := &lambda.SelfManagedEventSource{} - source.Endpoints = map[string][]*string{} + err := resource.Retry(waiter.EventSourceMappingPropagationTimeout, func() *resource.RetryError { + _, err := conn.DeleteEventSourceMapping(input) + + if tfawserr.ErrCodeEquals(err, lambda.ErrCodeResourceInUseException) { + return resource.RetryableError(err) + } - if config, ok := configured[0].(map[string]interface{}); ok { - if endpoints, ok := config["endpoints"].(map[string]interface{}); ok { - for key, value := range endpoints { - values := strings.Split(value.(string), ",") - source.Endpoints[key] = make([]*string, len(values)) - for i, value := range values { - valueCopy := value - source.Endpoints[key][i] = &valueCopy - } - } + if err != nil { + return resource.NonRetryableError(err) } + + return nil + }) + + if tfresource.TimedOut(err) { + _, err = conn.DeleteEventSourceMapping(input) + } + + if tfawserr.ErrCodeEquals(err, lambda.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Lambda Event Source Mapping (%s): %w", d.Id(), err) + } + + if _, err := waiter.EventSourceMappingDelete(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Lambda Event Source Mapping (%s) to delete: %w", d.Id(), err) + } + + return nil +} + +func expandLambdaDestinationConfig(tfMap map[string]interface{}) *lambda.DestinationConfig { + if tfMap == nil { + return nil + } + + apiObject := &lambda.DestinationConfig{} + + if v, ok := tfMap["on_failure"].([]interface{}); ok && len(v) > 0 { + apiObject.OnFailure = expandLambdaOnFailure(v[0].(map[string]interface{})) + } + + return apiObject +} + +func expandLambdaOnFailure(tfMap map[string]interface{}) *lambda.OnFailure { + if tfMap == nil { + return nil + } + + apiObject := &lambda.OnFailure{} + + if v, ok := tfMap["destination_arn"].(string); ok && v != "" { + apiObject.Destination = aws.String(v) + } + + return apiObject +} + +func flattenLambdaDestinationConfig(apiObject *lambda.DestinationConfig) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.OnFailure; v != nil { + tfMap["on_failure"] = []interface{}{flattenLambdaOnFailure(v)} + } + + return tfMap +} + +func flattenLambdaOnFailure(apiObject *lambda.OnFailure) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Destination; v != nil { + tfMap["destination_arn"] = aws.StringValue(v) } - return source + + return tfMap } -func flattenLambdaEventSourceMappingSelfManagedEventSource(source *lambda.SelfManagedEventSource, d *schema.ResourceData) []interface{} { - if source == nil { +func expandLambdaSelfManagedEventSource(tfMap map[string]interface{}) *lambda.SelfManagedEventSource { + if tfMap == nil { return nil } - if source.Endpoints == nil { + apiObject := &lambda.SelfManagedEventSource{} + + if v, ok := tfMap["endpoints"].(map[string]interface{}); ok && len(v) > 0 { + m := map[string][]*string{} + + for k, v := range v { + m[k] = aws.StringSlice(strings.Split(v.(string), ",")) + } + + apiObject.Endpoints = m + } + + return apiObject +} + +func flattenLambdaSelfManagedEventSource(apiObject *lambda.SelfManagedEventSource) map[string]interface{} { + if apiObject == nil { return nil } - endpoints := map[string]string{} - for key, values := range source.Endpoints { - sValues := make([]string, len(values)) - for i, value := range values { - sValues[i] = *value + tfMap := map[string]interface{}{} + + if v := apiObject.Endpoints; v != nil { + m := map[string]string{} + + for k, v := range v { + m[k] = strings.Join(aws.StringValueSlice(v), ",") } - // The AWS API sorts the list of brokers so try to order the string by what - // is in the TF file to prevent spurious diffs. - curValue, ok := d.Get("self_managed_event_source.0.endpoints." + key).(string) + + tfMap["endpoints"] = m + } + + return tfMap +} + +func expandLambdaSourceAccessConfiguration(tfMap map[string]interface{}) *lambda.SourceAccessConfiguration { + if tfMap == nil { + return nil + } + + apiObject := &lambda.SourceAccessConfiguration{} + + if v, ok := tfMap["type"].(string); ok && v != "" { + apiObject.Type = aws.String(v) + } + + if v, ok := tfMap["uri"].(string); ok && v != "" { + apiObject.URI = aws.String(v) + } + + return apiObject +} + +func expandLambdaSourceAccessConfigurations(tfList []interface{}) []*lambda.SourceAccessConfiguration { + if len(tfList) == 0 { + return nil + } + + var apiObjects []*lambda.SourceAccessConfiguration + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + if !ok { - curValue = "" + continue } - curValues := strings.Split(curValue, ",") - if len(sValues) == len(curValues) { - for i := 0; i < len(curValues); i++ { - for j := 0; j < len(sValues); j++ { - if curValues[i] == sValues[j] { - sValues[i], sValues[j] = sValues[j], sValues[i] - break - } - } - } + + apiObject := expandLambdaSourceAccessConfiguration(tfMap) + + if apiObject == nil { + continue } - endpoints[key] = strings.Join(sValues, ",") + + apiObjects = append(apiObjects, apiObject) } - if len(endpoints) == 0 { + return apiObjects +} + +func flattenLambdaSourceAccessConfiguration(apiObject *lambda.SourceAccessConfiguration) map[string]interface{} { + if apiObject == nil { return nil } - config := map[string]interface{}{} - config["endpoints"] = endpoints + tfMap := map[string]interface{}{} - return []interface{}{config} -} + if v := apiObject.Type; v != nil { + tfMap["type"] = aws.StringValue(v) + } -func expandLambdaEventSourceMappingSourceAccessConfigurations(configured []interface{}) []*lambda.SourceAccessConfiguration { - accesses := make([]*lambda.SourceAccessConfiguration, 0, len(configured)) - for _, m := range configured { - config := m.(map[string]interface{}) - accesses = append(accesses, &lambda.SourceAccessConfiguration{ - Type: aws.String(config["type"].(string)), - URI: aws.String(config["uri"].(string)), - }) + if v := apiObject.URI; v != nil { + tfMap["uri"] = aws.StringValue(v) } - return accesses + + return tfMap } -func flattenLambdaEventSourceMappingSourceAccessConfigurations(accesses []*lambda.SourceAccessConfiguration, d *schema.ResourceData) []map[string]interface{} { - if accesses == nil { +func flattenLambdaSourceAccessConfigurations(apiObjects []*lambda.SourceAccessConfiguration) []interface{} { + if len(apiObjects) == 0 { return nil } - settings := make([]map[string]interface{}, len(accesses)) - - for i, access := range accesses { - setting := make(map[string]interface{}) - setting["type"] = access.Type - setting["uri"] = access.URI - settings[i] = setting - } - // The result returned from AWS is sorted so try to order it like the original to prevent spurious diffs - if curCount, ok := d.Get("source_access_configuration.#").(int); ok { - if curCount == len(settings) { - for i := 0; i < curCount; i++ { - if curSetting, ok := d.Get("source_access_configuration." + strconv.Itoa(i)).(map[string]interface{}); ok { - for j := 0; j < len(settings); j++ { - if curSetting["type"] == *settings[j]["type"].(*string) && curSetting["uri"] == *settings[j]["uri"].(*string) { - settings[i], settings[j] = settings[j], settings[i] - } - } - } - } + + var tfList []interface{} + + for _, apiObject := range apiObjects { + if apiObject == nil { + continue } + + tfList = append(tfList, flattenLambdaSourceAccessConfiguration(apiObject)) } - return settings + + return tfList } diff --git a/aws/resource_aws_lambda_event_source_mapping_test.go b/aws/resource_aws_lambda_event_source_mapping_test.go index 94367b53e60b..51854bbef465 100644 --- a/aws/resource_aws_lambda_event_source_mapping_test.go +++ b/aws/resource_aws_lambda_event_source_mapping_test.go @@ -677,16 +677,14 @@ func TestAccAWSLambdaEventSourceMapping_SelfManagedKafka(t *testing.T) { CheckDestroy: testAccCheckLambdaEventSourceMappingDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLambdaEventSourceMappingConfigSelfManagedKafka(rName, "100"), + Config: testAccAWSLambdaEventSourceMappingConfigSelfManagedKafka(rName, "100", "test1:9092,test2:9092"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsLambdaEventSourceMappingExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "batch_size", "100"), + resource.TestCheckResourceAttr(resourceName, "enabled", "false"), resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.#", "1"), - resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.0.endpoints.KAFKA_BOOTSTRAP_SERVERS", "test2:9092,test1:9092"), + resource.TestCheckResourceAttr(resourceName, "self_managed_event_source.0.endpoints.KAFKA_BOOTSTRAP_SERVERS", "test1:9092,test2:9092"), resource.TestCheckResourceAttr(resourceName, "source_access_configuration.#", "3"), - resource.TestCheckResourceAttr(resourceName, "source_access_configuration.0.type", "VPC_SUBNET"), - resource.TestCheckResourceAttr(resourceName, "source_access_configuration.1.type", "VPC_SUBNET"), - resource.TestCheckResourceAttr(resourceName, "source_access_configuration.2.type", "VPC_SECURITY_GROUP"), testAccCheckResourceAttrRfc3339(resourceName, "last_modified"), resource.TestCheckResourceAttr(resourceName, "topics.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName, "topics.*", "test"), @@ -695,9 +693,10 @@ func TestAccAWSLambdaEventSourceMapping_SelfManagedKafka(t *testing.T) { // batch_size became optional. Ensure that if the user supplies the default // value, but then moves to not providing the value, that we don't consider this // a diff. + // Verify also that bootstrap broker order does not matter. { PlanOnly: true, - Config: testAccAWSLambdaEventSourceMappingConfigSelfManagedKafka(rName, "null"), + Config: testAccAWSLambdaEventSourceMappingConfigSelfManagedKafka(rName, "null", "test2:9092,test1:9092"), }, }, }) @@ -865,6 +864,214 @@ resource "aws_lambda_function" "test" { `, rName) } +func testAccAWSLambdaEventSourceMappingConfigSQSBase(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = < 0 { - if config, ok := vDest[0].(map[string]interface{}); ok { - if vOnFailure, ok := config["on_failure"].([]interface{}); ok && len(vOnFailure) > 0 && vOnFailure[0] != nil { - mOnFailure := vOnFailure[0].(map[string]interface{}) - onFailure.SetDestination(mOnFailure["destination_arn"].(string)) - } - } - } - dest.SetOnFailure(onFailure) - return dest -} - -func flattenLambdaEventSourceMappingDestinationConfig(dest *lambda.DestinationConfig) []interface{} { - mDest := map[string]interface{}{} - mOnFailure := map[string]interface{}{} - if dest != nil { - if dest.OnFailure != nil { - if dest.OnFailure.Destination != nil { - mOnFailure["destination_arn"] = *dest.OnFailure.Destination - mDest["on_failure"] = []interface{}{mOnFailure} - } - } - } - - if len(mDest) == 0 { - return nil - } - - return []interface{}{mDest} -} - func flattenLambdaLayers(layers []*lambda.Layer) []interface{} { arns := make([]*string, len(layers)) for i, layer := range layers { From 64c6e05096893259fc29ef48c5ecaf32417d1549 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 May 2021 10:01:54 -0400 Subject: [PATCH 0062/1208] r/aws_lambda_event_source_mapping: Focus Create retry on IAM propagation errors only (#14042). --- aws/resource_aws_lambda_event_source_mapping.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index 5752cad2b956..79aa72f5d694 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -342,7 +342,7 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte err = resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { eventSourceMappingConfiguration, err = conn.CreateEventSourceMapping(input) - if tfawserr.ErrCodeEquals(err, lambda.ErrCodeInvalidParameterValueException) { + if tfawserr.ErrMessageContains(err, lambda.ErrCodeInvalidParameterValueException, "cannot be assumed by Lambda") { return resource.RetryableError(err) } @@ -497,10 +497,6 @@ func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta inte err := resource.Retry(waiter.EventSourceMappingPropagationTimeout, func() *resource.RetryError { _, err := conn.UpdateEventSourceMapping(input) - if tfawserr.ErrCodeEquals(err, lambda.ErrCodeInvalidParameterValueException) { - return resource.RetryableError(err) - } - if tfawserr.ErrCodeEquals(err, lambda.ErrCodeResourceInUseException) { return resource.RetryableError(err) } From e05d007c2c458868c839359eb58669d8b8813fff Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 May 2021 10:23:48 -0400 Subject: [PATCH 0063/1208] r/aws_lambda_event_source_mapping: Add `tumbling_window_in_seconds` argument. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSLambdaEventSourceMapping_Kinesis_TumblingWindowInSeconds' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSLambdaEventSourceMapping_Kinesis_TumblingWindowInSeconds -timeout 180m === RUN TestAccAWSLambdaEventSourceMapping_Kinesis_TumblingWindowInSeconds === PAUSE TestAccAWSLambdaEventSourceMapping_Kinesis_TumblingWindowInSeconds === CONT TestAccAWSLambdaEventSourceMapping_Kinesis_TumblingWindowInSeconds --- PASS: TestAccAWSLambdaEventSourceMapping_Kinesis_TumblingWindowInSeconds (71.47s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 74.769s --- .changelog/19425.txt | 6 ++- ...esource_aws_lambda_event_source_mapping.go | 15 ++++++ ...ce_aws_lambda_event_source_mapping_test.go | 51 +++++++++++++++++++ .../lambda_event_source_mapping.html.markdown | 19 +++---- 4 files changed, 81 insertions(+), 10 deletions(-) diff --git a/.changelog/19425.txt b/.changelog/19425.txt index 8fd11e459b3e..e78934729e4b 100644 --- a/.changelog/19425.txt +++ b/.changelog/19425.txt @@ -1,3 +1,7 @@ ```release-notes:enhancement -resource/aws_lambda_event_source_mapping: Add `self_managed_event_source`, `source_access_configuration` to allow for self managed kafka cluster. +resource/aws_lambda_event_source_mapping: Add `self_managed_event_source` and `source_access_configuration` arguments to support self-managed Apache Kafka event sources ``` + +```release-notes:enhancement +resource/aws_lambda_event_source_mapping: Add `tumbling_window_in_seconds` argument to support AWS Lambda streaming analytics calculations +``` \ No newline at end of file diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index 79aa72f5d694..d8162e2bf23a 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -250,6 +250,12 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, }, + "tumbling_window_in_seconds": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 900), + }, + "uuid": { Type: schema.TypeString, Computed: true, @@ -328,6 +334,10 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte input.Topics = expandStringSet(v.(*schema.Set)) } + if v, ok := d.GetOk("tumbling_window_in_seconds"); ok { + input.TumblingWindowInSeconds = aws.Int64(int64(v.(int))) + } + log.Printf("[DEBUG] Creating Lambda Event Source Mapping: %s", input) // IAM profiles and roles can take some time to propagate in AWS: @@ -426,6 +436,7 @@ func resourceAwsLambdaEventSourceMappingRead(d *schema.ResourceData, meta interf d.Set("state", eventSourceMappingConfiguration.State) d.Set("state_transition_reason", eventSourceMappingConfiguration.StateTransitionReason) d.Set("topics", aws.StringValueSlice(eventSourceMappingConfiguration.Topics)) + d.Set("tumbling_window_in_seconds", eventSourceMappingConfiguration.TumblingWindowInSeconds) d.Set("uuid", eventSourceMappingConfiguration.UUID) switch state := d.Get("state").(string); state { @@ -494,6 +505,10 @@ func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta inte } } + if d.HasChange("tumbling_window_in_seconds") { + input.TumblingWindowInSeconds = aws.Int64(int64(d.Get("tumbling_window_in_seconds").(int))) + } + err := resource.Retry(waiter.EventSourceMappingPropagationTimeout, func() *resource.RetryError { _, err := conn.UpdateEventSourceMapping(input) diff --git a/aws/resource_aws_lambda_event_source_mapping_test.go b/aws/resource_aws_lambda_event_source_mapping_test.go index 51854bbef465..e7a0e1fbe922 100644 --- a/aws/resource_aws_lambda_event_source_mapping_test.go +++ b/aws/resource_aws_lambda_event_source_mapping_test.go @@ -39,6 +39,7 @@ func TestAccAWSLambdaEventSourceMapping_Kinesis_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "function_arn", functionResourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "function_name", functionResourceName, "arn"), testAccCheckResourceAttrRfc3339(resourceName, "last_modified"), + resource.TestCheckResourceAttr(resourceName, "tumbling_window_in_seconds", "0"), ), }, // batch_size became optional. Ensure that if the user supplies the default @@ -145,6 +146,7 @@ func TestAccAWSLambdaEventSourceMapping_DynamoDB_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "function_arn", functionResourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "function_name", functionResourceName, "arn"), testAccCheckResourceAttrRfc3339(resourceName, "last_modified"), + resource.TestCheckResourceAttr(resourceName, "tumbling_window_in_seconds", "0"), ), }, // batch_size became optional. Ensure that if the user supplies the default @@ -346,6 +348,42 @@ func TestAccAWSLambdaEventSourceMapping_Kinesis_ParallelizationFactor(t *testing }) } +func TestAccAWSLambdaEventSourceMapping_Kinesis_TumblingWindowInSeconds(t *testing.T) { + var conf lambda.EventSourceMappingConfiguration + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lambda_event_source_mapping.test" + tumblingWindowInSeconds := int64(30) + tumblingWindowInSecondsUpdate := int64(300) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckLambdaEventSourceMappingDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLambdaEventSourceMappingConfigKinesisTumblingWindowInSeconds(rName, tumblingWindowInSeconds), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaEventSourceMappingExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "tumbling_window_in_seconds", strconv.Itoa(int(tumblingWindowInSeconds))), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSLambdaEventSourceMappingConfigKinesisTumblingWindowInSeconds(rName, tumblingWindowInSecondsUpdate), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaEventSourceMappingExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "tumbling_window_in_seconds", strconv.Itoa(int(tumblingWindowInSecondsUpdate))), + ), + }, + }, + }) +} + func TestAccAWSLambdaEventSourceMapping_Kinesis_MaximumRetryAttempts(t *testing.T) { var conf lambda.EventSourceMappingConfiguration rName := acctest.RandomWithPrefix("tf-acc-test") @@ -1111,6 +1149,19 @@ resource "aws_lambda_event_source_mapping" "test" { `, parallelizationFactor)) } +func testAccAWSLambdaEventSourceMappingConfigKinesisTumblingWindowInSeconds(rName string, tumblingWindowInSeconds int64) string { + return composeConfig(testAccAWSLambdaEventSourceMappingConfigKinesisBase(rName), fmt.Sprintf(` +resource "aws_lambda_event_source_mapping" "test" { + batch_size = 100 + tumbling_window_in_seconds = %[1]d + enabled = true + event_source_arn = aws_kinesis_stream.test.arn + function_name = aws_lambda_function.test.arn + starting_position = "TRIM_HORIZON" +} +`, tumblingWindowInSeconds)) +} + func testAccAWSLambdaEventSourceMappingConfigKinesisMaximumRetryAttempts(rName string, maximumRetryAttempts int64) string { return composeConfig(testAccAWSLambdaEventSourceMappingConfigKinesisBase(rName), fmt.Sprintf(` resource "aws_lambda_event_source_mapping" "test" { diff --git a/website/docs/r/lambda_event_source_mapping.html.markdown b/website/docs/r/lambda_event_source_mapping.html.markdown index 6bb1476364f4..580a6419943e 100644 --- a/website/docs/r/lambda_event_source_mapping.html.markdown +++ b/website/docs/r/lambda_event_source_mapping.html.markdown @@ -89,20 +89,21 @@ resource "aws_lambda_event_source_mapping" "example" { ## Argument Reference * `batch_size` - (Optional) The largest number of records that Lambda will retrieve from your event source at the time of invocation. Defaults to `100` for DynamoDB, Kinesis and MSK, `10` for SQS. -* `maximum_batching_window_in_seconds` - (Optional) The maximum amount of time to gather records before invoking the function, in seconds (between 0 and 300). Records will continue to buffer (or accumulate in the case of an SQS queue event source) until either `maximum_batching_window_in_seconds` expires or `batch_size` has been met. For streaming event sources, defaults to as soon as records are available in the stream. If the batch it reads from the stream/queue only has one record in it, Lambda only sends one record to the function. Only available for stream sources (DynamoDB and Kinesis) and SQS standard queues. -* `event_source_arn` - (Optional) The event source ARN - this is required for Kinesis stream, DynamoDB stream, SQS queue or MSK cluster. It is incompatible with a Self Managed Kafka source. +* `bisect_batch_on_function_error`: - (Optional) If the function returns an error, split the batch in two and retry. Only available for stream sources (DynamoDB and Kinesis). Defaults to `false`. +* `destination_config`: - (Optional) An Amazon SQS queue or Amazon SNS topic destination for failed records. Only available for stream sources (DynamoDB and Kinesis). Detailed below. * `enabled` - (Optional) Determines if the mapping will be enabled on creation. Defaults to `true`. +* `event_source_arn` - (Optional) The event source ARN - this is required for Kinesis stream, DynamoDB stream, SQS queue or MSK cluster. It is incompatible with a Self Managed Kafka source. * `function_name` - (Required) The name or the ARN of the Lambda function that will be subscribing to events. -* `starting_position` - (Optional) The position in the stream where AWS Lambda should start reading. Must be one of `AT_TIMESTAMP` (Kinesis only), `LATEST` or `TRIM_HORIZON` if getting events from Kinesis, DynamoDB or MSK. Must not be provided if getting events from SQS. More information about these positions can be found in the [AWS DynamoDB Streams API Reference](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_GetShardIterator.html) and [AWS Kinesis API Reference](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html#Kinesis-GetShardIterator-request-ShardIteratorType). -* `starting_position_timestamp` - (Optional) A timestamp in [RFC3339 format](https://tools.ietf.org/html/rfc3339#section-5.8) of the data record which to start reading when using `starting_position` set to `AT_TIMESTAMP`. If a record with this exact timestamp does not exist, the next later record is chosen. If the timestamp is older than the current trim horizon, the oldest available record is chosen. -* `parallelization_factor`: - (Optional) The number of batches to process from each shard concurrently. Only available for stream sources (DynamoDB and Kinesis). Minimum and default of 1, maximum of 10. -* `maximum_retry_attempts`: - (Optional) The maximum number of times to retry when the function returns an error. Only available for stream sources (DynamoDB and Kinesis). Minimum and default of -1 (forever), maximum of 10000. +* `maximum_batching_window_in_seconds` - (Optional) The maximum amount of time to gather records before invoking the function, in seconds (between 0 and 300). Records will continue to buffer (or accumulate in the case of an SQS queue event source) until either `maximum_batching_window_in_seconds` expires or `batch_size` has been met. For streaming event sources, defaults to as soon as records are available in the stream. If the batch it reads from the stream/queue only has one record in it, Lambda only sends one record to the function. Only available for stream sources (DynamoDB and Kinesis) and SQS standard queues. * `maximum_record_age_in_seconds`: - (Optional) The maximum age of a record that Lambda sends to a function for processing. Only available for stream sources (DynamoDB and Kinesis). Must be either -1 (forever, and the default value) or between 60 and 604800 (inclusive). -* `bisect_batch_on_function_error`: - (Optional) If the function returns an error, split the batch in two and retry. Only available for stream sources (DynamoDB and Kinesis). Defaults to `false`. -* `topics` - (Optional) The name of the Kafka topics. Only available for MSK sources. A single topic name must be specified. -* `destination_config`: - (Optional) An Amazon SQS queue or Amazon SNS topic destination for failed records. Only available for stream sources (DynamoDB and Kinesis). Detailed below. +* `maximum_retry_attempts`: - (Optional) The maximum number of times to retry when the function returns an error. Only available for stream sources (DynamoDB and Kinesis). Minimum and default of -1 (forever), maximum of 10000. +* `parallelization_factor`: - (Optional) The number of batches to process from each shard concurrently. Only available for stream sources (DynamoDB and Kinesis). Minimum and default of 1, maximum of 10. * `self_managed_event_source`: - (Optional) For Self Managed Kafka sources, the location of the self managed cluster. If set, configuration must also include `source_access_configuration`. Detailed below. * `source_access_configuration`: (Optional) For Self Managed Kafka sources, the access configuration for the source. If set, configuration must also include `self_managed_event_source`. Detailed below. +* `starting_position` - (Optional) The position in the stream where AWS Lambda should start reading. Must be one of `AT_TIMESTAMP` (Kinesis only), `LATEST` or `TRIM_HORIZON` if getting events from Kinesis, DynamoDB or MSK. Must not be provided if getting events from SQS. More information about these positions can be found in the [AWS DynamoDB Streams API Reference](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_GetShardIterator.html) and [AWS Kinesis API Reference](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html#Kinesis-GetShardIterator-request-ShardIteratorType). +* `starting_position_timestamp` - (Optional) A timestamp in [RFC3339 format](https://tools.ietf.org/html/rfc3339#section-5.8) of the data record which to start reading when using `starting_position` set to `AT_TIMESTAMP`. If a record with this exact timestamp does not exist, the next later record is chosen. If the timestamp is older than the current trim horizon, the oldest available record is chosen. +* `topics` - (Optional) The name of the Kafka topics. Only available for MSK sources. A single topic name must be specified. +* `tumbling_window_in_seconds` - (Optional) The duration in seconds of a processing window for [streaming analytics](https://docs.aws.amazon.com/lambda/latest/dg/with-kinesis.html#services-kinesis-windows). The range is between 1 second up to 900 seconds. Only available for stream sources (DynamoDB and Kinesis). ### destination_config Configuration Block From 6c691a1d6a61cd69e50597b0499263e926630e3c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 27 May 2021 10:52:26 -0400 Subject: [PATCH 0064/1208] r/aws_lambda_event_source_mapping: Add `function_response_types` argument. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSLambdaEventSourceMapping_Kinesis_basic\|TestAccAWSLambdaEventSourceMapping_DynamoDB_FunctionResponseTypes\|TestAccAWSLambdaEventSourceMapping_DynamoDB_basic' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSLambdaEventSourceMapping_Kinesis_basic\|TestAccAWSLambdaEventSourceMapping_DynamoDB_FunctionResponseTypes\|TestAccAWSLambdaEventSourceMapping_DynamoDB_basic -timeout 180m === RUN TestAccAWSLambdaEventSourceMapping_Kinesis_basic === PAUSE TestAccAWSLambdaEventSourceMapping_Kinesis_basic === RUN TestAccAWSLambdaEventSourceMapping_DynamoDB_basic === PAUSE TestAccAWSLambdaEventSourceMapping_DynamoDB_basic === RUN TestAccAWSLambdaEventSourceMapping_DynamoDB_FunctionResponseTypes === PAUSE TestAccAWSLambdaEventSourceMapping_DynamoDB_FunctionResponseTypes === CONT TestAccAWSLambdaEventSourceMapping_Kinesis_basic === CONT TestAccAWSLambdaEventSourceMapping_DynamoDB_FunctionResponseTypes === CONT TestAccAWSLambdaEventSourceMapping_DynamoDB_basic --- PASS: TestAccAWSLambdaEventSourceMapping_DynamoDB_FunctionResponseTypes (70.67s) --- PASS: TestAccAWSLambdaEventSourceMapping_DynamoDB_basic (76.45s) --- PASS: TestAccAWSLambdaEventSourceMapping_Kinesis_basic (89.09s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 93.336s --- .changelog/19425.txt | 4 ++ ...esource_aws_lambda_event_source_mapping.go | 18 ++++++ ...ce_aws_lambda_event_source_mapping_test.go | 63 +++++++++++++++++++ .../lambda_event_source_mapping.html.markdown | 3 +- 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/.changelog/19425.txt b/.changelog/19425.txt index e78934729e4b..0a98108c4deb 100644 --- a/.changelog/19425.txt +++ b/.changelog/19425.txt @@ -4,4 +4,8 @@ resource/aws_lambda_event_source_mapping: Add `self_managed_event_source` and `s ```release-notes:enhancement resource/aws_lambda_event_source_mapping: Add `tumbling_window_in_seconds` argument to support AWS Lambda streaming analytics calculations +``` + +```release-notes:enhancement +resource/aws_lambda_event_source_mapping: Add `function_response_types` argument to support AWS Lambda checkpointing ``` \ No newline at end of file diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index d8162e2bf23a..764d5f073428 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -128,6 +128,15 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { }, }, + "function_response_types": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(lambda.FunctionResponseType_Values(), false), + }, + }, + "last_modified": { Type: schema.TypeString, Computed: true, @@ -294,6 +303,10 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte target = v } + if v, ok := d.GetOk("function_response_types"); ok && v.(*schema.Set).Len() > 0 { + input.FunctionResponseTypes = expandStringSet(v.(*schema.Set)) + } + if v, ok := d.GetOk("maximum_batching_window_in_seconds"); ok { input.MaximumBatchingWindowInSeconds = aws.Int64(int64(v.(int))) } @@ -407,6 +420,7 @@ func resourceAwsLambdaEventSourceMappingRead(d *schema.ResourceData, meta interf d.Set("event_source_arn", eventSourceMappingConfiguration.EventSourceArn) d.Set("function_arn", eventSourceMappingConfiguration.FunctionArn) d.Set("function_name", eventSourceMappingConfiguration.FunctionArn) + d.Set("function_response_types", aws.StringValueSlice(eventSourceMappingConfiguration.FunctionResponseTypes)) if eventSourceMappingConfiguration.LastModified != nil { d.Set("last_modified", aws.TimeValue(eventSourceMappingConfiguration.LastModified).Format(time.RFC3339)) } else { @@ -483,6 +497,10 @@ func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta inte input.FunctionName = aws.String(d.Get("function_name").(string)) } + if d.HasChange("function_response_types") { + input.FunctionResponseTypes = expandStringSet(d.Get("function_response_types").(*schema.Set)) + } + if d.HasChange("maximum_batching_window_in_seconds") { input.MaximumBatchingWindowInSeconds = aws.Int64(int64(d.Get("maximum_batching_window_in_seconds").(int))) } diff --git a/aws/resource_aws_lambda_event_source_mapping_test.go b/aws/resource_aws_lambda_event_source_mapping_test.go index e7a0e1fbe922..98815547e04d 100644 --- a/aws/resource_aws_lambda_event_source_mapping_test.go +++ b/aws/resource_aws_lambda_event_source_mapping_test.go @@ -38,6 +38,7 @@ func TestAccAWSLambdaEventSourceMapping_Kinesis_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "event_source_arn", eventSourceResourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "function_arn", functionResourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "function_name", functionResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "function_response_types.#", "0"), testAccCheckResourceAttrRfc3339(resourceName, "last_modified"), resource.TestCheckResourceAttr(resourceName, "tumbling_window_in_seconds", "0"), ), @@ -145,6 +146,7 @@ func TestAccAWSLambdaEventSourceMapping_DynamoDB_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "event_source_arn", eventSourceResourceName, "stream_arn"), resource.TestCheckResourceAttrPair(resourceName, "function_arn", functionResourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "function_name", functionResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "function_response_types.#", "0"), testAccCheckResourceAttrRfc3339(resourceName, "last_modified"), resource.TestCheckResourceAttr(resourceName, "tumbling_window_in_seconds", "0"), ), @@ -165,6 +167,41 @@ func TestAccAWSLambdaEventSourceMapping_DynamoDB_basic(t *testing.T) { }) } +func TestAccAWSLambdaEventSourceMapping_DynamoDB_FunctionResponseTypes(t *testing.T) { + var conf lambda.EventSourceMappingConfiguration + resourceName := "aws_lambda_event_source_mapping.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckLambdaEventSourceMappingDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLambdaEventSourceMappingConfigDynamoDbFunctionResponseTypes(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaEventSourceMappingExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "function_response_types.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "function_response_types.*", "ReportBatchItemFailures"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSLambdaEventSourceMappingConfigDynamoDbNoFunctionResponseTypes(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaEventSourceMappingExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "function_response_types.#", "0"), + ), + }, + }, + }) +} + func TestAccAWSLambdaEventSourceMapping_SQS_BatchWindow(t *testing.T) { var conf lambda.EventSourceMappingConfiguration rName := acctest.RandomWithPrefix("tf-acc-test") @@ -1387,3 +1424,29 @@ resource "aws_lambda_event_source_mapping" "test" { } `, batchSize)) } + +func testAccAWSLambdaEventSourceMappingConfigDynamoDbFunctionResponseTypes(rName string) string { + return composeConfig(testAccAWSLambdaEventSourceMappingConfigDynamoDBBase(rName), ` +resource "aws_lambda_event_source_mapping" "test" { + batch_size = 150 + enabled = true + event_source_arn = aws_dynamodb_table.test.stream_arn + function_name = aws_lambda_function.test.function_name + starting_position = "LATEST" + + function_response_types = ["ReportBatchItemFailures"] +} +`) +} + +func testAccAWSLambdaEventSourceMappingConfigDynamoDbNoFunctionResponseTypes(rName string) string { + return composeConfig(testAccAWSLambdaEventSourceMappingConfigDynamoDBBase(rName), ` +resource "aws_lambda_event_source_mapping" "test" { + batch_size = 150 + enabled = true + event_source_arn = aws_dynamodb_table.test.stream_arn + function_name = aws_lambda_function.test.function_name + starting_position = "LATEST" +} +`) +} diff --git a/website/docs/r/lambda_event_source_mapping.html.markdown b/website/docs/r/lambda_event_source_mapping.html.markdown index 580a6419943e..586ad46fcee5 100644 --- a/website/docs/r/lambda_event_source_mapping.html.markdown +++ b/website/docs/r/lambda_event_source_mapping.html.markdown @@ -94,6 +94,7 @@ resource "aws_lambda_event_source_mapping" "example" { * `enabled` - (Optional) Determines if the mapping will be enabled on creation. Defaults to `true`. * `event_source_arn` - (Optional) The event source ARN - this is required for Kinesis stream, DynamoDB stream, SQS queue or MSK cluster. It is incompatible with a Self Managed Kafka source. * `function_name` - (Required) The name or the ARN of the Lambda function that will be subscribing to events. +* `function_response_types` - (Optional) A list of current response type enums applied to the event source mapping for [AWS Lambda checkpointing](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html#services-ddb-batchfailurereporting). Only available for stream sources (DynamoDB and Kinesis). Valid values: `ReportBatchItemFailures`. * `maximum_batching_window_in_seconds` - (Optional) The maximum amount of time to gather records before invoking the function, in seconds (between 0 and 300). Records will continue to buffer (or accumulate in the case of an SQS queue event source) until either `maximum_batching_window_in_seconds` expires or `batch_size` has been met. For streaming event sources, defaults to as soon as records are available in the stream. If the batch it reads from the stream/queue only has one record in it, Lambda only sends one record to the function. Only available for stream sources (DynamoDB and Kinesis) and SQS standard queues. * `maximum_record_age_in_seconds`: - (Optional) The maximum age of a record that Lambda sends to a function for processing. Only available for stream sources (DynamoDB and Kinesis). Must be either -1 (forever, and the default value) or between 60 and 604800 (inclusive). * `maximum_retry_attempts`: - (Optional) The maximum number of times to retry when the function returns an error. Only available for stream sources (DynamoDB and Kinesis). Minimum and default of -1 (forever), maximum of 10000. @@ -103,7 +104,7 @@ resource "aws_lambda_event_source_mapping" "example" { * `starting_position` - (Optional) The position in the stream where AWS Lambda should start reading. Must be one of `AT_TIMESTAMP` (Kinesis only), `LATEST` or `TRIM_HORIZON` if getting events from Kinesis, DynamoDB or MSK. Must not be provided if getting events from SQS. More information about these positions can be found in the [AWS DynamoDB Streams API Reference](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_GetShardIterator.html) and [AWS Kinesis API Reference](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html#Kinesis-GetShardIterator-request-ShardIteratorType). * `starting_position_timestamp` - (Optional) A timestamp in [RFC3339 format](https://tools.ietf.org/html/rfc3339#section-5.8) of the data record which to start reading when using `starting_position` set to `AT_TIMESTAMP`. If a record with this exact timestamp does not exist, the next later record is chosen. If the timestamp is older than the current trim horizon, the oldest available record is chosen. * `topics` - (Optional) The name of the Kafka topics. Only available for MSK sources. A single topic name must be specified. -* `tumbling_window_in_seconds` - (Optional) The duration in seconds of a processing window for [streaming analytics](https://docs.aws.amazon.com/lambda/latest/dg/with-kinesis.html#services-kinesis-windows). The range is between 1 second up to 900 seconds. Only available for stream sources (DynamoDB and Kinesis). +* `tumbling_window_in_seconds` - (Optional) The duration in seconds of a processing window for [AWS Lambda streaming analytics](https://docs.aws.amazon.com/lambda/latest/dg/with-kinesis.html#services-kinesis-windows). The range is between 1 second up to 900 seconds. Only available for stream sources (DynamoDB and Kinesis). ### destination_config Configuration Block From 7e88347cca58f52cbef2cbd5c6959b49bd48774a Mon Sep 17 00:00:00 2001 From: Ian Neubert Date: Thu, 27 May 2021 12:27:52 -0700 Subject: [PATCH 0065/1208] Allow empty string as valid setting for launch_type. Fixes #16078 --- aws/resource_aws_cloudwatch_event_target.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index d4c60d91cb87..4b26fac283e6 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -146,7 +146,7 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource { Type: schema.TypeString, Optional: true, Default: events.LaunchTypeEc2, - ValidateFunc: validation.StringInSlice(events.LaunchType_Values(), false), + ValidateFunc: validation.StringInSlice(append(events.LaunchType_Values(), []string{""}...), false), }, "network_configuration": { Type: schema.TypeList, From f24b8f1450f9ca3cbe977e2643536b2060e447c8 Mon Sep 17 00:00:00 2001 From: Ian Neubert Date: Thu, 27 May 2021 12:55:19 -0700 Subject: [PATCH 0066/1208] Added changelog entry --- .changelog/19555.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19555.txt diff --git a/.changelog/19555.txt b/.changelog/19555.txt new file mode 100644 index 000000000000..71ed41d7b3b6 --- /dev/null +++ b/.changelog/19555.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_cloudwatch_event_target: Fix ecs_target.launch_type not allowing empty string values. +``` From 3d3cb4e4be0f7ce37eac35c591974a2d5cd0b3e7 Mon Sep 17 00:00:00 2001 From: Stephen Date: Thu, 25 Mar 2021 21:49:32 +0000 Subject: [PATCH 0067/1208] Add DynamoDB support to CloudTrail --- aws/resource_aws_cloudtrail.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudtrail.go b/aws/resource_aws_cloudtrail.go index 8f9a37b3a350..d54fd2043bb1 100644 --- a/aws/resource_aws_cloudtrail.go +++ b/aws/resource_aws_cloudtrail.go @@ -110,7 +110,7 @@ func resourceAwsCloudTrail() *schema.Resource { "type": { Type: schema.TypeString, Required: true, - ValidateFunc: validation.StringInSlice([]string{"AWS::S3::Object", "AWS::Lambda::Function"}, false), + ValidateFunc: validation.StringInSlice([]string{"AWS::S3::Object", "AWS::Lambda::Function", "AWS::DynamoDB::Table"}, false), }, "values": { Type: schema.TypeList, From a5e6c3a3ada7bb557d657d789e2d6e9a12c0f9dd Mon Sep 17 00:00:00 2001 From: Stephen Date: Thu, 25 Mar 2021 21:52:04 +0000 Subject: [PATCH 0068/1208] Update docs --- website/docs/r/cloudtrail.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/cloudtrail.html.markdown b/website/docs/r/cloudtrail.html.markdown index a1509ea44cf3..b4dc5d4c0428 100644 --- a/website/docs/r/cloudtrail.html.markdown +++ b/website/docs/r/cloudtrail.html.markdown @@ -185,8 +185,8 @@ For **event_selector** the following attributes are supported. #### Data Resource Arguments For **data_resource** the following attributes are supported. -* `type` (Required) - The resource type in which you want to log data events. You can specify only the following value: "AWS::S3::Object", "AWS::Lambda::Function" -* `values` (Required) - A list of ARN for the specified S3 buckets and object prefixes.. +* `type` (Required) - The resource type in which you want to log data events. You can specify only the following value: "AWS::S3::Object", "AWS::Lambda::Function" and "AWS::DynamoDB::Table". +* `values` (Required) - A list of ARN for the specified S3 buckets and object prefixes. ### Insight Selector Arguments From 2c75697e9510323c5de200707a58bb20e4030c5e Mon Sep 17 00:00:00 2001 From: Stephen Date: Wed, 21 Apr 2021 17:06:27 +0000 Subject: [PATCH 0069/1208] Update Cloudtrail docs --- website/docs/r/cloudtrail.html.markdown | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/website/docs/r/cloudtrail.html.markdown b/website/docs/r/cloudtrail.html.markdown index b4dc5d4c0428..6bb5ec81b435 100644 --- a/website/docs/r/cloudtrail.html.markdown +++ b/website/docs/r/cloudtrail.html.markdown @@ -186,7 +186,13 @@ For **event_selector** the following attributes are supported. For **data_resource** the following attributes are supported. * `type` (Required) - The resource type in which you want to log data events. You can specify only the following value: "AWS::S3::Object", "AWS::Lambda::Function" and "AWS::DynamoDB::Table". -* `values` (Required) - A list of ARN for the specified S3 buckets and object prefixes. +* `values` (Required) - A list of ARN strings or partial ARN strings to specify selectors for data audit events over data resources. ARN list is specific to single-valued `type`. + * `arn:aws:s3:::/` - all objects in bucket + * `arn:aws:s3:::/key` - specific key(s) + * `arn:aws:lambda` - all lambda events within account + * `arn:aws:lambda:us-west-2:111111111111:function:helloworld` - events for exact arn + * `arn:aws:dynamodb` - all DDB events for all tables within account + ### Insight Selector Arguments From 628fd6a47b7591134e2a11a18806d945c3213e12 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 17:57:43 -0400 Subject: [PATCH 0070/1208] r/cloudtrail: Add changelog --- .changelog/19559.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19559.txt diff --git a/.changelog/19559.txt b/.changelog/19559.txt new file mode 100644 index 000000000000..92c8b1a21383 --- /dev/null +++ b/.changelog/19559.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_cloudtrail: Add `AWS::DynamoDB::Table` as an option for `event_selector`.`data_resource`.`type` +``` \ No newline at end of file From e87c91e26e9f8689b23d979a8c711e6b06545bef Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 27 May 2021 15:17:31 -0700 Subject: [PATCH 0071/1208] resource/aws_ecs_service: Adds support for ECS Anywhere (#19557) * Uses `LaunchType_Values()` to get full list of ECS launch types, including `EXTERNAL` * Updates documentation * Adds CHANGELOG entry * Fixes naming error --- .changelog/19557.txt | 3 +++ aws/resource_aws_ecs_service.go | 13 +++++-------- website/docs/r/ecs_service.html.markdown | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 .changelog/19557.txt diff --git a/.changelog/19557.txt b/.changelog/19557.txt new file mode 100644 index 000000000000..f5d4696408b3 --- /dev/null +++ b/.changelog/19557.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_ecs_service: Add support for ECS Anywhere with the `launch_type` `EXTERNAL` +``` diff --git a/aws/resource_aws_ecs_service.go b/aws/resource_aws_ecs_service.go index 359a5a283d44..c6f3914d0c42 100644 --- a/aws/resource_aws_ecs_service.go +++ b/aws/resource_aws_ecs_service.go @@ -179,14 +179,11 @@ func resourceAwsEcsService() *schema.Resource { Computed: true, }, "launch_type": { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.LaunchTypeEc2, - ecs.LaunchTypeFargate, - }, false), + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(ecs.LaunchType_Values(), false), }, "load_balancer": { Type: schema.TypeSet, diff --git a/website/docs/r/ecs_service.html.markdown b/website/docs/r/ecs_service.html.markdown index e7c2e988a47a..6d2d448391cf 100644 --- a/website/docs/r/ecs_service.html.markdown +++ b/website/docs/r/ecs_service.html.markdown @@ -105,7 +105,7 @@ The following arguments are optional: * `force_new_deployment` - (Optional) Enable to force a new task deployment of the service. This can be used to update tasks to use a newer Docker image with same image/tag combination (e.g. `myimage:latest`), roll Fargate tasks onto a newer platform version, or immediately deploy `ordered_placement_strategy` and `placement_constraints` updates. * `health_check_grace_period_seconds` - (Optional) Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown, up to 2147483647. Only valid for services configured to use load balancers. * `iam_role` - (Optional) ARN of the IAM role that allows Amazon ECS to make calls to your load balancer on your behalf. This parameter is required if you are using a load balancer with your service, but only if your task definition does not use the `awsvpc` network mode. If using `awsvpc` network mode, do not specify this role. If your account has already created the Amazon ECS service-linked role, that role is used by default for your service unless you specify a role here. -* `launch_type` - (Optional) Launch type on which to run your service. The valid values are `EC2` and `FARGATE`. Defaults to `EC2`. +* `launch_type` - (Optional) Launch type on which to run your service. The valid values are `EC2`, `FARGATE`, and `EXTERNAL`. Defaults to `EC2`. * `load_balancer` - (Optional) Configuration block for load balancers. Detailed below. * `network_configuration` - (Optional) Network configuration for the service. This parameter is required for task definitions that use the `awsvpc` network mode to receive their own Elastic Network Interface, and it is not supported for other network modes. Detailed below. * `ordered_placement_strategy` - (Optional) Service level strategy rules that are taken into consideration during task placement. List from top to bottom in order of precedence. Updates to this configuration will take effect next task deployment unless `force_new_deployment` is enabled. The maximum number of `ordered_placement_strategy` blocks is `5`. Detailed below. From ca149f13b90e32b422c044e103ffc3338952d879 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 27 May 2021 22:19:24 +0000 Subject: [PATCH 0072/1208] Update CHANGELOG.md for #19557 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44e01947b2a2..d9149b708cfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ ENHANCEMENTS: * data-source/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` attribute ([#19404](https://github.com/hashicorp/terraform-provider-aws/issues/19404)) * resource/aws_ec2_capacity_reservation: Add `outpost_arn` argument ([#19535](https://github.com/hashicorp/terraform-provider-aws/issues/19535)) +* resource/aws_ecs_service: Add support for ECS Anywhere with the `launch_type` `EXTERNAL` ([#19557](https://github.com/hashicorp/terraform-provider-aws/issues/19557)) * resource/aws_eks_node_group: Add `taint` argument ([#19482](https://github.com/hashicorp/terraform-provider-aws/issues/19482)) * resource/aws_elasticache_parameter_group: Add `tags` argument and `arn` and `tags_all` attributes ([#19551](https://github.com/hashicorp/terraform-provider-aws/issues/19551)) * resource/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` attribute ([#19404](https://github.com/hashicorp/terraform-provider-aws/issues/19404)) @@ -40,6 +41,7 @@ BUG FIXES: * resource/aws_glue_connection: `connection_properties` are optional ([#19375](https://github.com/hashicorp/terraform-provider-aws/issues/19375)) * resource/aws_lb_listener_rule: Allow blank string for `action.redirect.query` nested argument ([#19496](https://github.com/hashicorp/terraform-provider-aws/issues/19496)) * resource/aws_synthetics_canary: Change minimum `timeout_in_seconds` in `run_config` from `60` to `3` ([#19515](https://github.com/hashicorp/terraform-provider-aws/issues/19515)) +* resource/aws_vpn_connection: Allow `local_ipv4_network_cidr`, `remote_ipv4_network_cidr`, `local_ipv6_network_cidr`, and `remote_ipv6_network_cidr` to be CIDRs of any size ([#17573](https://github.com/hashicorp/terraform-provider-aws/issues/17573)) ## 3.42.0 (May 20, 2021) From 5f80cfc3306c7e52d8dea0c42c742900265f1d2c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 18:23:33 -0400 Subject: [PATCH 0073/1208] tests/r/cloudtrail: Add DynamoDB test --- aws/resource_aws_cloudtrail_test.go | 95 +++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/aws/resource_aws_cloudtrail_test.go b/aws/resource_aws_cloudtrail_test.go index 9f3e0fb21eaa..5e7aa85ec22d 100644 --- a/aws/resource_aws_cloudtrail_test.go +++ b/aws/resource_aws_cloudtrail_test.go @@ -103,6 +103,7 @@ func TestAccAWSCloudTrail_serial(t *testing.T) { "kmsKey": testAccAWSCloudTrail_kmsKey, "tags": testAccAWSCloudTrail_tags, "eventSelector": testAccAWSCloudTrail_event_selector, + "eventSelectorDynamoDB": testAccAWSCloudTrail_eventSelectorDynamoDB, "insightSelector": testAccAWSCloudTrail_insight_selector, }, } @@ -555,6 +556,32 @@ func testAccAWSCloudTrail_event_selector(t *testing.T) { }) } +func testAccAWSCloudTrail_eventSelectorDynamoDB(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudtrail.foobar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudtrail.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudTrailDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudTrailConfig_eventSelectorDynamoDB(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "event_selector.#", "1"), + resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.#", "1"), + resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.0.type", "AWS::DynamoDB::Table"), + resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.0.values.#", "1"), + testAccMatchResourceAttrRegionalARN(resourceName, "event_selector.0.data_resource.0.values.0", "dynamodb", regexp.MustCompile(`table/tf-acc-test-.+`)), + resource.TestCheckResourceAttr(resourceName, "event_selector.0.include_management_events", "true"), + resource.TestCheckResourceAttr(resourceName, "event_selector.0.read_write_type", "All"), + ), + }, + }, + }) +} + func testAccAWSCloudTrail_insight_selector(t *testing.T) { resourceName := "aws_cloudtrail.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -1608,6 +1635,74 @@ POLICY `, cloudTrailRandInt) } +func testAccAWSCloudTrailConfig_eventSelectorDynamoDB(rName string) string { + return fmt.Sprintf(` +resource "aws_cloudtrail" "foobar" { + name = %[1]q + s3_bucket_name = aws_s3_bucket.foo.id + + event_selector { + read_write_type = "All" + include_management_events = true + + data_resource { + type = "AWS::DynamoDB::Table" + + values = [ + aws_dynamodb_table.test.arn, + ] + } + } +} + +data "aws_partition" "current" {} + +resource "aws_s3_bucket" "foo" { + bucket = %[1]q + force_destroy = true + + policy = < Date: Thu, 27 May 2021 18:47:07 -0400 Subject: [PATCH 0074/1208] docs/r/cloudtrail: Clean up docs --- website/docs/r/cloudtrail.html.markdown | 104 +++++++++++------------- 1 file changed, 48 insertions(+), 56 deletions(-) diff --git a/website/docs/r/cloudtrail.html.markdown b/website/docs/r/cloudtrail.html.markdown index 6bb5ec81b435..bb54b4e643b2 100644 --- a/website/docs/r/cloudtrail.html.markdown +++ b/website/docs/r/cloudtrail.html.markdown @@ -10,9 +10,9 @@ description: |- Provides a CloudTrail resource. -~> *NOTE:* For a multi-region trail, this resource must be in the home region of the trail. +-> **Tip:** For a multi-region trail, this resource must be in the home region of the trail. -~> *NOTE:* For an organization trail, this resource must be in the master account of the organization. +-> **Tip:** For an organization trail, this resource must be in the master account of the organization. ## Example Usage @@ -149,65 +149,57 @@ resource "aws_cloudtrail" "example" { ## Argument Reference -The following arguments are supported: - -* `name` - (Required) Specifies the name of the trail. -* `s3_bucket_name` - (Required) Specifies the name of the S3 bucket designated for publishing log files. -* `s3_key_prefix` - (Optional) Specifies the S3 key prefix that follows - the name of the bucket you have designated for log file delivery. -* `cloud_watch_logs_role_arn` - (Optional) Specifies the role for the CloudWatch Logs - endpoint to assume to write to a user’s log group. -* `cloud_watch_logs_group_arn` - (Optional) Specifies a log group name using an Amazon Resource Name (ARN), - that represents the log group to which CloudTrail logs will be delivered. Note that CloudTrail requires the Log Stream wildcard. -* `enable_logging` - (Optional) Enables logging for the trail. Defaults to `true`. - Setting this to `false` will pause logging. -* `include_global_service_events` - (Optional) Specifies whether the trail is publishing events - from global services such as IAM to the log files. Defaults to `true`. -* `is_multi_region_trail` - (Optional) Specifies whether the trail is created in the current - region or in all regions. Defaults to `false`. -* `is_organization_trail` - (Optional) Specifies whether the trail is an AWS Organizations trail. Organization trails log events for the master account and all member accounts. Can only be created in the organization master account. Defaults to `false`. -* `sns_topic_name` - (Optional) Specifies the name of the Amazon SNS topic - defined for notification of log file delivery. -* `enable_log_file_validation` - (Optional) Specifies whether log file integrity validation is enabled. - Defaults to `false`. -* `kms_key_id` - (Optional) Specifies the KMS key ARN to use to encrypt the logs delivered by CloudTrail. -* `event_selector` - (Optional) Specifies an event selector for enabling data event logging. Fields documented below. Please note the [CloudTrail limits](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/WhatIsCloudTrail-Limits.html) when configuring these. -* `insight_selector` - (Optional) Specifies an insight selector for identifying unusual operational activity. Fields documented below. -* `tags` - (Optional) A map of tags to assign to the trail. 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. - -### Event Selector Arguments -For **event_selector** the following attributes are supported. - -* `read_write_type` (Optional) - Specify if you want your trail to log read-only events, write-only events, or all. By default, the value is All. You can specify only the following value: "ReadOnly", "WriteOnly", "All". Defaults to `All`. -* `include_management_events` (Optional) - Specify if you want your event selector to include management events for your trail. -* `data_resource` (Optional) - Specifies logging data events. Fields documented below. - -#### Data Resource Arguments -For **data_resource** the following attributes are supported. - -* `type` (Required) - The resource type in which you want to log data events. You can specify only the following value: "AWS::S3::Object", "AWS::Lambda::Function" and "AWS::DynamoDB::Table". -* `values` (Required) - A list of ARN strings or partial ARN strings to specify selectors for data audit events over data resources. ARN list is specific to single-valued `type`. - * `arn:aws:s3:::/` - all objects in bucket - * `arn:aws:s3:::/key` - specific key(s) - * `arn:aws:lambda` - all lambda events within account - * `arn:aws:lambda:us-west-2:111111111111:function:helloworld` - events for exact arn - * `arn:aws:dynamodb` - all DDB events for all tables within account - - -### Insight Selector Arguments - -For **insight_selector** the following attributes are supported. - -* `insight_type` (Optional) - The type of insights to log on a trail. In this release, only `ApiCallRateInsight` is supported as an insight type. +The following arguments are required: + +* `name` - (Required) Name of the trail. +* `s3_bucket_name` - (Required) Name of the S3 bucket designated for publishing log files. + +The following arguments are optional: + +* `cloud_watch_logs_group_arn` - (Optional) Log group name using an ARN that represents the log group to which CloudTrail logs will be delivered. Note that CloudTrail requires the Log Stream wildcard. +* `cloud_watch_logs_role_arn` - (Optional) Role for the CloudWatch Logs endpoint to assume to write to a user’s log group. +* `enable_log_file_validation` - (Optional) Whether log file integrity validation is enabled. Defaults to `false`. +* `enable_logging` - (Optional) Enables logging for the trail. Defaults to `true`. Setting this to `false` will pause logging. +* `event_selector` - (Optional) Configuration block of an event selector for enabling data event logging. See details below. Please note the [CloudTrail limits](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/WhatIsCloudTrail-Limits.html) when configuring these. +* `include_global_service_events` - (Optional) Whether the trail is publishing events from global services such as IAM to the log files. Defaults to `true`. +* `insight_selector` - (Optional) Configuration block for identifying unusual operational activity. See details below. +* `is_multi_region_trail` - (Optional) Whether the trail is created in the current region or in all regions. Defaults to `false`. +* `is_organization_trail` - (Optional) Whether the trail is an AWS Organizations trail. Organization trails log events for the master account and all member accounts. Can only be created in the organization master account. Defaults to `false`. +* `kms_key_id` - (Optional) KMS key ARN to use to encrypt the logs delivered by CloudTrail. +* `s3_key_prefix` - (Optional) S3 key prefix that follows the name of the bucket you have designated for log file delivery. +* `sns_topic_name` - (Optional) Name of the Amazon SNS topic defined for notification of log file delivery. +* `tags` - (Optional) Map of tags to assign to the trail. 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. + +### event_selector + +This configuration block supports the following attributes: + +* `data_resource` - (Optional) Configuration block for data events. See details below. +* `include_management_events` - (Optional) Whether to include management events for your trail. +* `read_write_type` - (Optional) Type of events to log. Valid values are `ReadOnly`, `WriteOnly`, `All`. Default value is `All`. + +#### data_resource + +This configuration block supports the following attributes: + +* `type` - (Required) Resource type in which you want to log data events. You can specify only the following value: "AWS::S3::Object", "AWS::Lambda::Function" and "AWS::DynamoDB::Table". +* `values` - (Required) List of ARN strings or partial ARN strings to specify selectors for data audit events over data resources. ARN list is specific to single-valued `type`. For example, `arn:aws:s3:::/` for all objects in a bucket, `arn:aws:s3:::/key` for specific objects, `arn:aws:lambda` for all lambda events within an account, `arn:aws:lambda:::function:` for a specific Lambda function, `arn:aws:dynamodb` for all DDB events for all tables within an account, or `arn:aws:dynamodb:::table/` for a specific DynamoDB table. + + +### insight_selector + +This configuration block supports the following attributes: + +* `insight_type` - (Optional) Type of insights to log on a trail. The valid value is `ApiCallRateInsight`. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `id` - The name of the trail. -* `home_region` - The region in which the trail was created. -* `arn` - The Amazon Resource Name of the trail. -* `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). +* `arn` - ARN of the trail. +* `home_region` - Region in which the trail was created. +* `id` - Name of the trail. +* `tags_all` - 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 From 3cea22e3d4ce7a9cad0f251d848410fe56ecff2a Mon Sep 17 00:00:00 2001 From: philnichol Date: Thu, 5 Nov 2020 15:05:26 +0000 Subject: [PATCH 0075/1208] added new options to cloudfront distribution resource fixed formatting and broken link Change expected error --- ...nt_distribution_configuration_structure.go | 58 +++++++ ...stribution_configuration_structure_test.go | 29 ++++ aws/resource_aws_cloudfront_distribution.go | 30 ++++ ...source_aws_cloudfront_distribution_test.go | 159 +++++++++++++++++- .../r/cloudfront_distribution.html.markdown | 13 ++ 5 files changed, 288 insertions(+), 1 deletion(-) diff --git a/aws/cloudfront_distribution_configuration_structure.go b/aws/cloudfront_distribution_configuration_structure.go index 6ecfeba9d4ca..bace2eca835c 100644 --- a/aws/cloudfront_distribution_configuration_structure.go +++ b/aws/cloudfront_distribution_configuration_structure.go @@ -699,6 +699,13 @@ func expandOrigin(m map[string]interface{}) *cloudfront.Origin { Id: aws.String(m["origin_id"].(string)), DomainName: aws.String(m["domain_name"].(string)), } + + if v, ok := m["connection_attempts"]; ok { + origin.ConnectionAttempts = aws.Int64(int64(v.(int))) + } + if v, ok := m["connection_timeout"]; ok { + origin.ConnectionTimeout = aws.Int64(int64(v.(int))) + } if v, ok := m["custom_header"]; ok { origin.CustomHeaders = expandCustomHeaders(v.(*schema.Set)) } @@ -710,6 +717,13 @@ func expandOrigin(m map[string]interface{}) *cloudfront.Origin { if v, ok := m["origin_path"]; ok { origin.OriginPath = aws.String(v.(string)) } + + if v, ok := m["origin_shield"]; ok { + if s := v.([]interface{}); len(s) > 0 { + origin.OriginShield = expandOriginShield(s[0].(map[string]interface{})) + } + } + if v, ok := m["s3_origin_config"]; ok { if s := v.([]interface{}); len(s) > 0 { origin.S3OriginConfig = expandS3OriginConfig(s[0].(map[string]interface{})) @@ -731,6 +745,12 @@ func flattenOrigin(or *cloudfront.Origin) map[string]interface{} { m := make(map[string]interface{}) m["origin_id"] = aws.StringValue(or.Id) m["domain_name"] = aws.StringValue(or.DomainName) + if or.ConnectionAttempts != nil { + m["connection_attempts"] = int(aws.Int64Value(or.ConnectionAttempts)) + } + if or.ConnectionTimeout != nil { + m["connection_timeout"] = int(aws.Int64Value(or.ConnectionTimeout)) + } if or.CustomHeaders != nil { m["custom_header"] = flattenCustomHeaders(or.CustomHeaders) } @@ -740,6 +760,9 @@ func flattenOrigin(or *cloudfront.Origin) map[string]interface{} { if or.OriginPath != nil { m["origin_path"] = aws.StringValue(or.OriginPath) } + if or.OriginShield != nil && aws.BoolValue(or.OriginShield.Enabled) { + m["origin_shield"] = []interface{}{flattenOriginShield(or.OriginShield)} + } if or.S3OriginConfig != nil && aws.StringValue(or.S3OriginConfig.OriginAccessIdentity) != "" { m["s3_origin_config"] = []interface{}{flattenS3OriginConfig(or.S3OriginConfig)} } @@ -851,6 +874,12 @@ func originHash(v interface{}) int { m := v.(map[string]interface{}) buf.WriteString(fmt.Sprintf("%s-", m["origin_id"].(string))) buf.WriteString(fmt.Sprintf("%s-", m["domain_name"].(string))) + if v, ok := m["connection_attempts"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + if v, ok := m["connection_timeout"]; ok { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } if v, ok := m["custom_header"]; ok { buf.WriteString(fmt.Sprintf("%d-", customHeadersHash(v.(*schema.Set)))) } @@ -862,6 +891,13 @@ func originHash(v interface{}) int { if v, ok := m["origin_path"]; ok { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } + + if v, ok := m["origin_shield"]; ok { + if s := v.([]interface{}); len(s) > 0 && s[0] != nil { + buf.WriteString(fmt.Sprintf("%d-", originShieldHash((s[0].(map[string]interface{}))))) + } + } + if v, ok := m["s3_origin_config"]; ok { if s := v.([]interface{}); len(s) > 0 && s[0] != nil { buf.WriteString(fmt.Sprintf("%d-", s3OriginConfigHash((s[0].(map[string]interface{}))))) @@ -1026,12 +1062,26 @@ func expandS3OriginConfig(m map[string]interface{}) *cloudfront.S3OriginConfig { } } +func expandOriginShield(m map[string]interface{}) *cloudfront.OriginShield { + return &cloudfront.OriginShield{ + Enabled: aws.Bool(m["enabled"].(bool)), + OriginShieldRegion: aws.String(m["origin_shield_region"].(string)), + } +} + func flattenS3OriginConfig(s3o *cloudfront.S3OriginConfig) map[string]interface{} { return map[string]interface{}{ "origin_access_identity": aws.StringValue(s3o.OriginAccessIdentity), } } +func flattenOriginShield(o *cloudfront.OriginShield) map[string]interface{} { + return map[string]interface{}{ + "origin_shield_region": aws.StringValue(o.OriginShieldRegion), + "enabled": aws.BoolValue(o.Enabled), + } +} + // Assemble the hash for the aws_cloudfront_distribution s3_origin_config // TypeSet attribute. func s3OriginConfigHash(v interface{}) int { @@ -1041,6 +1091,14 @@ func s3OriginConfigHash(v interface{}) int { return hashcode.String(buf.String()) } +func originShieldHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%t-", m["enabled"].(bool))) + buf.WriteString(fmt.Sprintf("%s-", m["origin_shield_region"].(string))) + return hashcode.String(buf.String()) +} + func expandCustomErrorResponses(s *schema.Set) *cloudfront.CustomErrorResponses { qty := 0 items := []*cloudfront.CustomErrorResponse{} diff --git a/aws/cloudfront_distribution_configuration_structure_test.go b/aws/cloudfront_distribution_configuration_structure_test.go index 9ec4495829e4..93c5dc6cae41 100644 --- a/aws/cloudfront_distribution_configuration_structure_test.go +++ b/aws/cloudfront_distribution_configuration_structure_test.go @@ -136,6 +136,13 @@ func customOriginSslProtocolsConf() *schema.Set { return schema.NewSet(schema.HashString, []interface{}{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}) } +func originShield() map[string]interface{} { + return map[string]interface{}{ + "enabled": true, + "origin_shield_region": "us-east-1", + } +} + func s3OriginConf() map[string]interface{} { return map[string]interface{}{ "origin_access_identity": "origin-access-identity/cloudfront/E127EXAMPLE51Z", @@ -151,6 +158,7 @@ func originWithCustomConf() map[string]interface{} { "custom_header": originCustomHeadersConf(), } } + func originWithS3Conf() map[string]interface{} { return map[string]interface{}{ "origin_id": "S3Origin", @@ -816,6 +824,27 @@ func TestCloudFrontStructure_flattenCustomOriginConfigSSL(t *testing.T) { } } +func TestCloudFrontStructure_expandOriginShield(t *testing.T) { + data := originShield() + o := expandOriginShield(data) + if *o.Enabled != true { + t.Fatalf("Expected Enabled to be true, got %v", *o.Enabled) + } + if *o.OriginShieldRegion != "us-east-1" { + t.Fatalf("Expected OriginShieldRegion to be us-east-1, got %v", *o.OriginShieldRegion) + } +} + +func TestCloudFrontStructure_flattenOriginShield(t *testing.T) { + in := originShield() + o := expandOriginShield(in) + out := flattenOriginShield(o) + + if !reflect.DeepEqual(in, out) { + t.Fatalf("Expected out to be %v, got %v", in, out) + } +} + func TestCloudFrontStructure_expandS3OriginConfig(t *testing.T) { data := s3OriginConf() s3o := expandS3OriginConfig(data) diff --git a/aws/resource_aws_cloudfront_distribution.go b/aws/resource_aws_cloudfront_distribution.go index 65a31c232bd9..59f9a9a2af4e 100644 --- a/aws/resource_aws_cloudfront_distribution.go +++ b/aws/resource_aws_cloudfront_distribution.go @@ -495,6 +495,18 @@ func resourceAwsCloudFrontDistribution() *schema.Resource { Set: originHash, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "connection_attempts": { + Type: schema.TypeInt, + Optional: true, + Default: 3, + ValidateFunc: validation.IntBetween(1, 3), + }, + "connection_timeout": { + Type: schema.TypeInt, + Optional: true, + Default: 10, + ValidateFunc: validation.IntBetween(1, 10), + }, "custom_origin_config": { Type: schema.TypeList, Optional: true, @@ -562,6 +574,24 @@ func resourceAwsCloudFrontDistribution() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "origin_shield": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + }, + "origin_shield_region": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringMatch(awsRegionRegexp, "must be a valid AWS Region Code (eg. us-east-1)"), + }, + }, + }, + }, "s3_origin_config": { Type: schema.TypeList, Optional: true, diff --git a/aws/resource_aws_cloudfront_distribution_test.go b/aws/resource_aws_cloudfront_distribution_test.go index cceb23cc9013..09cd1962e20a 100644 --- a/aws/resource_aws_cloudfront_distribution_test.go +++ b/aws/resource_aws_cloudfront_distribution_test.go @@ -435,7 +435,110 @@ func TestAccAWSCloudFrontDistribution_Origin_EmptyOriginID(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSCloudFrontDistributionConfig_Origin_EmptyOriginID(), - ExpectError: regexp.MustCompile(`origin_id must not be empty`), + ExpectError: regexp.MustCompile(`origin.0.origin_id must not be empty`), + }, + }, + }) +} + +func TestAccAWSCloudFrontDistribution_Origin_ConnectionAttempts(t *testing.T) { + var distribution cloudfront.Distribution + resourceName := "aws_cloudfront_distribution.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + rInt := acctest.RandInt() + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck("cloudfront", t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontDistributionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, `connection_attempts = 0`), + ExpectError: regexp.MustCompile(`expected origin.0.connection_attempts to be in the range`), + }, + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, `connection_attempts = 4`), + ExpectError: regexp.MustCompile(`expected origin.0.connection_attempts to be in the range`), + }, + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, `connection_attempts = 2`), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontDistributionExists(resourceName, &distribution), + resource.TestCheckResourceAttr(resourceName, "origin.#", "1"), + resource.TestCheckResourceAttr(resourceName, "origin.0.connection_attempts", `2`), + ), + }, + }, + }) +} + +func TestAccAWSCloudFrontDistribution_Origin_ConnectionTimeout(t *testing.T) { + var distribution cloudfront.Distribution + resourceName := "aws_cloudfront_distribution.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + rInt := acctest.RandInt() + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck("cloudfront", t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontDistributionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, `connection_timeout = 0`), + ExpectError: regexp.MustCompile(`expected origin.0.connection_timeout to be in the range`), + }, + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, `connection_timeout = 11`), + ExpectError: regexp.MustCompile(`expected origin.0.connection_timeout to be in the range`), + }, + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, `connection_timeout = 6`), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontDistributionExists(resourceName, &distribution), + resource.TestCheckResourceAttr(resourceName, "origin.#", "1"), + resource.TestCheckResourceAttr(resourceName, "origin.0.connection_timeout", `6`), + ), + }, + }, + }) +} + +func TestAccAWSCloudFrontDistribution_Origin_OriginShield(t *testing.T) { + var distribution cloudfront.Distribution + resourceName := "aws_cloudfront_distribution.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + rInt := acctest.RandInt() + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck("cloudfront", t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontDistributionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`null`, `"us-east-1"`)), + ExpectError: regexp.MustCompile(`Missing required argument`), + }, + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`false`, `null`)), + ExpectError: regexp.MustCompile(`Missing required argument`), + }, + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`true`, `null`)), + ExpectError: regexp.MustCompile(`Missing required argument`), + }, + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`false`, `""`)), + ExpectError: regexp.MustCompile(`.*must be a valid AWS Region Code \(eg\. us\-east\-1\).*`), + }, + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`true`, `"US East (Ohio)"`)), + ExpectError: regexp.MustCompile(`.*must be a valid AWS Region Code \(eg\. us\-east\-1\).*`), + }, + { + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`true`, `"us-east-1"`)), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontDistributionExists(resourceName, &distribution), + resource.TestCheckResourceAttr(resourceName, "origin.#", "1"), + resource.TestCheckResourceAttr(resourceName, "origin.0.origin_shield.0.enabled", `true`), + resource.TestCheckResourceAttr(resourceName, "origin.0.origin_shield.0.origin_shield_region", "us-east-1"), + ), }, }, }) @@ -3521,3 +3624,57 @@ resource "aws_cloudfront_distribution" "test" { } `, retainOnDelete)) } + +func originShieldItem(enabled, region string) string { + return fmt.Sprintf(` +origin_shield { + enabled = %[1]s + origin_shield_region = %[2]s +} +`, enabled, region) +} + +func testAccAWSCloudFrontDistributionOriginItem(rName string, rInt int, item string) string { + return composeConfig( + originBucket, + testAccAWSCloudFrontDistributionConfigCacheBehaviorRealtimeLogConfigBase(rName), + fmt.Sprintf(` +variable rand_id { + default = %[1]d +} + +resource "aws_cloudfront_distribution" "test" { + origin { + domain_name = "${aws_s3_bucket.s3_bucket_origin.id}.s3.amazonaws.com" + origin_id = "myOrigin" + %[2]s + } + enabled = true + default_cache_behavior { + allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"] + cached_methods = ["GET", "HEAD"] + target_origin_id = "myOrigin" + forwarded_values { + query_string = false + cookies { + forward = "none" + } + } + viewer_protocol_policy = "allow-all" + min_ttl = 0 + default_ttl = 3600 + max_ttl = 86400 + } + price_class = "PriceClass_200" + restrictions { + geo_restriction { + restriction_type = "whitelist" + locations = ["US", "CA", "GB", "DE"] + } + } + viewer_certificate { + cloudfront_default_certificate = true + } +} +`, rInt, item)) +} diff --git a/website/docs/r/cloudfront_distribution.html.markdown b/website/docs/r/cloudfront_distribution.html.markdown index aee9eb131003..a56ebf54041a 100644 --- a/website/docs/r/cloudfront_distribution.html.markdown +++ b/website/docs/r/cloudfront_distribution.html.markdown @@ -452,6 +452,10 @@ argument should not be specified. #### Origin Arguments +* `connection_attempts` (Optional) - The number of times that CloudFront attempts to connect to the origin. Must be between 1-3. Defaults to 3. + +* `connection_timeout` (Optional) - The number of seconds that CloudFront waits when trying to establish a connection to the origin. Must be between 1-10. Defaults to 10. + * `custom_origin_config` - The [CloudFront custom origin](#custom-origin-config-arguments) configuration information. If an S3 origin is required, use `s3_origin_config` instead. @@ -469,6 +473,9 @@ argument should not be specified. request your content from a directory in your Amazon S3 bucket or your custom origin. +* `origin_shield` - The [CloudFront Origin Shield](#origin-shield-arguments) + configuration information. Using Origin Shield can help reduce the load on your origin. For more information, see [Using Origin Shield](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/origin-shield.html) in the Amazon CloudFront Developer Guide. + * `s3_origin_config` - The [CloudFront S3 origin](#s3-origin-config-arguments) configuration information. If a custom origin is required, use `custom_origin_config` instead. @@ -490,6 +497,12 @@ argument should not be specified. * `origin_read_timeout` - (Optional) The Custom Read timeout, in seconds. By default, AWS enforces a limit of `60`. But you can request an [increase](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorCustomOrigin.html#request-custom-request-timeout). +##### Origin Shield Arguments + +* `enabled` (Required) - A flag that specifies whether Origin Shield is enabled. + +* `origin_shield_region` (Required) - The AWS Region for Origin Shield. To specify a region, use the region code, not the region name. For example, specify the US East (Ohio) region as us-east-2. + ##### S3 Origin Config Arguments * `origin_access_identity` (Optional) - The [CloudFront origin access From c780e90cd881f9b145a5fe65761bb155aa442337 Mon Sep 17 00:00:00 2001 From: Joe Atzberger Date: Thu, 27 May 2021 19:43:35 -0400 Subject: [PATCH 0076/1208] Fix invalid example: session_number is required Otherwise the error is: ``` The argument "session_number" is required, but no definition was found. ``` --- website/docs/r/ec2_traffic_mirror_session.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/ec2_traffic_mirror_session.html.markdown b/website/docs/r/ec2_traffic_mirror_session.html.markdown index f0ec22e666d5..0bed8bf54f58 100644 --- a/website/docs/r/ec2_traffic_mirror_session.html.markdown +++ b/website/docs/r/ec2_traffic_mirror_session.html.markdown @@ -28,6 +28,7 @@ resource "aws_ec2_traffic_mirror_target" "target" { resource "aws_ec2_traffic_mirror_session" "session" { description = "traffic mirror session - terraform example" network_interface_id = aws_instance.test.primary_network_interface_id + session_number = 1 traffic_mirror_filter_id = aws_ec2_traffic_mirror_filter.filter.id traffic_mirror_target_id = aws_ec2_traffic_mirror_target.target.id } From ee8accd325193fadd81f5935954d8e8bfc210d3a Mon Sep 17 00:00:00 2001 From: bill-rich Date: Thu, 27 May 2021 16:44:52 -0700 Subject: [PATCH 0077/1208] Fix linting errors --- ...t_distribution_configuration_structure_test.go | 6 +++--- aws/resource_aws_cloudfront_distribution.go | 2 +- aws/resource_aws_cloudfront_distribution_test.go | 15 ++++++++++----- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/aws/cloudfront_distribution_configuration_structure_test.go b/aws/cloudfront_distribution_configuration_structure_test.go index 93c5dc6cae41..b1ffdc2e8593 100644 --- a/aws/cloudfront_distribution_configuration_structure_test.go +++ b/aws/cloudfront_distribution_configuration_structure_test.go @@ -139,7 +139,7 @@ func customOriginSslProtocolsConf() *schema.Set { func originShield() map[string]interface{} { return map[string]interface{}{ "enabled": true, - "origin_shield_region": "us-east-1", + "origin_shield_region": "testRegion", } } @@ -830,8 +830,8 @@ func TestCloudFrontStructure_expandOriginShield(t *testing.T) { if *o.Enabled != true { t.Fatalf("Expected Enabled to be true, got %v", *o.Enabled) } - if *o.OriginShieldRegion != "us-east-1" { - t.Fatalf("Expected OriginShieldRegion to be us-east-1, got %v", *o.OriginShieldRegion) + if *o.OriginShieldRegion != "testRegion" { + t.Fatalf("Expected OriginShieldRegion to be testRegion, got %v", *o.OriginShieldRegion) } } diff --git a/aws/resource_aws_cloudfront_distribution.go b/aws/resource_aws_cloudfront_distribution.go index 59f9a9a2af4e..e69fcfeeeaf6 100644 --- a/aws/resource_aws_cloudfront_distribution.go +++ b/aws/resource_aws_cloudfront_distribution.go @@ -587,7 +587,7 @@ func resourceAwsCloudFrontDistribution() *schema.Resource { "origin_shield_region": { Type: schema.TypeString, Required: true, - ValidateFunc: validation.StringMatch(awsRegionRegexp, "must be a valid AWS Region Code (eg. us-east-1)"), + ValidateFunc: validation.StringMatch(awsRegionRegexp, "must be a valid AWS Region Code"), }, }, }, diff --git a/aws/resource_aws_cloudfront_distribution_test.go b/aws/resource_aws_cloudfront_distribution_test.go index 09cd1962e20a..4b3a0cdf8fee 100644 --- a/aws/resource_aws_cloudfront_distribution_test.go +++ b/aws/resource_aws_cloudfront_distribution_test.go @@ -448,6 +448,7 @@ func TestAccAWSCloudFrontDistribution_Origin_ConnectionAttempts(t *testing.T) { rInt := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck("cloudfront", t) }, + ErrorCheck: testAccErrorCheck(t, cloudfront.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckCloudFrontDistributionDestroy, Steps: []resource.TestStep{ @@ -478,6 +479,7 @@ func TestAccAWSCloudFrontDistribution_Origin_ConnectionTimeout(t *testing.T) { rInt := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck("cloudfront", t) }, + ErrorCheck: testAccErrorCheck(t, cloudfront.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckCloudFrontDistributionDestroy, Steps: []resource.TestStep{ @@ -508,11 +510,12 @@ func TestAccAWSCloudFrontDistribution_Origin_OriginShield(t *testing.T) { rInt := acctest.RandInt() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck("cloudfront", t) }, + ErrorCheck: testAccErrorCheck(t, cloudfront.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckCloudFrontDistributionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`null`, `"us-east-1"`)), + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`null`, `data.aws_region.current.name`)), ExpectError: regexp.MustCompile(`Missing required argument`), }, { @@ -525,19 +528,19 @@ func TestAccAWSCloudFrontDistribution_Origin_OriginShield(t *testing.T) { }, { Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`false`, `""`)), - ExpectError: regexp.MustCompile(`.*must be a valid AWS Region Code \(eg\. us\-east\-1\).*`), + ExpectError: regexp.MustCompile(`.*must be a valid AWS Region Code.*`), }, { Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`true`, `"US East (Ohio)"`)), - ExpectError: regexp.MustCompile(`.*must be a valid AWS Region Code \(eg\. us\-east\-1\).*`), + ExpectError: regexp.MustCompile(`.*must be a valid AWS Region Code.*`), }, { - Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`true`, `"us-east-1"`)), + Config: testAccAWSCloudFrontDistributionOriginItem(rName, rInt, originShieldItem(`true`, `"us-east-1"`)), //lintignore:AWSAT003 Check: resource.ComposeTestCheckFunc( testAccCheckCloudFrontDistributionExists(resourceName, &distribution), resource.TestCheckResourceAttr(resourceName, "origin.#", "1"), resource.TestCheckResourceAttr(resourceName, "origin.0.origin_shield.0.enabled", `true`), - resource.TestCheckResourceAttr(resourceName, "origin.0.origin_shield.0.origin_shield_region", "us-east-1"), + resource.TestCheckResourceAttr(resourceName, "origin.0.origin_shield.0.origin_shield_region", "us-east-1"), //lintignore:AWSAT003 ), }, }, @@ -3643,6 +3646,8 @@ variable rand_id { default = %[1]d } +data "aws_region" "current" {} + resource "aws_cloudfront_distribution" "test" { origin { domain_name = "${aws_s3_bucket.s3_bucket_origin.id}.s3.amazonaws.com" From e00b3e2b8aa106837c5e445a62aec1676ad8f9fa Mon Sep 17 00:00:00 2001 From: bill-rich Date: Thu, 27 May 2021 17:14:33 -0700 Subject: [PATCH 0078/1208] Add changelog entry --- .changelog/16049.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/16049.txt diff --git a/.changelog/16049.txt b/.changelog/16049.txt new file mode 100644 index 000000000000..efd40e9764c2 --- /dev/null +++ b/.changelog/16049.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_cloudfront_distribution: Add `connection_attempts`, `connection_timeout`, and `origin_shield`. +``` From fb9665f772db815cacc3062e679ba2c3129f5c61 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 22:21:33 -0400 Subject: [PATCH 0079/1208] tests/r/cloudtrail: Clean tests --- aws/resource_aws_cloudtrail_test.go | 1185 +++++++-------------------- 1 file changed, 310 insertions(+), 875 deletions(-) diff --git a/aws/resource_aws_cloudtrail_test.go b/aws/resource_aws_cloudtrail_test.go index 5e7aa85ec22d..4b20a125fe1b 100644 --- a/aws/resource_aws_cloudtrail_test.go +++ b/aws/resource_aws_cloudtrail_test.go @@ -93,18 +93,18 @@ func testSweepCloudTrails(region string) error { func TestAccAWSCloudTrail_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "Trail": { - "basic": testAccAWSCloudTrail_basic, - "cloudwatch": testAccAWSCloudTrail_cloudwatch, - "enableLogging": testAccAWSCloudTrail_enable_logging, - "includeGlobalServiceEvents": testAccAWSCloudTrail_include_global_service_events, - "isMultiRegion": testAccAWSCloudTrail_is_multi_region, - "isOrganization": testAccAWSCloudTrail_is_organization, - "logValidation": testAccAWSCloudTrail_logValidation, - "kmsKey": testAccAWSCloudTrail_kmsKey, - "tags": testAccAWSCloudTrail_tags, - "eventSelector": testAccAWSCloudTrail_event_selector, - "eventSelectorDynamoDB": testAccAWSCloudTrail_eventSelectorDynamoDB, - "insightSelector": testAccAWSCloudTrail_insight_selector, + "basic": testAccAWSCloudTrail_basic, + "cloudwatch": testAccAWSCloudTrail_cloudwatch, + "enableLogging": testAccAWSCloudTrail_enableLogging, + "globalServiceEvents": testAccAWSCloudTrail_globalServiceEvents, + "multiRegion": testAccAWSCloudTrail_multiRegion, + "organization": testAccAWSCloudTrail_organization, + "logValidation": testAccAWSCloudTrail_logValidation, + "kmsKey": testAccAWSCloudTrail_kmsKey, + "tags": testAccAWSCloudTrail_tags, + "eventSelector": testAccAWSCloudTrail_eventSelector, + "eventSelectorDynamoDB": testAccAWSCloudTrail_eventSelectorDynamoDB, + "insightSelector": testAccAWSCloudTrail_insightSelector, }, } @@ -123,8 +123,8 @@ func TestAccAWSCloudTrail_serial(t *testing.T) { func testAccAWSCloudTrail_basic(t *testing.T) { var trail cloudtrail.Trail - cloudTrailRandInt := acctest.RandInt() - resourceName := "aws_cloudtrail.foobar" + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudtrail.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -133,7 +133,7 @@ func testAccAWSCloudTrail_basic(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfig(cloudTrailRandInt), + Config: testAccAWSCloudTrailConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "include_global_service_events", "true"), @@ -148,7 +148,7 @@ func testAccAWSCloudTrail_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCloudTrailConfigModified(cloudTrailRandInt), + Config: testAccAWSCloudTrailModifiedConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "s3_key_prefix", "prefix"), @@ -163,7 +163,7 @@ func testAccAWSCloudTrail_basic(t *testing.T) { func testAccAWSCloudTrail_cloudwatch(t *testing.T) { var trail cloudtrail.Trail - randInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudtrail.test" resource.Test(t, resource.TestCase{ @@ -173,7 +173,7 @@ func testAccAWSCloudTrail_cloudwatch(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfigCloudWatch(randInt), + Config: testAccAWSCloudTrailCloudWatchConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttrSet(resourceName, "cloud_watch_logs_group_arn"), @@ -186,7 +186,7 @@ func testAccAWSCloudTrail_cloudwatch(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCloudTrailConfigCloudWatchModified(randInt), + Config: testAccAWSCloudTrailCloudWatchModifiedConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttrSet(resourceName, "cloud_watch_logs_group_arn"), @@ -197,10 +197,10 @@ func testAccAWSCloudTrail_cloudwatch(t *testing.T) { }) } -func testAccAWSCloudTrail_enable_logging(t *testing.T) { +func testAccAWSCloudTrail_enableLogging(t *testing.T) { var trail cloudtrail.Trail - cloudTrailRandInt := acctest.RandInt() - resourceName := "aws_cloudtrail.foobar" + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudtrail.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -209,7 +209,7 @@ func testAccAWSCloudTrail_enable_logging(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfig(cloudTrailRandInt), + Config: testAccAWSCloudTrailConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), // AWS will create the trail with logging turned off. @@ -225,7 +225,7 @@ func testAccAWSCloudTrail_enable_logging(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCloudTrailConfigModified(cloudTrailRandInt), + Config: testAccAWSCloudTrailModifiedConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), testAccCheckCloudTrailLoggingEnabled(resourceName, false), @@ -234,7 +234,7 @@ func testAccAWSCloudTrail_enable_logging(t *testing.T) { ), }, { - Config: testAccAWSCloudTrailConfig(cloudTrailRandInt), + Config: testAccAWSCloudTrailConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), testAccCheckCloudTrailLoggingEnabled(resourceName, true), @@ -246,10 +246,10 @@ func testAccAWSCloudTrail_enable_logging(t *testing.T) { }) } -func testAccAWSCloudTrail_is_multi_region(t *testing.T) { +func testAccAWSCloudTrail_multiRegion(t *testing.T) { var trail cloudtrail.Trail - cloudTrailRandInt := acctest.RandInt() - resourceName := "aws_cloudtrail.foobar" + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudtrail.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -258,7 +258,7 @@ func testAccAWSCloudTrail_is_multi_region(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfig(cloudTrailRandInt), + Config: testAccAWSCloudTrailConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "is_multi_region_trail", "false"), @@ -267,7 +267,7 @@ func testAccAWSCloudTrail_is_multi_region(t *testing.T) { ), }, { - Config: testAccAWSCloudTrailConfigMultiRegion(cloudTrailRandInt), + Config: testAccAWSCloudTrailMultiRegionConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "is_multi_region_trail", "true"), @@ -281,7 +281,7 @@ func testAccAWSCloudTrail_is_multi_region(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCloudTrailConfig(cloudTrailRandInt), + Config: testAccAWSCloudTrailConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "is_multi_region_trail", "false"), @@ -293,10 +293,10 @@ func testAccAWSCloudTrail_is_multi_region(t *testing.T) { }) } -func testAccAWSCloudTrail_is_organization(t *testing.T) { +func testAccAWSCloudTrail_organization(t *testing.T) { var trail cloudtrail.Trail - cloudTrailRandInt := acctest.RandInt() - resourceName := "aws_cloudtrail.foobar" + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudtrail.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, @@ -305,7 +305,7 @@ func testAccAWSCloudTrail_is_organization(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfigOrganization(cloudTrailRandInt), + Config: testAccAWSCloudTrailOrganizationConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "is_organization_trail", "true"), @@ -319,7 +319,7 @@ func testAccAWSCloudTrail_is_organization(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCloudTrailConfig(cloudTrailRandInt), + Config: testAccAWSCloudTrailConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "is_organization_trail", "false"), @@ -333,8 +333,8 @@ func testAccAWSCloudTrail_is_organization(t *testing.T) { func testAccAWSCloudTrail_logValidation(t *testing.T) { var trail cloudtrail.Trail - cloudTrailRandInt := acctest.RandInt() - resourceName := "aws_cloudtrail.foobar" + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudtrail.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -343,7 +343,7 @@ func testAccAWSCloudTrail_logValidation(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfig_logValidation(cloudTrailRandInt), + Config: testAccAWSCloudTrailLogValidationConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "s3_key_prefix", ""), @@ -358,7 +358,7 @@ func testAccAWSCloudTrail_logValidation(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCloudTrailConfig_logValidationModified(cloudTrailRandInt), + Config: testAccAWSCloudTrailLogValidationModifiedConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "s3_key_prefix", ""), @@ -373,10 +373,10 @@ func testAccAWSCloudTrail_logValidation(t *testing.T) { func testAccAWSCloudTrail_kmsKey(t *testing.T) { var trail cloudtrail.Trail - cloudTrailRandInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_cloudtrail.foobar" - kmsResourceName := "aws_kms_key.foo" + resourceName := "aws_cloudtrail.test" + kmsResourceName := "aws_kms_key.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -385,7 +385,7 @@ func testAccAWSCloudTrail_kmsKey(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfig_kmsKey(cloudTrailRandInt), + Config: testAccAWSCloudTrailKMSKeyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "s3_key_prefix", ""), @@ -407,8 +407,8 @@ func testAccAWSCloudTrail_tags(t *testing.T) { var trail cloudtrail.Trail var trailTags []*cloudtrail.Tag var trailTagsModified []*cloudtrail.Tag - cloudTrailRandInt := acctest.RandInt() - resourceName := "aws_cloudtrail.foobar" + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudtrail.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -417,7 +417,7 @@ func testAccAWSCloudTrail_tags(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfig_tags(cloudTrailRandInt), + Config: testAccAWSCloudTrailTagsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), @@ -434,7 +434,7 @@ func testAccAWSCloudTrail_tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCloudTrailConfig_tagsModified(cloudTrailRandInt), + Config: testAccAWSCloudTrailTagsModifiedConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), @@ -447,7 +447,7 @@ func testAccAWSCloudTrail_tags(t *testing.T) { ), }, { - Config: testAccAWSCloudTrailConfig_tagsModifiedAgain(cloudTrailRandInt), + Config: testAccAWSCloudTrailTagsModifiedAgainConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), @@ -460,10 +460,10 @@ func testAccAWSCloudTrail_tags(t *testing.T) { }) } -func testAccAWSCloudTrail_include_global_service_events(t *testing.T) { +func testAccAWSCloudTrail_globalServiceEvents(t *testing.T) { var trail cloudtrail.Trail - cloudTrailRandInt := acctest.RandInt() - resourceName := "aws_cloudtrail.foobar" + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudtrail.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -472,7 +472,7 @@ func testAccAWSCloudTrail_include_global_service_events(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfig_include_global_service_events(cloudTrailRandInt), + Config: testAccAWSCloudTrailGlobalServiceEventsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "include_global_service_events", "false"), @@ -487,9 +487,9 @@ func testAccAWSCloudTrail_include_global_service_events(t *testing.T) { }) } -func testAccAWSCloudTrail_event_selector(t *testing.T) { - cloudTrailRandInt := acctest.RandInt() - resourceName := "aws_cloudtrail.foobar" +func testAccAWSCloudTrail_eventSelector(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudtrail.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -498,14 +498,14 @@ func testAccAWSCloudTrail_event_selector(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfig_eventSelector(cloudTrailRandInt), + Config: testAccAWSCloudTrailEventSelectorConfig(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "event_selector.#", "1"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.#", "1"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.0.type", "AWS::S3::Object"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.0.values.#", "2"), - resource.TestMatchResourceAttr(resourceName, "event_selector.0.data_resource.0.values.0", regexp.MustCompile(`^arn:[^:]+:s3:::.+/foobar$`)), - resource.TestMatchResourceAttr(resourceName, "event_selector.0.data_resource.0.values.1", regexp.MustCompile(`^arn:[^:]+:s3:::.+/baz$`)), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.0", "s3", fmt.Sprintf("%s-2/foobar", rName)), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.1", "s3", fmt.Sprintf("%s-2/baz", rName)), resource.TestCheckResourceAttr(resourceName, "event_selector.0.include_management_events", "false"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.read_write_type", "ReadOnly"), ), @@ -516,7 +516,7 @@ func testAccAWSCloudTrail_event_selector(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCloudTrailConfig_eventSelectorReadWriteType(cloudTrailRandInt), + Config: testAccAWSCloudTrailEventSelectorReadWriteTypeConfig(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "event_selector.#", "1"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.include_management_events", "true"), @@ -524,30 +524,30 @@ func testAccAWSCloudTrail_event_selector(t *testing.T) { ), }, { - Config: testAccAWSCloudTrailConfig_eventSelectorModified(cloudTrailRandInt), + Config: testAccAWSCloudTrailEventSelectorModifiedConfig(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "event_selector.#", "2"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.#", "1"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.0.type", "AWS::S3::Object"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.0.values.#", "2"), - resource.TestMatchResourceAttr(resourceName, "event_selector.0.data_resource.0.values.0", regexp.MustCompile(`^arn:[^:]+:s3:::.+/foobar$`)), - resource.TestMatchResourceAttr(resourceName, "event_selector.0.data_resource.0.values.1", regexp.MustCompile(`^arn:[^:]+:s3:::.+/baz$`)), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.0", "s3", fmt.Sprintf("%s-2/foobar", rName)), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.1", "s3", fmt.Sprintf("%s-2/baz", rName)), resource.TestCheckResourceAttr(resourceName, "event_selector.0.include_management_events", "true"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.read_write_type", "ReadOnly"), resource.TestCheckResourceAttr(resourceName, "event_selector.1.data_resource.#", "2"), resource.TestCheckResourceAttr(resourceName, "event_selector.1.data_resource.0.type", "AWS::S3::Object"), resource.TestCheckResourceAttr(resourceName, "event_selector.1.data_resource.0.values.#", "2"), - resource.TestMatchResourceAttr(resourceName, "event_selector.1.data_resource.0.values.0", regexp.MustCompile(`^arn:[^:]+:s3:::.+/tf1$`)), - resource.TestMatchResourceAttr(resourceName, "event_selector.1.data_resource.0.values.1", regexp.MustCompile(`^arn:[^:]+:s3:::.+/tf2$`)), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.1.data_resource.0.values.0", "s3", fmt.Sprintf("%s-2/tf1", rName)), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.1.data_resource.0.values.1", "s3", fmt.Sprintf("%s-2/tf2", rName)), resource.TestCheckResourceAttr(resourceName, "event_selector.1.data_resource.1.type", "AWS::Lambda::Function"), resource.TestCheckResourceAttr(resourceName, "event_selector.1.data_resource.1.values.#", "1"), - resource.TestMatchResourceAttr(resourceName, "event_selector.1.data_resource.1.values.0", regexp.MustCompile(`^arn:[^:]+:lambda:.+:tf-test-trail-event-select-\d+$`)), + testAccCheckResourceAttrRegionalARN(resourceName, "event_selector.1.data_resource.1.values.0", "lambda", fmt.Sprintf("function:%s", rName)), resource.TestCheckResourceAttr(resourceName, "event_selector.1.include_management_events", "false"), resource.TestCheckResourceAttr(resourceName, "event_selector.1.read_write_type", "All"), ), }, { - Config: testAccAWSCloudTrailConfig_eventSelectorNone(cloudTrailRandInt), + Config: testAccAWSCloudTrailEventSelectorNoneConfig(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "event_selector.#", "0"), ), @@ -558,7 +558,7 @@ func testAccAWSCloudTrail_event_selector(t *testing.T) { func testAccAWSCloudTrail_eventSelectorDynamoDB(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_cloudtrail.foobar" + resourceName := "aws_cloudtrail.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -567,7 +567,7 @@ func testAccAWSCloudTrail_eventSelectorDynamoDB(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfig_eventSelectorDynamoDB(rName), + Config: testAccAWSCloudTrailEventSelectorDynamoDBConfig(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "event_selector.#", "1"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.#", "1"), @@ -582,7 +582,7 @@ func testAccAWSCloudTrail_eventSelectorDynamoDB(t *testing.T) { }) } -func testAccAWSCloudTrail_insight_selector(t *testing.T) { +func testAccAWSCloudTrail_insightSelector(t *testing.T) { resourceName := "aws_cloudtrail.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -593,7 +593,7 @@ func testAccAWSCloudTrail_insight_selector(t *testing.T) { CheckDestroy: testAccCheckAWSCloudTrailDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudTrailConfig_insightSelector(rName), + Config: testAccAWSCloudTrailInsightSelectorConfig(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "insight_selector.#", "1"), resource.TestCheckResourceAttr(resourceName, "insight_selector.0.insight_type", "ApiCallRateInsight"), @@ -731,650 +731,293 @@ func testAccCheckCloudTrailLoadTags(trail *cloudtrail.Trail, tags *[]*cloudtrail } } -func testAccAWSCloudTrailConfig(cloudTrailRandInt int) string { +func testAccAWSCloudTrailBaseConfig(rName string) string { return fmt.Sprintf(` -resource "aws_cloudtrail" "foobar" { - name = "tf-trail-foobar-%[1]d" - s3_bucket_name = aws_s3_bucket.foo.id -} - data "aws_partition" "current" {} -resource "aws_s3_bucket" "foo" { - bucket = "tf-test-trail-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q force_destroy = true - policy = < Date: Thu, 27 May 2021 22:41:48 -0400 Subject: [PATCH 0080/1208] tests/r/cloudtrail: Lint --- aws/resource_aws_cloudtrail_test.go | 108 ++++++++++++++++------------ 1 file changed, 61 insertions(+), 47 deletions(-) diff --git a/aws/resource_aws_cloudtrail_test.go b/aws/resource_aws_cloudtrail_test.go index 4b20a125fe1b..c9b6632361b4 100644 --- a/aws/resource_aws_cloudtrail_test.go +++ b/aws/resource_aws_cloudtrail_test.go @@ -422,8 +422,8 @@ func testAccAWSCloudTrail_tags(t *testing.T) { testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), testAccCheckCloudTrailLoadTags(&trail, &trailTags), - resource.TestCheckResourceAttr(resourceName, "tags.Foo", "moo"), - resource.TestCheckResourceAttr(resourceName, "tags.Pooh", "hi"), + resource.TestCheckResourceAttr(resourceName, "tags.Yak", "milk"), + resource.TestCheckResourceAttr(resourceName, "tags.Fox", "tail"), testAccCheckCloudTrailLogValidationEnabled(resourceName, false, &trail), resource.TestCheckResourceAttr(resourceName, "kms_key_id", ""), ), @@ -439,9 +439,9 @@ func testAccAWSCloudTrail_tags(t *testing.T) { testAccCheckCloudTrailExists(resourceName, &trail), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), testAccCheckCloudTrailLoadTags(&trail, &trailTagsModified), - resource.TestCheckResourceAttr(resourceName, "tags.Foo", "moo"), - resource.TestCheckResourceAttr(resourceName, "tags.Moo", "boom"), - resource.TestCheckResourceAttr(resourceName, "tags.Pooh", "hi"), + resource.TestCheckResourceAttr(resourceName, "tags.Yak", "milk"), + resource.TestCheckResourceAttr(resourceName, "tags.Emu", "toes"), + resource.TestCheckResourceAttr(resourceName, "tags.Fox", "tail"), testAccCheckCloudTrailLogValidationEnabled(resourceName, false, &trail), resource.TestCheckResourceAttr(resourceName, "kms_key_id", ""), ), @@ -504,8 +504,8 @@ func testAccAWSCloudTrail_eventSelector(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.#", "1"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.0.type", "AWS::S3::Object"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.0.values.#", "2"), - testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.0", "s3", fmt.Sprintf("%s-2/foobar", rName)), - testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.1", "s3", fmt.Sprintf("%s-2/baz", rName)), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.0", "s3", fmt.Sprintf("%s-2/isen", rName)), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.1", "s3", fmt.Sprintf("%s-2/ko", rName)), resource.TestCheckResourceAttr(resourceName, "event_selector.0.include_management_events", "false"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.read_write_type", "ReadOnly"), ), @@ -530,8 +530,8 @@ func testAccAWSCloudTrail_eventSelector(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.#", "1"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.0.type", "AWS::S3::Object"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.data_resource.0.values.#", "2"), - testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.0", "s3", fmt.Sprintf("%s-2/foobar", rName)), - testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.1", "s3", fmt.Sprintf("%s-2/baz", rName)), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.0", "s3", fmt.Sprintf("%s-2/isen", rName)), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "event_selector.0.data_resource.0.values.1", "s3", fmt.Sprintf("%s-2/ko", rName)), resource.TestCheckResourceAttr(resourceName, "event_selector.0.include_management_events", "true"), resource.TestCheckResourceAttr(resourceName, "event_selector.0.read_write_type", "ReadOnly"), resource.TestCheckResourceAttr(resourceName, "event_selector.1.data_resource.#", "2"), @@ -741,25 +741,27 @@ resource "aws_s3_bucket" "test" { policy = jsonencode({ Version = "2012-10-17" - Statement = [{ - Sid = "AWSCloudTrailAclCheck" - Effect = "Allow" - Principal = "*" - Action = "s3:GetBucketAcl" - Resource = "arn:${data.aws_partition.current.partition}:s3:::%[1]s" - }, - { - Sid = "AWSCloudTrailWrite" - Effect = "Allow" - Principal = "*" - Action = "s3:PutObject" - Resource = "arn:${data.aws_partition.current.partition}:s3:::%[1]s/*" - Condition = { - StringEquals = { - "s3:x-amz-acl" = "bucket-owner-full-control" + Statement = [ + { + Sid = "AWSCloudTrailAclCheck" + Effect = "Allow" + Principal = "*" + Action = "s3:GetBucketAcl" + Resource = "arn:${data.aws_partition.current.partition}:s3:::%[1]s" + }, + { + Sid = "AWSCloudTrailWrite" + Effect = "Allow" + Principal = "*" + Action = "s3:PutObject" + Resource = "arn:${data.aws_partition.current.partition}:s3:::%[1]s/*" + Condition = { + StringEquals = { + "s3:x-amz-acl" = "bucket-owner-full-control" + } } } - }] + ] }) } `, rName) @@ -804,11 +806,13 @@ resource "aws_iam_role" "test" { name = %[1]q assume_role_policy = jsonencode({ - Version = "2012-10-17" + Version = "2012-10-17" + Statement = [{ Sid = "" Effect = "Allow" Action = "sts:AssumeRole" + Principal = { Service = "cloudtrail.${data.aws_partition.current.dns_suffix}" } @@ -821,11 +825,13 @@ resource "aws_iam_role_policy" "test" { role = aws_iam_role.test.id policy = jsonencode({ - Version = "2012-10-17" + Version = "2012-10-17" + Statement = [{ Sid = "AWSCloudTrailCreateLogStream" Effect = "Allow" Resource = "${aws_cloudwatch_log_group.test.arn}:*" + Action = [ "logs:CreateLogStream", "logs:PutLogEvents", @@ -859,10 +865,12 @@ resource "aws_iam_role" "test" { assume_role_policy = jsonencode({ Version = "2012-10-17" + Statement = [{ Sid = "" Effect = "Allow" Action = "sts:AssumeRole" + Principal = { Service = "cloudtrail.${data.aws_partition.current.dns_suffix}" } @@ -876,10 +884,12 @@ resource "aws_iam_role_policy" "test" { policy = jsonencode({ Version = "2012-10-17" + Statement = [{ Sid = "AWSCloudTrailCreateLogStream" Effect = "Allow" Resource = "${aws_cloudwatch_log_group.test2.arn}:*" + Action = [ "logs:CreateLogStream", "logs:PutLogEvents", @@ -942,13 +952,15 @@ resource "aws_kms_key" "test" { description = %[1]q policy = jsonencode({ - Version = "2012-10-17" - Id = %[1]q + Version = "2012-10-17" + Id = %[1]q + Statement = [{ - Sid = "Enable IAM User Permissions" - Effect = "Allow" - Action = "kms:*" - Resource = "*" + Sid = "Enable IAM User Permissions" + Effect = "Allow" + Action = "kms:*" + Resource = "*" + Principal = { AWS = "*" } @@ -982,8 +994,8 @@ resource "aws_cloudtrail" "test" { s3_bucket_name = aws_s3_bucket.test.id tags = { - Foo = "moo" - Pooh = "hi" + Yak = "milk" + Fox = "tail" } } `, rName)) @@ -996,9 +1008,9 @@ resource "aws_cloudtrail" "test" { s3_bucket_name = aws_s3_bucket.test.id tags = { - Foo = "moo" - Pooh = "hi" - Moo = "boom" + Yak = "milk" + Fox = "tail" + Emu = "toes" } } `, rName)) @@ -1027,8 +1039,8 @@ resource "aws_cloudtrail" "test" { type = "AWS::S3::Object" values = [ - "${aws_s3_bucket.test2.arn}/foobar", - "${aws_s3_bucket.test2.arn}/baz", + "${aws_s3_bucket.test2.arn}/isen", + "${aws_s3_bucket.test2.arn}/ko", ] } } @@ -1069,8 +1081,8 @@ resource "aws_cloudtrail" "test" { type = "AWS::S3::Object" values = [ - "${aws_s3_bucket.test2.arn}/foobar", - "${aws_s3_bucket.test2.arn}/baz", + "${aws_s3_bucket.test2.arn}/isen", + "${aws_s3_bucket.test2.arn}/ko", ] } } @@ -1107,11 +1119,13 @@ resource "aws_iam_role" "test" { name = %[1]q assume_role_policy = jsonencode({ - Version = "2012-10-17" + Version = "2012-10-17" + Statement = [{ - Sid = "" - Effect = "Allow" - Action = "sts:AssumeRole" + Sid = "" + Effect = "Allow" + Action = "sts:AssumeRole" + Principal = { Service = "lambda.${data.aws_partition.current.dns_suffix}" } From b18820902abdcb6c7fd96e9d7fb2dfe46b02734a Mon Sep 17 00:00:00 2001 From: "sathija.x.pavuluri" Date: Thu, 17 Oct 2019 13:22:27 -0400 Subject: [PATCH 0081/1208] Added check for on_failure before updating disable_rollback to prevent it from being reset during refresh. --- aws/resource_aws_cloudformation_stack.go | 6 +++ aws/resource_aws_cloudformation_stack_test.go | 47 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/aws/resource_aws_cloudformation_stack.go b/aws/resource_aws_cloudformation_stack.go index c59fdeac6dd1..044683076d68 100644 --- a/aws/resource_aws_cloudformation_stack.go +++ b/aws/resource_aws_cloudformation_stack.go @@ -261,6 +261,12 @@ func resourceAwsCloudFormationStackRead(d *schema.ResourceData, meta interface{} } if stack.DisableRollback != nil { d.Set("disable_rollback", stack.DisableRollback) + + // takes into account that disable_rollback conflicts with on_failure and + // prevents forced new creation if disable_rollback is reset during refresh + if d.Get("on_failure") != nil { + d.Set("disable_rollback", false) + } } if len(stack.NotificationARNs) > 0 { err = d.Set("notification_arns", flattenStringSet(stack.NotificationARNs)) diff --git a/aws/resource_aws_cloudformation_stack_test.go b/aws/resource_aws_cloudformation_stack_test.go index e967b8ca8d2f..031102b73657 100644 --- a/aws/resource_aws_cloudformation_stack_test.go +++ b/aws/resource_aws_cloudformation_stack_test.go @@ -479,6 +479,28 @@ func TestAccAWSCloudFormationStack_withTransform(t *testing.T) { }) } +// Test for https://github.com/hashicorp/terraform/issues/5204 +func TestAccAWSCloudFormationStack_onFailure(t *testing.T) { + var stack cloudformation.Stack + rName := fmt.Sprintf("tf-acc-test-cloudformation-on-failure-%s", acctest.RandString(10)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudFormationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudFormationStackConfig_onFailure(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFormationStackExists("aws_cloudformation_stack.bucket-onfailure", &stack), + resource.TestCheckResourceAttr("aws_cloudformation_stack.bucket-onfailure", "disable_rollback", "false"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.bucket-onfailure", "on_failure", "DO_NOTHING"), + ), + }, + }, + }) +} + func testAccCheckCloudFormationStackExists(n string, stack *cloudformation.Stack) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -1033,3 +1055,28 @@ STACK } `, rName) } + +func testAccAWSCloudFormationStackConfig_onFailure(stackName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "foo" { + bucket = "%[1]s" + force_destroy = true +} + +resource "aws_cloudformation_stack" "bucket-onfailure" { + name = "%[1]s" + on_failure = "DO_NOTHING" + + template_body = <<-EOF + { + "AWSTemplateFormatVersion": "2010-09-09", + "Resources": { + "S3Bucket": { + "Type" : "AWS::S3::Bucket" + } + } + } + EOF +} +`, stackName) +} From f3acf306c265288d2918d210d3e93cec0825350c Mon Sep 17 00:00:00 2001 From: changelogbot Date: Fri, 28 May 2021 03:11:42 +0000 Subject: [PATCH 0082/1208] Update CHANGELOG.md for #19559 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9149b708cfb..3da42894501f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ FEATURES: ENHANCEMENTS: * data-source/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` attribute ([#19404](https://github.com/hashicorp/terraform-provider-aws/issues/19404)) +* resource/aws_cloudfront_distribution: Add `connection_attempts`, `connection_timeout`, and `origin_shield`. ([#16049](https://github.com/hashicorp/terraform-provider-aws/issues/16049)) +* resource/aws_cloudtrail: Add `AWS::DynamoDB::Table` as an option for `event_selector`.`data_resource`.`type` ([#19559](https://github.com/hashicorp/terraform-provider-aws/issues/19559)) * resource/aws_ec2_capacity_reservation: Add `outpost_arn` argument ([#19535](https://github.com/hashicorp/terraform-provider-aws/issues/19535)) * resource/aws_ecs_service: Add support for ECS Anywhere with the `launch_type` `EXTERNAL` ([#19557](https://github.com/hashicorp/terraform-provider-aws/issues/19557)) * resource/aws_eks_node_group: Add `taint` argument ([#19482](https://github.com/hashicorp/terraform-provider-aws/issues/19482)) From d11c60ec0595cd950c28b1b4a5dbf9c680d51785 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 23:18:35 -0400 Subject: [PATCH 0083/1208] r/cloudformation_stack: Add changelog --- .changelog/10539.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/10539.txt diff --git a/.changelog/10539.txt b/.changelog/10539.txt new file mode 100644 index 000000000000..0b2a3ff42e82 --- /dev/null +++ b/.changelog/10539.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_cloudformation_stack: Avoid conflicts with `on_failure` and `disable_rollback` +``` From 460e01e7d4fe6093f43d12ae4f49183e80982937 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 23:18:58 -0400 Subject: [PATCH 0084/1208] tests/r/cloudformation_stack: Add ErrorCheck --- aws/resource_aws_cloudformation_stack_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudformation_stack_test.go b/aws/resource_aws_cloudformation_stack_test.go index 031102b73657..9da884944ee2 100644 --- a/aws/resource_aws_cloudformation_stack_test.go +++ b/aws/resource_aws_cloudformation_stack_test.go @@ -479,13 +479,14 @@ func TestAccAWSCloudFormationStack_withTransform(t *testing.T) { }) } -// Test for https://github.com/hashicorp/terraform/issues/5204 +// TestAccAWSCloudFormationStack_onFailure verifies https://github.com/hashicorp/terraform-provider-aws/issues/5204 func TestAccAWSCloudFormationStack_onFailure(t *testing.T) { var stack cloudformation.Stack rName := fmt.Sprintf("tf-acc-test-cloudformation-on-failure-%s", acctest.RandString(10)) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudformation.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ From 0dfac0b5ee8de93048a5dc5ea37e575d51c7e057 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 23:32:27 -0400 Subject: [PATCH 0085/1208] tests/r/cloudformation_stack: Clean up test --- aws/resource_aws_cloudformation_stack_test.go | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/aws/resource_aws_cloudformation_stack_test.go b/aws/resource_aws_cloudformation_stack_test.go index 9da884944ee2..f963951487f3 100644 --- a/aws/resource_aws_cloudformation_stack_test.go +++ b/aws/resource_aws_cloudformation_stack_test.go @@ -482,7 +482,8 @@ func TestAccAWSCloudFormationStack_withTransform(t *testing.T) { // TestAccAWSCloudFormationStack_onFailure verifies https://github.com/hashicorp/terraform-provider-aws/issues/5204 func TestAccAWSCloudFormationStack_onFailure(t *testing.T) { var stack cloudformation.Stack - rName := fmt.Sprintf("tf-acc-test-cloudformation-on-failure-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudformation_stack.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -493,9 +494,9 @@ func TestAccAWSCloudFormationStack_onFailure(t *testing.T) { { Config: testAccAWSCloudFormationStackConfig_onFailure(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckCloudFormationStackExists("aws_cloudformation_stack.bucket-onfailure", &stack), - resource.TestCheckResourceAttr("aws_cloudformation_stack.bucket-onfailure", "disable_rollback", "false"), - resource.TestCheckResourceAttr("aws_cloudformation_stack.bucket-onfailure", "on_failure", "DO_NOTHING"), + testAccCheckCloudFormationStackExists(resourceName, &stack), + resource.TestCheckResourceAttr(resourceName, "disable_rollback", "false"), + resource.TestCheckResourceAttr(resourceName, "on_failure", "DO_NOTHING"), ), }, }, @@ -1057,27 +1058,25 @@ STACK `, rName) } -func testAccAWSCloudFormationStackConfig_onFailure(stackName string) string { +func testAccAWSCloudFormationStackConfig_onFailure(rName string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "foo" { - bucket = "%[1]s" +resource "aws_s3_bucket" "test" { + bucket = %[1]q force_destroy = true } -resource "aws_cloudformation_stack" "bucket-onfailure" { - name = "%[1]s" +resource "aws_cloudformation_stack" "test" { + name = %[1]q on_failure = "DO_NOTHING" - template_body = <<-EOF - { - "AWSTemplateFormatVersion": "2010-09-09", - "Resources": { - "S3Bucket": { - "Type" : "AWS::S3::Bucket" - } + template_body = jsonencode({ + AWSTemplateFormatVersion = "2010-09-09" + Resources = { + S3Bucket = { + Type = "AWS::S3::Bucket" } } - EOF + }) } -`, stackName) +`, rName) } From 36ab6aeed062ba004bb2a5837b51303ff1bbb756 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 23:46:40 -0400 Subject: [PATCH 0086/1208] tests/r/cloudformation_stack: Conform tests --- aws/resource_aws_cloudformation_stack_test.go | 135 +++++++++--------- 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/aws/resource_aws_cloudformation_stack_test.go b/aws/resource_aws_cloudformation_stack_test.go index f963951487f3..d6fc1532520d 100644 --- a/aws/resource_aws_cloudformation_stack_test.go +++ b/aws/resource_aws_cloudformation_stack_test.go @@ -77,7 +77,7 @@ func testSweepCloudformationStacks(region string) error { func TestAccAWSCloudFormationStack_basic(t *testing.T) { var stack cloudformation.Stack - stackName := acctest.RandomWithPrefix("tf-acc-test-basic") + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudformation_stack.test" resource.ParallelTest(t, resource.TestCase{ @@ -87,10 +87,10 @@ func TestAccAWSCloudFormationStack_basic(t *testing.T) { CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFormationStackConfig(stackName), + Config: testAccAWSCloudFormationStackConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists(resourceName, &stack), - resource.TestCheckResourceAttr(resourceName, "name", stackName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckNoResourceAttr(resourceName, "on_failure"), ), }, @@ -104,7 +104,7 @@ func TestAccAWSCloudFormationStack_basic(t *testing.T) { } func TestAccAWSCloudFormationStack_CreationFailure_DoNothing(t *testing.T) { - stackName := acctest.RandomWithPrefix("tf-acc-test") + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -113,7 +113,7 @@ func TestAccAWSCloudFormationStack_CreationFailure_DoNothing(t *testing.T) { CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFormationStackConfigCreationFailure(stackName, cloudformation.OnFailureDoNothing), + Config: testAccAWSCloudFormationStackConfigCreationFailure(rName, cloudformation.OnFailureDoNothing), ExpectError: regexp.MustCompile(`failed to create CloudFormation stack \(CREATE_FAILED\).*The following resource\(s\) failed to create.*This is not a valid CIDR block`), }, }, @@ -121,7 +121,7 @@ func TestAccAWSCloudFormationStack_CreationFailure_DoNothing(t *testing.T) { } func TestAccAWSCloudFormationStack_CreationFailure_Delete(t *testing.T) { - stackName := acctest.RandomWithPrefix("tf-acc-test") + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -130,7 +130,7 @@ func TestAccAWSCloudFormationStack_CreationFailure_Delete(t *testing.T) { CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFormationStackConfigCreationFailure(stackName, cloudformation.OnFailureDelete), + Config: testAccAWSCloudFormationStackConfigCreationFailure(rName, cloudformation.OnFailureDelete), ExpectError: regexp.MustCompile(`failed to create CloudFormation stack, delete requested \(DELETE_COMPLETE\).*The following resource\(s\) failed to create.*This is not a valid CIDR block`), }, }, @@ -138,7 +138,7 @@ func TestAccAWSCloudFormationStack_CreationFailure_Delete(t *testing.T) { } func TestAccAWSCloudFormationStack_CreationFailure_Rollback(t *testing.T) { - stackName := acctest.RandomWithPrefix("tf-acc-test") + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -147,7 +147,7 @@ func TestAccAWSCloudFormationStack_CreationFailure_Rollback(t *testing.T) { CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFormationStackConfigCreationFailure(stackName, cloudformation.OnFailureRollback), + Config: testAccAWSCloudFormationStackConfigCreationFailure(rName, cloudformation.OnFailureRollback), ExpectError: regexp.MustCompile(`failed to create CloudFormation stack, rollback requested \(ROLLBACK_COMPLETE\).*The following resource\(s\) failed to create.*This is not a valid CIDR block`), }, }, @@ -156,7 +156,7 @@ func TestAccAWSCloudFormationStack_CreationFailure_Rollback(t *testing.T) { func TestAccAWSCloudFormationStack_UpdateFailure(t *testing.T) { var stack cloudformation.Stack - stackName := acctest.RandomWithPrefix("tf-acc-test") + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudformation_stack.test" vpcCidrInitial := "10.0.0.0/16" @@ -169,13 +169,13 @@ func TestAccAWSCloudFormationStack_UpdateFailure(t *testing.T) { CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFormationStackConfig_withParams(stackName, vpcCidrInitial), + Config: testAccAWSCloudFormationStackConfig_withParams(rName, vpcCidrInitial), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists(resourceName, &stack), ), }, { - Config: testAccAWSCloudFormationStackConfig_withParams(stackName, vpcCidrInvalid), + Config: testAccAWSCloudFormationStackConfig_withParams(rName, vpcCidrInvalid), ExpectError: regexp.MustCompile(`failed to update CloudFormation stack \(UPDATE_ROLLBACK_COMPLETE\).*This is not a valid CIDR block`), }, }, @@ -184,7 +184,7 @@ func TestAccAWSCloudFormationStack_UpdateFailure(t *testing.T) { func TestAccAWSCloudFormationStack_disappears(t *testing.T) { var stack cloudformation.Stack - stackName := fmt.Sprintf("tf-acc-test-basic-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudformation_stack.test" resource.ParallelTest(t, resource.TestCase{ @@ -194,7 +194,7 @@ func TestAccAWSCloudFormationStack_disappears(t *testing.T) { CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFormationStackConfig(stackName), + Config: testAccAWSCloudFormationStackConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists(resourceName, &stack), testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudFormationStack(), resourceName), @@ -207,7 +207,7 @@ func TestAccAWSCloudFormationStack_disappears(t *testing.T) { func TestAccAWSCloudFormationStack_yaml(t *testing.T) { var stack cloudformation.Stack - stackName := fmt.Sprintf("tf-acc-test-yaml-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudformation_stack.test" resource.ParallelTest(t, resource.TestCase{ @@ -217,7 +217,7 @@ func TestAccAWSCloudFormationStack_yaml(t *testing.T) { CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFormationStackConfig_yaml(stackName), + Config: testAccAWSCloudFormationStackConfig_yaml(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists(resourceName, &stack), ), @@ -233,7 +233,7 @@ func TestAccAWSCloudFormationStack_yaml(t *testing.T) { func TestAccAWSCloudFormationStack_defaultParams(t *testing.T) { var stack cloudformation.Stack - stackName := fmt.Sprintf("tf-acc-test-default-params-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudformation_stack.test" resource.ParallelTest(t, resource.TestCase{ @@ -243,7 +243,7 @@ func TestAccAWSCloudFormationStack_defaultParams(t *testing.T) { CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFormationStackConfig_defaultParams(stackName), + Config: testAccAWSCloudFormationStackConfig_defaultParams(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists(resourceName, &stack), ), @@ -260,7 +260,7 @@ func TestAccAWSCloudFormationStack_defaultParams(t *testing.T) { func TestAccAWSCloudFormationStack_allAttributes(t *testing.T) { var stack cloudformation.Stack - stackName := fmt.Sprintf("tf-acc-test-all-attributes-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudformation_stack.test" expectedPolicyBody := "{\"Statement\":[{\"Action\":\"Update:*\",\"Effect\":\"Deny\",\"Principal\":\"*\",\"Resource\":\"LogicalResourceId/StaticVPC\"},{\"Action\":\"Update:*\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"*\"}]}" @@ -271,10 +271,10 @@ func TestAccAWSCloudFormationStack_allAttributes(t *testing.T) { CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFormationStackConfig_allAttributesWithBodies(stackName), + Config: testAccAWSCloudFormationStackConfig_allAttributesWithBodies(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists(resourceName, &stack), - resource.TestCheckResourceAttr(resourceName, "name", stackName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "capabilities.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName, "capabilities.*", "CAPABILITY_IAM"), resource.TestCheckResourceAttr(resourceName, "disable_rollback", "false"), @@ -295,10 +295,10 @@ func TestAccAWSCloudFormationStack_allAttributes(t *testing.T) { ImportStateVerifyIgnore: []string{"on_failure", "parameters", "policy_body"}, }, { - Config: testAccAWSCloudFormationStackConfig_allAttributesWithBodies_modified(stackName), + Config: testAccAWSCloudFormationStackConfig_allAttributesWithBodies_modified(rName), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists(resourceName, &stack), - resource.TestCheckResourceAttr(resourceName, "name", stackName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "capabilities.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName, "capabilities.*", "CAPABILITY_IAM"), resource.TestCheckResourceAttr(resourceName, "disable_rollback", "false"), @@ -319,7 +319,7 @@ func TestAccAWSCloudFormationStack_allAttributes(t *testing.T) { // Regression for https://github.com/hashicorp/terraform/issues/4332 func TestAccAWSCloudFormationStack_withParams(t *testing.T) { var stack cloudformation.Stack - stackName := fmt.Sprintf("tf-acc-test-with-params-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudformation_stack.test" vpcCidrInitial := "10.0.0.0/16" @@ -332,7 +332,7 @@ func TestAccAWSCloudFormationStack_withParams(t *testing.T) { CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFormationStackConfig_withParams(stackName, vpcCidrInitial), + Config: testAccAWSCloudFormationStackConfig_withParams(rName, vpcCidrInitial), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists(resourceName, &stack), resource.TestCheckResourceAttr(resourceName, "parameters.%", "1"), @@ -346,7 +346,7 @@ func TestAccAWSCloudFormationStack_withParams(t *testing.T) { ImportStateVerifyIgnore: []string{"on_failure", "parameters"}, }, { - Config: testAccAWSCloudFormationStackConfig_withParams(stackName, vpcCidrUpdated), + Config: testAccAWSCloudFormationStackConfig_withParams(rName, vpcCidrUpdated), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists(resourceName, &stack), resource.TestCheckResourceAttr(resourceName, "parameters.%", "1"), @@ -360,7 +360,7 @@ func TestAccAWSCloudFormationStack_withParams(t *testing.T) { // Regression for https://github.com/hashicorp/terraform/issues/4534 func TestAccAWSCloudFormationStack_withUrl_withParams(t *testing.T) { var stack cloudformation.Stack - rName := fmt.Sprintf("tf-acc-test-with-url-and-params-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudformation_stack.test" resource.ParallelTest(t, resource.TestCase{ @@ -393,7 +393,7 @@ func TestAccAWSCloudFormationStack_withUrl_withParams(t *testing.T) { func TestAccAWSCloudFormationStack_withUrl_withParams_withYaml(t *testing.T) { var stack cloudformation.Stack - rName := fmt.Sprintf("tf-acc-test-with-params-and-yaml-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudformation_stack.test" resource.ParallelTest(t, resource.TestCase{ @@ -421,7 +421,7 @@ func TestAccAWSCloudFormationStack_withUrl_withParams_withYaml(t *testing.T) { // Test for https://github.com/hashicorp/terraform/issues/5653 func TestAccAWSCloudFormationStack_withUrl_withParams_noUpdate(t *testing.T) { var stack cloudformation.Stack - rName := fmt.Sprintf("tf-acc-test-with-params-no-update-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cloudformation_stack.test" resource.ParallelTest(t, resource.TestCase{ @@ -454,7 +454,8 @@ func TestAccAWSCloudFormationStack_withUrl_withParams_noUpdate(t *testing.T) { func TestAccAWSCloudFormationStack_withTransform(t *testing.T) { var stack cloudformation.Stack - rName := fmt.Sprintf("tf-acc-test-with-transform-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cloudformation_stack.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -465,14 +466,14 @@ func TestAccAWSCloudFormationStack_withTransform(t *testing.T) { { Config: testAccAWSCloudFormationStackConfig_withTransform(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with-transform", &stack), + testAccCheckCloudFormationStackExists(resourceName, &stack), ), }, { PlanOnly: true, Config: testAccAWSCloudFormationStackConfig_withTransform(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with-transform", &stack), + testAccCheckCloudFormationStackExists(resourceName, &stack), ), }, }, @@ -589,10 +590,10 @@ func testAccCheckCloudFormationStackDisappears(stack *cloudformation.Stack) reso } } -func testAccAWSCloudFormationStackConfig(stackName string) string { +func testAccAWSCloudFormationStackConfig(rName string) string { return fmt.Sprintf(` resource "aws_cloudformation_stack" "test" { - name = "%[1]s" + name = %[1]q template_body = < Date: Thu, 27 May 2021 23:49:10 -0400 Subject: [PATCH 0087/1208] tests/r/cloudformation_stack: Use const --- aws/resource_aws_cloudformation_stack_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudformation_stack_test.go b/aws/resource_aws_cloudformation_stack_test.go index d6fc1532520d..ada95be5169b 100644 --- a/aws/resource_aws_cloudformation_stack_test.go +++ b/aws/resource_aws_cloudformation_stack_test.go @@ -497,7 +497,7 @@ func TestAccAWSCloudFormationStack_onFailure(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists(resourceName, &stack), resource.TestCheckResourceAttr(resourceName, "disable_rollback", "false"), - resource.TestCheckResourceAttr(resourceName, "on_failure", "DO_NOTHING"), + resource.TestCheckResourceAttr(resourceName, "on_failure", cloudformation.OnFailureDoNothing), ), }, }, From 3a6313c568007111eea8f0bd257fed026ab54e82 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 27 May 2021 23:52:11 -0400 Subject: [PATCH 0088/1208] tests/cloudformation_stack: Use modern notation --- aws/resource_aws_cloudformation_stack_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudformation_stack_test.go b/aws/resource_aws_cloudformation_stack_test.go index ada95be5169b..fc9ac7156322 100644 --- a/aws/resource_aws_cloudformation_stack_test.go +++ b/aws/resource_aws_cloudformation_stack_test.go @@ -813,7 +813,7 @@ STACK %[2]s POLICY capabilities = ["CAPABILITY_IAM"] - notification_arns = ["${aws_sns_topic.test.arn}"] + notification_arns = [aws_sns_topic.test.arn] on_failure = "DELETE" timeout_in_minutes = 10 tags = { From b8ac5ee921c0c4829684869aec01981bb385acd8 Mon Sep 17 00:00:00 2001 From: Matthew Tse <66440247+mtpdt@users.noreply.github.com> Date: Fri, 8 Jan 2021 14:21:28 -0500 Subject: [PATCH 0089/1208] Allow in-place update of aws_fsx_lustre_file_system's storage_capacity. --- aws/resource_aws_fsx_lustre_file_system.go | 6 +++++- aws/resource_aws_fsx_lustre_file_system_test.go | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_fsx_lustre_file_system.go b/aws/resource_aws_fsx_lustre_file_system.go index 59a2607e1e06..5bfa5a83d4df 100644 --- a/aws/resource_aws_fsx_lustre_file_system.go +++ b/aws/resource_aws_fsx_lustre_file_system.go @@ -89,7 +89,6 @@ func resourceAwsFsxLustreFileSystem() *schema.Resource { "storage_capacity": { Type: schema.TypeInt, Required: true, - ForceNew: true, ValidateFunc: validation.IntAtLeast(1200), }, "subnet_ids": { @@ -310,6 +309,11 @@ func resourceAwsFsxLustreFileSystemUpdate(d *schema.ResourceData, meta interface requestUpdate = true } + if d.HasChange("storage_capacity") { + input.StorageCapacity = aws.Int64(int64(d.Get("storage_capacity").(int))) + requestUpdate = true + } + if requestUpdate { _, err := conn.UpdateFileSystem(input) if err != nil { diff --git a/aws/resource_aws_fsx_lustre_file_system_test.go b/aws/resource_aws_fsx_lustre_file_system_test.go index 7f6c52d88e62..a9957ff79e74 100644 --- a/aws/resource_aws_fsx_lustre_file_system_test.go +++ b/aws/resource_aws_fsx_lustre_file_system_test.go @@ -315,7 +315,7 @@ func TestAccAWSFsxLustreFileSystem_StorageCapacity(t *testing.T) { Config: testAccAwsFsxLustreFileSystemConfigStorageCapacity(1200), Check: resource.ComposeTestCheckFunc( testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem2), - testAccCheckFsxLustreFileSystemRecreated(&filesystem1, &filesystem2), + testAccCheckFsxLustreFileSystemNotRecreated(&filesystem1, &filesystem2), resource.TestCheckResourceAttr(resourceName, "storage_capacity", "1200"), ), }, From 26b86098b103d218f6d1fcecb7b6920bf21f9aca Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 28 May 2021 09:26:50 -0400 Subject: [PATCH 0090/1208] ds/servicecat_constraint: Fix up after review --- aws/data_source_aws_servicecatalog_constraint.go | 10 ++-------- aws/data_source_aws_servicecatalog_constraint_test.go | 1 + 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/aws/data_source_aws_servicecatalog_constraint.go b/aws/data_source_aws_servicecatalog_constraint.go index 771b877ea367..71e2a863782e 100644 --- a/aws/data_source_aws_servicecatalog_constraint.go +++ b/aws/data_source_aws_servicecatalog_constraint.go @@ -67,17 +67,11 @@ func dataSourceAwsServiceCatalogConstraintRead(d *schema.ResourceData, meta inte return fmt.Errorf("error describing Service Catalog Constraint: %w", err) } - if output == nil { + if output == nil || output.ConstraintDetail == nil { return fmt.Errorf("error getting Service Catalog Constraint: empty response") } - acceptLanguage := d.Get("accept_language").(string) - - if acceptLanguage == "" { - acceptLanguage = "en" - } - - d.Set("accept_language", acceptLanguage) + d.Set("accept_language", d.Get("accept_language").(string)) d.Set("parameters", output.ConstraintParameters) d.Set("status", output.Status) diff --git a/aws/data_source_aws_servicecatalog_constraint_test.go b/aws/data_source_aws_servicecatalog_constraint_test.go index 025966ef59aa..d8e8b40e954d 100644 --- a/aws/data_source_aws_servicecatalog_constraint_test.go +++ b/aws/data_source_aws_servicecatalog_constraint_test.go @@ -23,6 +23,7 @@ func TestAccAWSServiceCatalogConstraintDataSource_basic(t *testing.T) { Config: testAccAWSServiceCatalogConstraintDataSourceConfig_basic(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogConstraintExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "acceptLanguage", dataSourceName, "acceptLanguage"), resource.TestCheckResourceAttrPair(resourceName, "description", dataSourceName, "description"), resource.TestCheckResourceAttrPair(resourceName, "owner", dataSourceName, "owner"), resource.TestCheckResourceAttrPair(resourceName, "parameters", dataSourceName, "parameters"), From 8042fd6af9f8fecb64f6208d3c8c13083e771e2e Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 May 2021 17:15:27 +0300 Subject: [PATCH 0091/1208] add tests + custom diff --- aws/resource_aws_fsx_lustre_file_system.go | 21 ++++++- ...esource_aws_fsx_lustre_file_system_test.go | 55 ++++++++++++++++++- .../r/fsx_lustre_file_system.html.markdown | 2 +- 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_fsx_lustre_file_system.go b/aws/resource_aws_fsx_lustre_file_system.go index 5bfa5a83d4df..3704bb313ee5 100644 --- a/aws/resource_aws_fsx_lustre_file_system.go +++ b/aws/resource_aws_fsx_lustre_file_system.go @@ -1,6 +1,7 @@ package aws import ( + "context" "fmt" "log" "regexp" @@ -8,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/fsx" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -182,10 +184,27 @@ func resourceAwsFsxLustreFileSystem() *schema.Resource { }, }, - CustomizeDiff: SetTagsDiff, + CustomizeDiff: customdiff.Sequence( + SetTagsDiff, + resourceFsxLustreFileSystemSchemaCustomizeDiff, + ), } } +func resourceFsxLustreFileSystemSchemaCustomizeDiff(_ context.Context, d *schema.ResourceDiff, meta interface{}) error { + // we want to force a new resource if the new storage capacity is less than the old one + if d.HasChange("storage_capacity") { + o, n := d.GetChange("storage_capacity") + if n.(int) < o.(int) || d.Get("deployment_type").(string) == fsx.LustreDeploymentTypeScratch1 { + if err := d.ForceNew("storage_capacity"); err != nil { + return err + } + } + } + + return nil +} + func resourceAwsFsxLustreFileSystemCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).fsxconn defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig diff --git a/aws/resource_aws_fsx_lustre_file_system_test.go b/aws/resource_aws_fsx_lustre_file_system_test.go index a9957ff79e74..119ff6a9af1d 100644 --- a/aws/resource_aws_fsx_lustre_file_system_test.go +++ b/aws/resource_aws_fsx_lustre_file_system_test.go @@ -315,7 +315,7 @@ func TestAccAWSFsxLustreFileSystem_StorageCapacity(t *testing.T) { Config: testAccAwsFsxLustreFileSystemConfigStorageCapacity(1200), Check: resource.ComposeTestCheckFunc( testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem2), - testAccCheckFsxLustreFileSystemNotRecreated(&filesystem1, &filesystem2), + testAccCheckFsxLustreFileSystemRecreated(&filesystem1, &filesystem2), resource.TestCheckResourceAttr(resourceName, "storage_capacity", "1200"), ), }, @@ -323,6 +323,49 @@ func TestAccAWSFsxLustreFileSystem_StorageCapacity(t *testing.T) { }) } +func TestAccAWSFsxLustreFileSystem_StorageCapacityUpdate(t *testing.T) { + var filesystem1, filesystem2, filesystem3 fsx.FileSystem + resourceName := "aws_fsx_lustre_file_system.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(fsx.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, fsx.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckFsxLustreFileSystemDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsFsxLustreFileSystemConfigStorageCapacityScratch2(7200), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem1), + resource.TestCheckResourceAttr(resourceName, "storage_capacity", "7200"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"security_group_ids"}, + }, + { + Config: testAccAwsFsxLustreFileSystemConfigStorageCapacityScratch2(1200), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem2), + testAccCheckFsxLustreFileSystemRecreated(&filesystem1, &filesystem2), + resource.TestCheckResourceAttr(resourceName, "storage_capacity", "1200"), + ), + }, + { + Config: testAccAwsFsxLustreFileSystemConfigStorageCapacityScratch2(7200), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem3), + testAccCheckFsxLustreFileSystemNotRecreated(&filesystem2, &filesystem3), + resource.TestCheckResourceAttr(resourceName, "storage_capacity", "7200"), + ), + }, + }, + }) +} + func TestAccAWSFsxLustreFileSystem_Tags(t *testing.T) { var filesystem1, filesystem2, filesystem3 fsx.FileSystem resourceName := "aws_fsx_lustre_file_system.test" @@ -926,6 +969,16 @@ resource "aws_fsx_lustre_file_system" "test" { `, storageCapacity)) } +func testAccAwsFsxLustreFileSystemConfigStorageCapacityScratch2(storageCapacity int) string { + return composeConfig(testAccAwsFsxLustreFileSystemConfigBase(), fmt.Sprintf(` +resource "aws_fsx_lustre_file_system" "test" { + storage_capacity = %[1]d + subnet_ids = [aws_subnet.test1.id] + deployment_type = "SCRATCH_2" +} +`, storageCapacity)) +} + func testAccAwsFsxLustreFileSystemConfigSubnetIds1() string { return composeConfig(testAccAwsFsxLustreFileSystemConfigBase(), ` resource "aws_fsx_lustre_file_system" "test" { diff --git a/website/docs/r/fsx_lustre_file_system.html.markdown b/website/docs/r/fsx_lustre_file_system.html.markdown index 179417826f2f..ae3e53478d1b 100644 --- a/website/docs/r/fsx_lustre_file_system.html.markdown +++ b/website/docs/r/fsx_lustre_file_system.html.markdown @@ -24,7 +24,7 @@ resource "aws_fsx_lustre_file_system" "example" { The following arguments are supported: -* `storage_capacity` - (Required) The storage capacity (GiB) of the file system. Minimum of `1200`. Storage capacity is provisioned in increments of 3,600 GiB. +* `storage_capacity` - (Required) The storage capacity (GiB) of the file system. Minimum of `1200`. See more details at [Allowed values for Fsx storage capacity](https://docs.aws.amazon.com/fsx/latest/APIReference/API_CreateFileSystem.html#FSx-CreateFileSystem-request-StorageCapacity). Update is allowed only for `SCRATCH_2` and `PERSISTENT_1` deployment types, See more details at [Fsx Storage Capacity Update](https://docs.aws.amazon.com/fsx/latest/APIReference/API_UpdateFileSystem.html#FSx-UpdateFileSystem-request-StorageCapacity). * `subnet_ids` - (Required) A list of IDs for the subnets that the file system will be accessible from. File systems currently support only one subnet. The file server is also launched in that subnet's Availability Zone. * `export_path` - (Optional) S3 URI (with optional prefix) where the root of your Amazon FSx file system is exported. Can only be specified with `import_path` argument and the path must use the same Amazon S3 bucket as specified in `import_path`. Set equal to `import_path` to overwrite files on export. Defaults to `s3://{IMPORT BUCKET}/FSxLustre{CREATION TIMESTAMP}`. * `import_path` - (Optional) S3 URI (with optional prefix) that you're using as the data repository for your FSx for Lustre file system. For example, `s3://example-bucket/optional-prefix/`. From 77463f6aca03f1e84027017a0e5b8c1911a28208 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Fri, 28 May 2021 14:16:55 +0000 Subject: [PATCH 0092/1208] Update CHANGELOG.md for #19499 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3da42894501f..d2f0ebac30ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ BUG FIXES: * resource/aws_apprunner_service: Handle asynchronous IAM eventual consistency error on creation ([#19483](https://github.com/hashicorp/terraform-provider-aws/issues/19483)) * resource/aws_apprunner_service: Suppress `instance_configuration` `cpu` and `memory` differences ([#19483](https://github.com/hashicorp/terraform-provider-aws/issues/19483)) * resource/aws_batch_job_definition: Don't crash when setting `timeout.attempt_duration_seconds` to `null` ([#19505](https://github.com/hashicorp/terraform-provider-aws/issues/19505)) +* resource/aws_cloudformation_stack: Avoid conflicts with `on_failure` and `disable_rollback` ([#10539](https://github.com/hashicorp/terraform-provider-aws/issues/10539)) * resource/aws_ec2_managed_prefix_list: Fix crash with multiple description-only updates ([#19517](https://github.com/hashicorp/terraform-provider-aws/issues/19517)) * resource/aws_eks_addon: Use `service_account_role_arn`, if set, on updates ([#19454](https://github.com/hashicorp/terraform-provider-aws/issues/19454)) * resource/aws_glue_connection: `connection_properties` are optional ([#19375](https://github.com/hashicorp/terraform-provider-aws/issues/19375)) From 4e9ff0f24ebac099ddfece1c6bef30b0c271496e Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 May 2021 17:19:57 +0300 Subject: [PATCH 0093/1208] changelog --- .changelog/19568.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19568.txt diff --git a/.changelog/19568.txt b/.changelog/19568.txt new file mode 100644 index 000000000000..b369c83530bd --- /dev/null +++ b/.changelog/19568.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_fsx_lustre_filesystem: Allow updating `storage_capacity`. +``` \ No newline at end of file From debe211715c46d01d6cc3d33569f69603cfb7a10 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 May 2021 19:12:30 +0300 Subject: [PATCH 0094/1208] add finder --- .../service/cloudwatch/finder/finder.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/aws/internal/service/cloudwatch/finder/finder.go b/aws/internal/service/cloudwatch/finder/finder.go index 1de5bf2c9d68..e78cf2ca9138 100644 --- a/aws/internal/service/cloudwatch/finder/finder.go +++ b/aws/internal/service/cloudwatch/finder/finder.go @@ -24,3 +24,21 @@ func CompositeAlarmByName(ctx context.Context, conn *cloudwatch.CloudWatch, name return output.CompositeAlarms[0], nil } + +func MetricAlarmByName(conn *cloudwatch.CloudWatch, name string) (*cloudwatch.MetricAlarm, error) { + input := cloudwatch.DescribeAlarmsInput{ + AlarmNames: []*string{aws.String(name)}, + AlarmTypes: aws.StringSlice([]string{cloudwatch.AlarmTypeMetricAlarm}), + } + + output, err := conn.DescribeAlarms(&input) + if err != nil { + return nil, err + } + + if output == nil || len(output.MetricAlarms) != 1 { + return nil, nil + } + + return output.MetricAlarms[0], nil +} From dde377d9f3058b531898f122116d5d6fc85d3ae3 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 May 2021 19:12:45 +0300 Subject: [PATCH 0095/1208] use finder and refactor to expand/flatten --- aws/resource_aws_cloudwatch_metric_alarm.go | 245 +++++++++--------- ...source_aws_cloudwatch_metric_alarm_test.go | 50 ++-- 2 files changed, 139 insertions(+), 156 deletions(-) diff --git a/aws/resource_aws_cloudwatch_metric_alarm.go b/aws/resource_aws_cloudwatch_metric_alarm.go index 43bcea9333bc..f5d32df556df 100644 --- a/aws/resource_aws_cloudwatch_metric_alarm.go +++ b/aws/resource_aws_cloudwatch_metric_alarm.go @@ -10,6 +10,7 @@ import ( "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatch/finder" ) func resourceAwsCloudWatchMetricAlarm() *schema.Resource { @@ -98,8 +99,9 @@ func resourceAwsCloudWatchMetricAlarm() *schema.Resource { Required: true, }, "stat": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cloudwatch.Statistic_Values(), false), }, "unit": { Type: schema.TypeString, @@ -143,6 +145,7 @@ func resourceAwsCloudWatchMetricAlarm() *schema.Resource { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"extended_statistic", "metric_query"}, + ExactlyOneOf: []string{"extended_statistic", "statistic"}, ValidateFunc: validation.StringInSlice(cloudwatch.Statistic_Values(), false), }, "threshold": { @@ -222,6 +225,7 @@ func resourceAwsCloudWatchMetricAlarm() *schema.Resource { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"statistic", "metric_query"}, + ExactlyOneOf: []string{"extended_statistic", "statistic"}, ValidateFunc: validation.StringMatch(regexp.MustCompile(`p(\d{1,2}(\.\d{0,2})?|100)`), "must specify a value between p0.0 and p100"), }, "treat_missing_data": { @@ -246,14 +250,6 @@ func resourceAwsCloudWatchMetricAlarm() *schema.Resource { } func validateResourceAwsCloudWatchMetricAlarm(d *schema.ResourceData) error { - _, metricNameOk := d.GetOk("metric_name") - _, statisticOk := d.GetOk("statistic") - _, extendedStatisticOk := d.GetOk("extended_statistic") - - if metricNameOk && ((!statisticOk && !extendedStatisticOk) || (statisticOk && extendedStatisticOk)) { - return fmt.Errorf("One of `statistic` or `extended_statistic` must be set for a cloudwatch metric alarm") - } - if v := d.Get("metric_query"); v != nil { for _, v := range v.(*schema.Set).List() { metricQueryResource := v.(map[string]interface{}) @@ -282,7 +278,7 @@ func resourceAwsCloudWatchMetricAlarmCreate(d *schema.ResourceData, meta interfa log.Printf("[DEBUG] Creating CloudWatch Metric Alarm: %#v", params) _, err = conn.PutMetricAlarm(¶ms) if err != nil { - return fmt.Errorf("Creating metric alarm failed: %s", err) + return fmt.Errorf("Creating metric alarm failed: %w", err) } d.SetId(d.Get("alarm_name").(string)) log.Println("[INFO] CloudWatch Metric Alarm created") @@ -295,7 +291,7 @@ func resourceAwsCloudWatchMetricAlarmRead(d *schema.ResourceData, meta interface defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - resp, err := getAwsCloudWatchMetricAlarm(d, meta) + resp, err := finder.MetricAlarmByName(conn, d.Id()) if err != nil { return err } @@ -304,12 +300,12 @@ func resourceAwsCloudWatchMetricAlarmRead(d *schema.ResourceData, meta interface return nil } - log.Printf("[DEBUG] Reading CloudWatch Metric Alarm: %s", d.Get("alarm_name")) + log.Printf("[DEBUG] Reading CloudWatch Metric Alarm: %s", d.Id()) d.Set("actions_enabled", resp.ActionsEnabled) if err := d.Set("alarm_actions", flattenStringSet(resp.AlarmActions)); err != nil { - log.Printf("[WARN] Error setting Alarm Actions: %s", err) + return fmt.Errorf("error setting Alarm Actions: %w", err) } arn := aws.StringValue(resp.AlarmArn) d.Set("alarm_description", resp.AlarmDescription) @@ -317,47 +313,27 @@ func resourceAwsCloudWatchMetricAlarmRead(d *schema.ResourceData, meta interface d.Set("arn", arn) d.Set("comparison_operator", resp.ComparisonOperator) d.Set("datapoints_to_alarm", resp.DatapointsToAlarm) - if err := d.Set("dimensions", flattenDimensions(resp.Dimensions)); err != nil { - return err + if err := d.Set("dimensions", flattenAwsCloudWatchMetricAlarmDimensions(resp.Dimensions)); err != nil { + return fmt.Errorf("error setting dimensions: %w", err) } d.Set("evaluation_periods", resp.EvaluationPeriods) if err := d.Set("insufficient_data_actions", flattenStringSet(resp.InsufficientDataActions)); err != nil { - log.Printf("[WARN] Error setting Insufficient Data Actions: %s", err) + return fmt.Errorf("error setting Insufficient Data Actions: %w", err) } d.Set("metric_name", resp.MetricName) d.Set("namespace", resp.Namespace) if resp.Metrics != nil && len(resp.Metrics) > 0 { - metricQueries := make([]interface{}, len(resp.Metrics)) - for i, mq := range resp.Metrics { - metricQuery := map[string]interface{}{ - "expression": aws.StringValue(mq.Expression), - "id": aws.StringValue(mq.Id), - "label": aws.StringValue(mq.Label), - "return_data": aws.BoolValue(mq.ReturnData), - } - if mq.MetricStat != nil { - metric := map[string]interface{}{ - "metric_name": aws.StringValue(mq.MetricStat.Metric.MetricName), - "namespace": aws.StringValue(mq.MetricStat.Metric.Namespace), - "period": int(aws.Int64Value(mq.MetricStat.Period)), - "stat": aws.StringValue(mq.MetricStat.Stat), - "unit": aws.StringValue(mq.MetricStat.Unit), - "dimensions": flattenDimensions(mq.MetricStat.Metric.Dimensions), - } - metricQuery["metric"] = []interface{}{metric} - } - metricQueries[i] = metricQuery - } - if err := d.Set("metric_query", metricQueries); err != nil { - return fmt.Errorf("error setting metric_query: %s", err) + if err := d.Set("metric_query", flattenAwsCloudWatchMetricAlarmMetrics(resp.Metrics)); err != nil { + return fmt.Errorf("error setting metric_query: %w", err) } } if err := d.Set("ok_actions", flattenStringSet(resp.OKActions)); err != nil { - log.Printf("[WARN] Error setting OK Actions: %s", err) + return fmt.Errorf("error setting OK Actions: %w", err) } + d.Set("period", resp.Period) d.Set("statistic", resp.Statistic) d.Set("threshold", resp.Threshold) @@ -370,7 +346,7 @@ func resourceAwsCloudWatchMetricAlarmRead(d *schema.ResourceData, meta interface tags, err := keyvaluetags.CloudwatchListTags(conn, arn) if err != nil { - return fmt.Errorf("error listing tags for CloudWatch Metric Alarm (%s): %s", arn, err) + return fmt.Errorf("error listing tags for CloudWatch Metric Alarm (%s): %w", arn, err) } tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -394,7 +370,7 @@ func resourceAwsCloudWatchMetricAlarmUpdate(d *schema.ResourceData, meta interfa log.Printf("[DEBUG] Updating CloudWatch Metric Alarm: %#v", params) _, err := conn.PutMetricAlarm(¶ms) if err != nil { - return fmt.Errorf("Updating metric alarm failed: %s", err) + return fmt.Errorf("Updating metric alarm failed: %w", err) } log.Println("[INFO] CloudWatch Metric Alarm updated") @@ -403,7 +379,7 @@ func resourceAwsCloudWatchMetricAlarmUpdate(d *schema.ResourceData, meta interfa o, n := d.GetChange("tags_all") if err := keyvaluetags.CloudwatchUpdateTags(conn, arn, o, n); err != nil { - return fmt.Errorf("error updating CloudWatch Metric Alarm (%s) tags: %s", arn, err) + return fmt.Errorf("error updating CloudWatch Metric Alarm (%s) tags: %w", arn, err) } } @@ -422,7 +398,7 @@ func resourceAwsCloudWatchMetricAlarmDelete(d *schema.ResourceData, meta interfa if isAWSErr(err, cloudwatch.ErrCodeResourceNotFoundException, "") { return nil } - return fmt.Errorf("Error deleting CloudWatch Metric Alarm: %s", err) + return fmt.Errorf("Error deleting CloudWatch Metric Alarm: %w", err) } log.Println("[INFO] CloudWatch Metric Alarm deleted") @@ -494,105 +470,128 @@ func getAwsCloudWatchPutMetricAlarmInput(d *schema.ResourceData, meta interface{ params.InsufficientDataActions = expandStringSet(v.(*schema.Set)) } - var metrics []*cloudwatch.MetricDataQuery if v := d.Get("metric_query"); v != nil { - for _, v := range v.(*schema.Set).List() { - metricQueryResource := v.(map[string]interface{}) - id := metricQueryResource["id"].(string) - if id == "" { - continue - } - metricQuery := cloudwatch.MetricDataQuery{ - Id: aws.String(id), - } - if v, ok := metricQueryResource["expression"]; ok && v.(string) != "" { - metricQuery.Expression = aws.String(v.(string)) - } - if v, ok := metricQueryResource["label"]; ok && v.(string) != "" { - metricQuery.Label = aws.String(v.(string)) - } - if v, ok := metricQueryResource["return_data"]; ok { - metricQuery.ReturnData = aws.Bool(v.(bool)) - } - if v := metricQueryResource["metric"]; v != nil { - for _, v := range v.([]interface{}) { - metricResource := v.(map[string]interface{}) - metric := cloudwatch.Metric{ - MetricName: aws.String(metricResource["metric_name"].(string)), - } - metricStat := cloudwatch.MetricStat{ - Metric: &metric, - Stat: aws.String(metricResource["stat"].(string)), - } - if v, ok := metricResource["namespace"]; ok && v.(string) != "" { - metric.Namespace = aws.String(v.(string)) - } - if v, ok := metricResource["period"]; ok { - metricStat.Period = aws.Int64(int64(v.(int))) - } - if v, ok := metricResource["unit"]; ok && v.(string) != "" { - metricStat.Unit = aws.String(v.(string)) - } - a := metricResource["dimensions"].(map[string]interface{}) - dimensions := make([]*cloudwatch.Dimension, 0, len(a)) - for k, v := range a { - dimensions = append(dimensions, &cloudwatch.Dimension{ - Name: aws.String(k), - Value: aws.String(v.(string)), - }) - } - metric.Dimensions = dimensions - metricQuery.MetricStat = &metricStat - } - } - metrics = append(metrics, &metricQuery) - } - params.Metrics = metrics + params.Metrics = expandCloudWatchMetricAlarmMetrics(v.(*schema.Set)) } if v, ok := d.GetOk("ok_actions"); ok { params.OKActions = expandStringSet(v.(*schema.Set)) } - a := d.Get("dimensions").(map[string]interface{}) - var dimensions []*cloudwatch.Dimension - for k, v := range a { - dimensions = append(dimensions, &cloudwatch.Dimension{ - Name: aws.String(k), - Value: aws.String(v.(string)), - }) + if v, ok := d.GetOk("dimensions"); ok { + params.Dimensions = expandAwsCloudWatchMetricAlarmDimensions(v.(map[string]interface{})) } - params.Dimensions = dimensions return params } -func getAwsCloudWatchMetricAlarm(d *schema.ResourceData, meta interface{}) (*cloudwatch.MetricAlarm, error) { - conn := meta.(*AWSClient).cloudwatchconn +func flattenAwsCloudWatchMetricAlarmDimensions(dims []*cloudwatch.Dimension) map[string]interface{} { + flatDims := make(map[string]interface{}) + for _, d := range dims { + flatDims[aws.StringValue(d.Name)] = aws.StringValue(d.Value) + } + return flatDims +} - params := cloudwatch.DescribeAlarmsInput{ - AlarmNames: []*string{aws.String(d.Id())}, +func flattenAwsCloudWatchMetricAlarmMetrics(metrics []*cloudwatch.MetricDataQuery) []map[string]interface{} { + metricQueries := make([]map[string]interface{}, 0) + for _, mq := range metrics { + metricQuery := map[string]interface{}{ + "expression": aws.StringValue(mq.Expression), + "id": aws.StringValue(mq.Id), + "label": aws.StringValue(mq.Label), + "return_data": aws.BoolValue(mq.ReturnData), + } + if mq.MetricStat != nil { + metric := flattenAwsCloudWatchMetricAlarmMetricsMetricStat(mq.MetricStat) + metricQuery["metric"] = []interface{}{metric} + } + metricQueries = append(metricQueries, metricQuery) } - resp, err := conn.DescribeAlarms(¶ms) - if err != nil { - return nil, err + return metricQueries +} + +func flattenAwsCloudWatchMetricAlarmMetricsMetricStat(ms *cloudwatch.MetricStat) map[string]interface{} { + msm := ms.Metric + metric := map[string]interface{}{ + "metric_name": aws.StringValue(msm.MetricName), + "namespace": aws.StringValue(msm.Namespace), + "period": int(aws.Int64Value(ms.Period)), + "stat": aws.StringValue(ms.Stat), + "unit": aws.StringValue(ms.Unit), + "dimensions": flattenAwsCloudWatchMetricAlarmDimensions(msm.Dimensions), } - // Find it and return it - for idx, ma := range resp.MetricAlarms { - if aws.StringValue(ma.AlarmName) == d.Id() { - return resp.MetricAlarms[idx], nil + return metric +} + +func expandCloudWatchMetricAlarmMetrics(v *schema.Set) []*cloudwatch.MetricDataQuery { + var metrics []*cloudwatch.MetricDataQuery + + for _, v := range v.List() { + metricQueryResource := v.(map[string]interface{}) + id := metricQueryResource["id"].(string) + if id == "" { + continue + } + metricQuery := cloudwatch.MetricDataQuery{ + Id: aws.String(id), } + if v, ok := metricQueryResource["expression"]; ok && v.(string) != "" { + metricQuery.Expression = aws.String(v.(string)) + } + if v, ok := metricQueryResource["label"]; ok && v.(string) != "" { + metricQuery.Label = aws.String(v.(string)) + } + if v, ok := metricQueryResource["return_data"]; ok { + metricQuery.ReturnData = aws.Bool(v.(bool)) + } + if v := metricQueryResource["metric"]; v != nil { + metricQuery.MetricStat = expandCloudWatchMetricAlarmMetricsMetric(v.([]interface{})) + } + metrics = append(metrics, &metricQuery) } + return metrics +} - return nil, nil +func expandCloudWatchMetricAlarmMetricsMetric(v []interface{}) *cloudwatch.MetricStat { + metricResource := v[0].(map[string]interface{}) + metric := cloudwatch.Metric{ + MetricName: aws.String(metricResource["metric_name"].(string)), + } + metricStat := cloudwatch.MetricStat{ + Metric: &metric, + Stat: aws.String(metricResource["stat"].(string)), + } + if v, ok := metricResource["namespace"]; ok && v.(string) != "" { + metric.Namespace = aws.String(v.(string)) + } + if v, ok := metricResource["period"]; ok { + metricStat.Period = aws.Int64(int64(v.(int))) + } + if v, ok := metricResource["unit"]; ok && v.(string) != "" { + metricStat.Unit = aws.String(v.(string)) + } + a := metricResource["dimensions"].(map[string]interface{}) + dimensions := make([]*cloudwatch.Dimension, 0, len(a)) + for k, v := range a { + dimensions = append(dimensions, &cloudwatch.Dimension{ + Name: aws.String(k), + Value: aws.String(v.(string)), + }) + } + metric.Dimensions = dimensions + return &metricStat } -func flattenDimensions(dims []*cloudwatch.Dimension) map[string]interface{} { - flatDims := make(map[string]interface{}) - for _, d := range dims { - flatDims[aws.StringValue(d.Name)] = aws.StringValue(d.Value) +func expandAwsCloudWatchMetricAlarmDimensions(dims map[string]interface{}) []*cloudwatch.Dimension { + var dimensions []*cloudwatch.Dimension + for k, v := range dims { + dimensions = append(dimensions, &cloudwatch.Dimension{ + Name: aws.String(k), + Value: aws.String(v.(string)), + }) } - return flatDims + return dimensions } diff --git a/aws/resource_aws_cloudwatch_metric_alarm_test.go b/aws/resource_aws_cloudwatch_metric_alarm_test.go index e706a43b02f0..e6c15d1f84a6 100644 --- a/aws/resource_aws_cloudwatch_metric_alarm_test.go +++ b/aws/resource_aws_cloudwatch_metric_alarm_test.go @@ -10,6 +10,7 @@ import ( "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatch/finder" ) func TestAccAWSCloudWatchMetricAlarm_basic(t *testing.T) { @@ -30,8 +31,18 @@ func TestAccAWSCloudWatchMetricAlarm_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "metric_name", "CPUUtilization"), resource.TestCheckResourceAttr(resourceName, "statistic", "Average"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "cloudwatch", regexp.MustCompile(`alarm:.+`)), - testAccCheckCloudWatchMetricAlarmDimension(resourceName, "InstanceId", "i-abc123"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "alarm_description", "This metric monitors ec2 cpu utilization"), + resource.TestCheckResourceAttr(resourceName, "threshold", "80"), + resource.TestCheckResourceAttr(resourceName, "period", "120"), + resource.TestCheckResourceAttr(resourceName, "namespace", "AWS/EC2"), + resource.TestCheckResourceAttr(resourceName, "alarm_name", rName), + resource.TestCheckResourceAttr(resourceName, "comparison_operator", "GreaterThanOrEqualToThreshold"), + resource.TestCheckResourceAttr(resourceName, "datapoints_to_alarm", "0"), + resource.TestCheckResourceAttr(resourceName, "evaluation_periods", "2"), + resource.TestCheckResourceAttr(resourceName, "insufficient_data_actions.#", "0"), + resource.TestCheckResourceAttr(resourceName, "dimensions.%", "1"), + resource.TestCheckResourceAttr(resourceName, "dimensions.InstanceId", "i-abc123"), ), }, { @@ -390,24 +401,6 @@ func TestAccAWSCloudWatchMetricAlarm_disappears(t *testing.T) { }) } -func testAccCheckCloudWatchMetricAlarmDimension(n, k, v string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } - key := fmt.Sprintf("dimensions.%s", k) - val, ok := rs.Primary.Attributes[key] - if !ok { - return fmt.Errorf("Could not find dimension: %s", k) - } - if val != v { - return fmt.Errorf("Expected dimension %s => %s; got: %s", k, v, val) - } - return nil - } -} - func testAccCheckCloudWatchMetricAlarmExists(n string, alarm *cloudwatch.MetricAlarm) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -416,17 +409,14 @@ func testAccCheckCloudWatchMetricAlarmExists(n string, alarm *cloudwatch.MetricA } conn := testAccProvider.Meta().(*AWSClient).cloudwatchconn - params := cloudwatch.DescribeAlarmsInput{ - AlarmNames: []*string{aws.String(rs.Primary.ID)}, - } - resp, err := conn.DescribeAlarms(¶ms) + resp, err := finder.MetricAlarmByName(conn, rs.Primary.ID) if err != nil { return err } - if len(resp.MetricAlarms) == 0 { + if resp == nil { return fmt.Errorf("Alarm not found") } - *alarm = *resp.MetricAlarms[0] + *alarm = *resp return nil } @@ -440,15 +430,9 @@ func testAccCheckAWSCloudWatchMetricAlarmDestroy(s *terraform.State) error { continue } - params := cloudwatch.DescribeAlarmsInput{ - AlarmNames: []*string{aws.String(rs.Primary.ID)}, - } - - resp, err := conn.DescribeAlarms(¶ms) - + resp, err := finder.MetricAlarmByName(conn, rs.Primary.ID) if err == nil { - if len(resp.MetricAlarms) != 0 && - *resp.MetricAlarms[0].AlarmName == rs.Primary.ID { + if resp != nil && aws.StringValue(resp.AlarmName) == rs.Primary.ID { return fmt.Errorf("Alarm Still Exists: %s", rs.Primary.ID) } } From 2249edac3f6b25ed47910bbcb3f66258c17d9c20 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 May 2021 19:16:37 +0300 Subject: [PATCH 0096/1208] changelog --- .changelog/19571.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19571.txt diff --git a/.changelog/19571.txt b/.changelog/19571.txt new file mode 100644 index 000000000000..b2ba1cf5694e --- /dev/null +++ b/.changelog/19571.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_cloudwatch_metric_alarm: Add plan time validation to `metric_query.metric.stat`. +``` \ No newline at end of file From ea6b0c618b774e60a927c0d1c6181711a0db8510 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 May 2021 19:23:51 +0300 Subject: [PATCH 0097/1208] revert --- aws/resource_aws_cloudwatch_metric_alarm.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/aws/resource_aws_cloudwatch_metric_alarm.go b/aws/resource_aws_cloudwatch_metric_alarm.go index f5d32df556df..4e9afa2620e5 100644 --- a/aws/resource_aws_cloudwatch_metric_alarm.go +++ b/aws/resource_aws_cloudwatch_metric_alarm.go @@ -145,7 +145,6 @@ func resourceAwsCloudWatchMetricAlarm() *schema.Resource { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"extended_statistic", "metric_query"}, - ExactlyOneOf: []string{"extended_statistic", "statistic"}, ValidateFunc: validation.StringInSlice(cloudwatch.Statistic_Values(), false), }, "threshold": { @@ -225,7 +224,6 @@ func resourceAwsCloudWatchMetricAlarm() *schema.Resource { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"statistic", "metric_query"}, - ExactlyOneOf: []string{"extended_statistic", "statistic"}, ValidateFunc: validation.StringMatch(regexp.MustCompile(`p(\d{1,2}(\.\d{0,2})?|100)`), "must specify a value between p0.0 and p100"), }, "treat_missing_data": { @@ -250,6 +248,14 @@ func resourceAwsCloudWatchMetricAlarm() *schema.Resource { } func validateResourceAwsCloudWatchMetricAlarm(d *schema.ResourceData) error { + _, metricNameOk := d.GetOk("metric_name") + _, statisticOk := d.GetOk("statistic") + _, extendedStatisticOk := d.GetOk("extended_statistic") + + if metricNameOk && ((!statisticOk && !extendedStatisticOk) || (statisticOk && extendedStatisticOk)) { + return fmt.Errorf("One of `statistic` or `extended_statistic` must be set for a cloudwatch metric alarm") + } + if v := d.Get("metric_query"); v != nil { for _, v := range v.(*schema.Set).List() { metricQueryResource := v.(map[string]interface{}) @@ -573,15 +579,10 @@ func expandCloudWatchMetricAlarmMetricsMetric(v []interface{}) *cloudwatch.Metri if v, ok := metricResource["unit"]; ok && v.(string) != "" { metricStat.Unit = aws.String(v.(string)) } - a := metricResource["dimensions"].(map[string]interface{}) - dimensions := make([]*cloudwatch.Dimension, 0, len(a)) - for k, v := range a { - dimensions = append(dimensions, &cloudwatch.Dimension{ - Name: aws.String(k), - Value: aws.String(v.(string)), - }) + if v, ok := metricResource["dimensions"]; ok { + metric.Dimensions = expandAwsCloudWatchMetricAlarmDimensions(v.(map[string]interface{})) } - metric.Dimensions = dimensions + return &metricStat } From d4a1de90338d73dc90e8245ea6efa76b5c292e03 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 28 May 2021 12:30:44 -0400 Subject: [PATCH 0098/1208] tests/ds/servicecat_constraint: Fix typo --- aws/data_source_aws_servicecatalog_constraint_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/data_source_aws_servicecatalog_constraint_test.go b/aws/data_source_aws_servicecatalog_constraint_test.go index d8e8b40e954d..132f6cbf8586 100644 --- a/aws/data_source_aws_servicecatalog_constraint_test.go +++ b/aws/data_source_aws_servicecatalog_constraint_test.go @@ -23,7 +23,7 @@ func TestAccAWSServiceCatalogConstraintDataSource_basic(t *testing.T) { Config: testAccAWSServiceCatalogConstraintDataSourceConfig_basic(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogConstraintExists(resourceName), - resource.TestCheckResourceAttrPair(resourceName, "acceptLanguage", dataSourceName, "acceptLanguage"), + resource.TestCheckResourceAttrPair(resourceName, "accept_language", dataSourceName, "accept_language"), resource.TestCheckResourceAttrPair(resourceName, "description", dataSourceName, "description"), resource.TestCheckResourceAttrPair(resourceName, "owner", dataSourceName, "owner"), resource.TestCheckResourceAttrPair(resourceName, "parameters", dataSourceName, "parameters"), From 3effe64dd628d6b8e85dc59f4f4858cdbc8de11d Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 May 2021 19:56:58 +0300 Subject: [PATCH 0099/1208] check fo len --- aws/resource_aws_cloudwatch_metric_alarm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudwatch_metric_alarm.go b/aws/resource_aws_cloudwatch_metric_alarm.go index 4e9afa2620e5..c3ac1c24fed9 100644 --- a/aws/resource_aws_cloudwatch_metric_alarm.go +++ b/aws/resource_aws_cloudwatch_metric_alarm.go @@ -553,7 +553,7 @@ func expandCloudWatchMetricAlarmMetrics(v *schema.Set) []*cloudwatch.MetricDataQ if v, ok := metricQueryResource["return_data"]; ok { metricQuery.ReturnData = aws.Bool(v.(bool)) } - if v := metricQueryResource["metric"]; v != nil { + if v := metricQueryResource["metric"]; v != nil && len(v.([]interface{})) > 0 { metricQuery.MetricStat = expandCloudWatchMetricAlarmMetricsMetric(v.([]interface{})) } metrics = append(metrics, &metricQuery) From ea084260bd7197437de0bc8ea905146d40e6ec35 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 May 2021 20:50:35 +0300 Subject: [PATCH 0100/1208] add timout arg --- aws/resource_aws_devicefarm_project.go | 58 +++++++++++++------- aws/resource_aws_devicefarm_project_test.go | 60 +++++++++++++++++++++ 2 files changed, 98 insertions(+), 20 deletions(-) diff --git a/aws/resource_aws_devicefarm_project.go b/aws/resource_aws_devicefarm_project.go index 4fc1249f96e5..3b4cd9f8e7b5 100644 --- a/aws/resource_aws_devicefarm_project.go +++ b/aws/resource_aws_devicefarm_project.go @@ -7,6 +7,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/devicefarm" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func resourceAwsDevicefarmProject() *schema.Resource { @@ -26,8 +27,13 @@ func resourceAwsDevicefarmProject() *schema.Resource { }, "name": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 256), + }, + "default_job_timeout_minutes": { + Type: schema.TypeInt, + Optional: true, }, }, } @@ -36,18 +42,24 @@ func resourceAwsDevicefarmProject() *schema.Resource { func resourceAwsDevicefarmProjectCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).devicefarmconn + name := d.Get("name").(string) input := &devicefarm.CreateProjectInput{ - Name: aws.String(d.Get("name").(string)), + Name: aws.String(name), + } + + if v, ok := d.GetOk("default_job_timeout_minutes"); ok { + input.DefaultJobTimeoutMinutes = aws.Int64(int64(v.(int))) } - log.Printf("[DEBUG] Creating DeviceFarm Project: %s", d.Get("name").(string)) + log.Printf("[DEBUG] Creating DeviceFarm Project: %s", name) out, err := conn.CreateProject(input) if err != nil { - return fmt.Errorf("Error creating DeviceFarm Project: %s", err) + return fmt.Errorf("Error creating DeviceFarm Project: %w", err) } - log.Printf("[DEBUG] Successsfully Created DeviceFarm Project: %s", *out.Project.Arn) - d.SetId(aws.StringValue(out.Project.Arn)) + arn := aws.StringValue(out.Project.Arn) + log.Printf("[DEBUG] Successsfully Created DeviceFarm Project: %s", arn) + d.SetId(arn) return resourceAwsDevicefarmProjectRead(d, meta) } @@ -67,11 +79,13 @@ func resourceAwsDevicefarmProjectRead(d *schema.ResourceData, meta interface{}) d.SetId("") return nil } - return fmt.Errorf("Error reading DeviceFarm Project: %s", err) + return fmt.Errorf("Error reading DeviceFarm Project: %w", err) } - d.Set("name", out.Project.Name) - d.Set("arn", out.Project.Arn) + project := out.Project + d.Set("name", project.Name) + d.Set("arn", project.Arn) + d.Set("default_job_timeout_minutes", project.DefaultJobTimeoutMinutes) return nil } @@ -79,18 +93,22 @@ func resourceAwsDevicefarmProjectRead(d *schema.ResourceData, meta interface{}) func resourceAwsDevicefarmProjectUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).devicefarmconn + input := &devicefarm.UpdateProjectInput{ + Arn: aws.String(d.Id()), + } + if d.HasChange("name") { - input := &devicefarm.UpdateProjectInput{ - Arn: aws.String(d.Id()), - Name: aws.String(d.Get("name").(string)), - } + input.Name = aws.String(d.Get("name").(string)) + } - log.Printf("[DEBUG] Updating DeviceFarm Project: %s", d.Id()) - _, err := conn.UpdateProject(input) - if err != nil { - return fmt.Errorf("Error Updating DeviceFarm Project: %s", err) - } + if d.HasChange("default_job_timeout_minutes") { + input.DefaultJobTimeoutMinutes = aws.Int64(int64(d.Get("default_job_timeout_minutes").(int))) + } + log.Printf("[DEBUG] Updating DeviceFarm Project: %s", d.Id()) + _, err := conn.UpdateProject(input) + if err != nil { + return fmt.Errorf("Error Updating DeviceFarm Project: %w", err) } return resourceAwsDevicefarmProjectRead(d, meta) @@ -106,7 +124,7 @@ func resourceAwsDevicefarmProjectDelete(d *schema.ResourceData, meta interface{} log.Printf("[DEBUG] Deleting DeviceFarm Project: %s", d.Id()) _, err := conn.DeleteProject(input) if err != nil { - return fmt.Errorf("Error deleting DeviceFarm Project: %s", err) + return fmt.Errorf("Error deleting DeviceFarm Project: %w", err) } return nil diff --git a/aws/resource_aws_devicefarm_project_test.go b/aws/resource_aws_devicefarm_project_test.go index 41844b75407c..00173c417901 100644 --- a/aws/resource_aws_devicefarm_project_test.go +++ b/aws/resource_aws_devicefarm_project_test.go @@ -16,6 +16,7 @@ import ( func TestAccAWSDeviceFarmProject_basic(t *testing.T) { var proj devicefarm.Project rName := acctest.RandomWithPrefix("tf-acc-test") + rNameUpdated := acctest.RandomWithPrefix("tf-acc-test-updated") resourceName := "aws_devicefarm_project.test" resource.ParallelTest(t, resource.TestCase{ @@ -43,6 +44,56 @@ func TestAccAWSDeviceFarmProject_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccDeviceFarmProjectConfig(rNameUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckDeviceFarmProjectExists(resourceName, &proj), + resource.TestCheckResourceAttr(resourceName, "name", rNameUpdated), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "devicefarm", regexp.MustCompile(`project:.+`)), + ), + }, + }, + }) +} + +func TestAccAWSDeviceFarmProject_timeout(t *testing.T) { + var proj devicefarm.Project + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_devicefarm_project.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPartitionHasServicePreCheck(devicefarm.EndpointsID, t) + // Currently, DeviceFarm is only supported in us-west-2 + // https://docs.aws.amazon.com/general/latest/gr/devicefarm.html + testAccRegionPreCheck(t, endpoints.UsWest2RegionID) + }, + ErrorCheck: testAccErrorCheck(t, devicefarm.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckDeviceFarmProjectDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDeviceFarmProjectConfigDefaultJobTimeout(rName, 10), + Check: resource.ComposeTestCheckFunc( + testAccCheckDeviceFarmProjectExists(resourceName, &proj), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "default_job_timeout_minutes", "10"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccDeviceFarmProjectConfigDefaultJobTimeout(rName, 20), + Check: resource.ComposeTestCheckFunc( + testAccCheckDeviceFarmProjectExists(resourceName, &proj), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "default_job_timeout_minutes", "20"), + ), + }, }, }) } @@ -137,3 +188,12 @@ resource "aws_devicefarm_project" "test" { } `, rName) } + +func testAccDeviceFarmProjectConfigDefaultJobTimeout(rName string, timeout int) string { + return fmt.Sprintf(` +resource "aws_devicefarm_project" "test" { + name = %[1]q + default_job_timeout_minutes = %[2]d +} +`, rName, timeout) +} From 6880beb207a7ec98003843f83d36ea947ada7c99 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 May 2021 21:08:26 +0300 Subject: [PATCH 0101/1208] docs --- website/docs/r/devicefarm_project.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/devicefarm_project.html.markdown b/website/docs/r/devicefarm_project.html.markdown index 725f073618c2..fbe6dfa725a3 100644 --- a/website/docs/r/devicefarm_project.html.markdown +++ b/website/docs/r/devicefarm_project.html.markdown @@ -27,6 +27,7 @@ resource "aws_devicefarm_project" "awesome_devices" { ## Argument Reference * `name` - (Required) The name of the project +* `default_job_timeout_minutes` - (Optional) Sets the execution timeout value (in minutes) for a project. All test runs in this project use the specified execution timeout value unless overridden when scheduling a run. ## Attributes Reference From 4880bcf85bc8f3127303801e5832b74f8feb7ce8 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 May 2021 21:09:59 +0300 Subject: [PATCH 0102/1208] changelog --- .changelog/19574.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/19574.txt diff --git a/.changelog/19574.txt b/.changelog/19574.txt new file mode 100644 index 000000000000..f3b5f5d27bdc --- /dev/null +++ b/.changelog/19574.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_devicefarm_project: Add `default_job_timeout_minutes` argument +``` + +```release-note:enhancement +resource/aws_devicefarm_project: Add plan time validation for `name` +``` \ No newline at end of file From 4eb4ef6f0b965ee1dc1fc2e961f79b7ee6f5a9f1 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 29 May 2021 01:16:16 +0300 Subject: [PATCH 0103/1208] add tagging support --- .changelog/19574.txt | 2 +- aws/resource_aws_devicefarm_project.go | 71 +++++++++++++---- aws/resource_aws_devicefarm_project_test.go | 77 +++++++++++++++++++ .../docs/r/devicefarm_project.html.markdown | 2 + 4 files changed, 138 insertions(+), 14 deletions(-) diff --git a/.changelog/19574.txt b/.changelog/19574.txt index f3b5f5d27bdc..be8af655535f 100644 --- a/.changelog/19574.txt +++ b/.changelog/19574.txt @@ -1,5 +1,5 @@ ```release-note:enhancement -resource/aws_devicefarm_project: Add `default_job_timeout_minutes` argument +resource/aws_devicefarm_project: Add `default_job_timeout_minutes` and `tags` argument ``` ```release-note:enhancement diff --git a/aws/resource_aws_devicefarm_project.go b/aws/resource_aws_devicefarm_project.go index 3b4cd9f8e7b5..643975323f58 100644 --- a/aws/resource_aws_devicefarm_project.go +++ b/aws/resource_aws_devicefarm_project.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/service/devicefarm" "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 resourceAwsDevicefarmProject() *schema.Resource { @@ -35,12 +36,17 @@ func resourceAwsDevicefarmProject() *schema.Resource { Type: schema.TypeInt, Optional: true, }, + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, + CustomizeDiff: SetTagsDiff, } } func resourceAwsDevicefarmProjectCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).devicefarmconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) name := d.Get("name").(string) input := &devicefarm.CreateProjectInput{ @@ -61,11 +67,19 @@ func resourceAwsDevicefarmProjectCreate(d *schema.ResourceData, meta interface{} log.Printf("[DEBUG] Successsfully Created DeviceFarm Project: %s", arn) d.SetId(arn) + if len(tags) > 0 { + if err := keyvaluetags.DevicefarmUpdateTags(conn, arn, nil, tags); err != nil { + return fmt.Errorf("error updating DeviceFarm Project (%s) tags: %w", arn, err) + } + } + return resourceAwsDevicefarmProjectRead(d, meta) } func resourceAwsDevicefarmProjectRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).devicefarmconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig input := &devicefarm.GetProjectInput{ Arn: aws.String(d.Id()), @@ -83,32 +97,60 @@ func resourceAwsDevicefarmProjectRead(d *schema.ResourceData, meta interface{}) } project := out.Project + arn := aws.StringValue(project.Arn) d.Set("name", project.Name) - d.Set("arn", project.Arn) + d.Set("arn", arn) d.Set("default_job_timeout_minutes", project.DefaultJobTimeoutMinutes) + tags, err := keyvaluetags.DevicefarmListTags(conn, arn) + + if err != nil { + return fmt.Errorf("error listing tags for DeviceFarm Project (%s): %w", arn, 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_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) + } + return nil } func resourceAwsDevicefarmProjectUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).devicefarmconn - input := &devicefarm.UpdateProjectInput{ - Arn: aws.String(d.Id()), - } + if d.HasChangesExcept("tags", "tags_all") { + input := &devicefarm.UpdateProjectInput{ + Arn: aws.String(d.Id()), + } - if d.HasChange("name") { - input.Name = aws.String(d.Get("name").(string)) - } + if d.HasChange("name") { + input.Name = aws.String(d.Get("name").(string)) + } - if d.HasChange("default_job_timeout_minutes") { - input.DefaultJobTimeoutMinutes = aws.Int64(int64(d.Get("default_job_timeout_minutes").(int))) + if d.HasChange("default_job_timeout_minutes") { + input.DefaultJobTimeoutMinutes = aws.Int64(int64(d.Get("default_job_timeout_minutes").(int))) + } + + log.Printf("[DEBUG] Updating DeviceFarm Project: %s", d.Id()) + _, err := conn.UpdateProject(input) + if err != nil { + return fmt.Errorf("Error Updating DeviceFarm Project: %w", err) + } } - log.Printf("[DEBUG] Updating DeviceFarm Project: %s", d.Id()) - _, err := conn.UpdateProject(input) - if err != nil { - return fmt.Errorf("Error Updating DeviceFarm Project: %w", err) + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + + if err := keyvaluetags.DevicefarmUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating DeviceFarm Project (%s) tags: %w", d.Get("arn").(string), err) + } } return resourceAwsDevicefarmProjectRead(d, meta) @@ -124,6 +166,9 @@ func resourceAwsDevicefarmProjectDelete(d *schema.ResourceData, meta interface{} log.Printf("[DEBUG] Deleting DeviceFarm Project: %s", d.Id()) _, err := conn.DeleteProject(input) if err != nil { + if isAWSErr(err, devicefarm.ErrCodeNotFoundException, "") { + return nil + } return fmt.Errorf("Error deleting DeviceFarm Project: %w", err) } diff --git a/aws/resource_aws_devicefarm_project_test.go b/aws/resource_aws_devicefarm_project_test.go index 00173c417901..dcb1d867bb13 100644 --- a/aws/resource_aws_devicefarm_project_test.go +++ b/aws/resource_aws_devicefarm_project_test.go @@ -36,6 +36,7 @@ func TestAccAWSDeviceFarmProject_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckDeviceFarmProjectExists(resourceName, &proj), resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "devicefarm", regexp.MustCompile(`project:.+`)), ), }, @@ -98,6 +99,57 @@ func TestAccAWSDeviceFarmProject_timeout(t *testing.T) { }) } +func TestAccAWSDeviceFarmProject_tags(t *testing.T) { + var proj devicefarm.Project + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_devicefarm_project.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPartitionHasServicePreCheck(devicefarm.EndpointsID, t) + // Currently, DeviceFarm is only supported in us-west-2 + // https://docs.aws.amazon.com/general/latest/gr/devicefarm.html + testAccRegionPreCheck(t, endpoints.UsWest2RegionID) + }, + ErrorCheck: testAccErrorCheck(t, devicefarm.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckDeviceFarmProjectDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDeviceFarmProjectConfigTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDeviceFarmProjectExists(resourceName, &proj), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccDeviceFarmProjectConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDeviceFarmProjectExists(resourceName, &proj), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccDeviceFarmProjectConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDeviceFarmProjectExists(resourceName, &proj), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func TestAccAWSDeviceFarmProject_disappears(t *testing.T) { var proj devicefarm.Project rName := acctest.RandomWithPrefix("tf-acc-test") @@ -197,3 +249,28 @@ resource "aws_devicefarm_project" "test" { } `, rName, timeout) } + +func testAccDeviceFarmProjectConfigTags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_devicefarm_project" "test" { + name = %[1]q + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccDeviceFarmProjectConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_devicefarm_project" "test" { + name = %[1]q + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} diff --git a/website/docs/r/devicefarm_project.html.markdown b/website/docs/r/devicefarm_project.html.markdown index fbe6dfa725a3..7581da695046 100644 --- a/website/docs/r/devicefarm_project.html.markdown +++ b/website/docs/r/devicefarm_project.html.markdown @@ -28,12 +28,14 @@ resource "aws_devicefarm_project" "awesome_devices" { * `name` - (Required) The name of the project * `default_job_timeout_minutes` - (Optional) Sets the execution timeout value (in minutes) for a project. All test runs in this project use the specified execution timeout value unless overridden when scheduling a run. +* `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 of this project +* `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). [aws-get-project]: http://docs.aws.amazon.com/devicefarm/latest/APIReference/API_GetProject.html From fd24595aed1eb6da3f3f69be0c86bc406cc569d9 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 29 May 2021 01:19:06 +0300 Subject: [PATCH 0104/1208] fmt --- aws/resource_aws_devicefarm_project_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_devicefarm_project_test.go b/aws/resource_aws_devicefarm_project_test.go index dcb1d867bb13..48f831ac0e64 100644 --- a/aws/resource_aws_devicefarm_project_test.go +++ b/aws/resource_aws_devicefarm_project_test.go @@ -257,7 +257,7 @@ resource "aws_devicefarm_project" "test" { tags = { %[2]q = %[3]q - } + } } `, rName, tagKey1, tagValue1) } @@ -270,7 +270,7 @@ resource "aws_devicefarm_project" "test" { tags = { %[2]q = %[3]q %[4]q = %[5]q - } + } } `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } From 80c513628a6bcb899d0e5b384545f096567c2f34 Mon Sep 17 00:00:00 2001 From: teruya <27873650+teru01@users.noreply.github.com> Date: Sun, 30 May 2021 11:52:30 +0900 Subject: [PATCH 0105/1208] update docs: add codebuild_source_credential note --- website/docs/r/codebuild_source_credential.html.markdown | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/docs/r/codebuild_source_credential.html.markdown b/website/docs/r/codebuild_source_credential.html.markdown index 60c14a93aa40..cb995824d6ec 100644 --- a/website/docs/r/codebuild_source_credential.html.markdown +++ b/website/docs/r/codebuild_source_credential.html.markdown @@ -10,6 +10,9 @@ description: |- Provides a CodeBuild Source Credentials Resource. +~> **NOTE:** +[Codebuild only allows a single credential per given server type in a given region](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_codebuild.GitHubSourceCredentials.html). Therefore, when you define `aws_codebuild_source_credential`, [`aws_codebuild_project` resource](/docs/providers/aws/r/codebuild_project.html) defined in the same module will use it. + ## Example Usage ```terraform From b3137917e2eef0bc6a5960be5ce905b5d1dd17ac Mon Sep 17 00:00:00 2001 From: Gyeongjun Paik Date: Mon, 31 May 2021 19:03:05 +0900 Subject: [PATCH 0106/1208] Update lb_target_group docs - #19590 Issue solved Description [This PR](https://github.com/terraform-aws-modules/terraform-aws-alb/pull/160) is merged. But not apply in terraform docs in site lambda_multi_value_headers_enabled is changed from null to false The changes were not reflected in the document. --- website/docs/r/lb_target_group.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lb_target_group.html.markdown b/website/docs/r/lb_target_group.html.markdown index 37829a3ed78a..3d09b7762b8a 100644 --- a/website/docs/r/lb_target_group.html.markdown +++ b/website/docs/r/lb_target_group.html.markdown @@ -60,7 +60,7 @@ The following arguments are supported: * `deregistration_delay` - (Optional) Amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused. The range is 0-3600 seconds. The default value is 300 seconds. * `health_check` - (Optional, Maximum of 1) Health Check configuration block. Detailed below. -* `lambda_multi_value_headers_enabled` - (Optional) Whether the request and response headers exchanged between the load balancer and the Lambda function include arrays of values or strings. Only applies when `target_type` is `lambda`. +* `lambda_multi_value_headers_enabled` - (Optional) Whether the request and response headers exchanged between the load balancer and the Lambda function include arrays of values or strings. Only applies when `target_type` is `lambda`. Default is `false`. * `load_balancing_algorithm_type` - (Optional) Determines how the load balancer selects targets when routing requests. Only applicable for Application Load Balancer Target Groups. The value is `round_robin` or `least_outstanding_requests`. The default is `round_robin`. * `name_prefix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`. Cannot be longer than 6 characters. * `name` - (Optional, Forces new resource) Name of the target group. If omitted, Terraform will assign a random, unique name. From 85f21b503719f6ff4eb259887b4c178f4be204e1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 31 May 2021 08:11:52 -0400 Subject: [PATCH 0107/1208] r/aws_cloudwatch_event_api_destination: Maximum value for 'invocation_rate_limit_per_second' is '300'. --- aws/resource_aws_cloudwatch_event_api_destination.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_api_destination.go b/aws/resource_aws_cloudwatch_event_api_destination.go index f2ff0d42af14..0a645db0a8db 100644 --- a/aws/resource_aws_cloudwatch_event_api_destination.go +++ b/aws/resource_aws_cloudwatch_event_api_destination.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "math" "regexp" "github.com/aws/aws-sdk-go/aws" @@ -44,7 +43,7 @@ func resourceAwsCloudWatchEventApiDestination() *schema.Resource { "invocation_rate_limit_per_second": { Type: schema.TypeInt, Optional: true, - ValidateFunc: validation.IntBetween(1, math.MaxInt64), + ValidateFunc: validation.IntBetween(1, 300), Default: 300, }, "http_method": { From 24ce02a85c73f4ec86f5b02d8331f55dc969dd14 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 31 May 2021 08:21:17 -0400 Subject: [PATCH 0108/1208] Add CHANGELOG entry. --- .changelog/19594.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19594.txt diff --git a/.changelog/19594.txt b/.changelog/19594.txt new file mode 100644 index 000000000000..3c8b2b5ca13c --- /dev/null +++ b/.changelog/19594.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_cloudwatch_event_api_destination: Reduce the maximum allowed value for the `invocation_rate_limit_per_second` argument to `300` +``` From 56325ac002a768c763282af51e73dc6bff5c041d Mon Sep 17 00:00:00 2001 From: alextodicescu <30607646+alextodicescu@users.noreply.github.com> Date: Mon, 31 May 2021 18:17:33 +0300 Subject: [PATCH 0109/1208] Update ssoadmin_managed_policy_attachment.html.markdown Update example from aws_ssoadmin_managed_policy_attachment resource docs. The `instance_arn` incorrectly references the permission_set arn instead of the aws_ssoadmin_instances arn --- website/docs/r/ssoadmin_managed_policy_attachment.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/ssoadmin_managed_policy_attachment.html.markdown b/website/docs/r/ssoadmin_managed_policy_attachment.html.markdown index 29441ce68445..e162225aa5be 100644 --- a/website/docs/r/ssoadmin_managed_policy_attachment.html.markdown +++ b/website/docs/r/ssoadmin_managed_policy_attachment.html.markdown @@ -23,7 +23,7 @@ resource "aws_ssoadmin_permission_set" "example" { } resource "aws_ssoadmin_managed_policy_attachment" "example" { - instance_arn = aws_ssoadmin_permission_set.example.instance_arn + instance_arn = tolist(data.aws_ssoadmin_instances.example.arns)[0] managed_policy_arn = "arn:aws:iam::aws:policy/AlexaForBusinessDeviceSetup" permission_set_arn = aws_ssoadmin_permission_set.example.arn } From 27d209a7dbe1112d5066ad07cbc974ef88b7c5ad Mon Sep 17 00:00:00 2001 From: philof Date: Mon, 31 May 2021 11:56:55 -0400 Subject: [PATCH 0110/1208] Removes dead code --- ..._aws_elasticsearch_domain_saml_options_test.go | 15 --------------- aws/resource_aws_elasticsearch_domain_test.go | 12 ------------ 2 files changed, 27 deletions(-) diff --git a/aws/resource_aws_elasticsearch_domain_saml_options_test.go b/aws/resource_aws_elasticsearch_domain_saml_options_test.go index 2899f0fb2177..56a814e3fea3 100644 --- a/aws/resource_aws_elasticsearch_domain_saml_options_test.go +++ b/aws/resource_aws_elasticsearch_domain_saml_options_test.go @@ -146,21 +146,6 @@ func testAccCheckESDomainSAMLOptionsDestroy(s *terraform.State) error { return nil } -func testAccCheckESDomainSAMLOptionsDisappears(domainName string) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).esconn - - input := elasticsearch.AdvancedSecurityOptionsInput{} - input.SetSAMLOptions(nil) - _, err := conn.UpdateElasticsearchDomainConfig(&elasticsearch.UpdateElasticsearchDomainConfigInput{ - DomainName: aws.String(domainName), - AdvancedSecurityOptions: &input, - }) - - return err - } -} - func testAccCheckESDomainSAMLOptions(esResource string, samlOptionsResource string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[esResource] diff --git a/aws/resource_aws_elasticsearch_domain_test.go b/aws/resource_aws_elasticsearch_domain_test.go index 5d332813673d..edb3fbf75d8b 100644 --- a/aws/resource_aws_elasticsearch_domain_test.go +++ b/aws/resource_aws_elasticsearch_domain_test.go @@ -1457,18 +1457,6 @@ func testAccPreCheckIamServiceLinkedRoleEs(t *testing.T) { } } -func testAccCheckESDomainDisappears(domainName string) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).esconn - - _, err := conn.DeleteElasticsearchDomain(&elasticsearch.DeleteElasticsearchDomainInput{ - DomainName: aws.String(domainName), - }) - - return err - } -} - func testAccESDomainConfig(randInt int) string { return fmt.Sprintf(` resource "aws_elasticsearch_domain" "test" { From 0862f40c08d08a3dbf2bc35084ea6af06c3db28d Mon Sep 17 00:00:00 2001 From: philof Date: Mon, 31 May 2021 12:02:03 -0400 Subject: [PATCH 0111/1208] Applies terrafmt --- ..._elasticsearch_domain_saml_options_test.go | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/aws/resource_aws_elasticsearch_domain_saml_options_test.go b/aws/resource_aws_elasticsearch_domain_saml_options_test.go index 56a814e3fea3..9469c3a7a932 100644 --- a/aws/resource_aws_elasticsearch_domain_saml_options_test.go +++ b/aws/resource_aws_elasticsearch_domain_saml_options_test.go @@ -218,16 +218,11 @@ resource "aws_elasticsearch_domain_saml_options" "main" { domain_name = aws_elasticsearch_domain.example.domain_name saml_options { - # enabled = true + enabled = true idp { - entity_id = "https://terraform-dev-ed.my.salesforce.com" - metadata_content = file("./test-fixtures/saml-metadata.xml") + entity_id = "https://terraform-dev-ed.my.salesforce.com" + metadata_content = file("./test-fixtures/saml-metadata.xml") } - # master_backend_role = "my-idp-group-or-role" - # master_user_name = "my-idp-user" - # roles_key = "optional-roles-key" - # session_timeout_minutes = 60 - # subject_key = "optional-subject-key" } } `, userName, domainName) @@ -280,16 +275,12 @@ resource "aws_elasticsearch_domain_saml_options" "main" { domain_name = aws_elasticsearch_domain.example.domain_name saml_options { - # enabled = true + enabled = true idp { - entity_id = "https://terraform-dev-ed.my.salesforce.com" - metadata_content = file("./test-fixtures/saml-metadata.xml") + entity_id = "https://terraform-dev-ed.my.salesforce.com" + metadata_content = file("./test-fixtures/saml-metadata.xml") } - # master_backend_role = "my-idp-group-or-role" - # master_user_name = "my-idp-user" - # roles_key = "optional-roles-key" - session_timeout_minutes = 180 - # subject_key = "optional-subject-key" + session_timeout_minutes = 180 } } `, userName, domainName) From 32a661e7cb603a18e39c49f089f5dc890bacedbc Mon Sep 17 00:00:00 2001 From: grahamhar Date: Mon, 31 May 2021 21:37:20 +0100 Subject: [PATCH 0112/1208] Add example showing Web ACL association Provide an example to show how to associate a Web ACL (V2) with appsync api --- .../docs/r/appsync_graphql_api.html.markdown | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/website/docs/r/appsync_graphql_api.html.markdown b/website/docs/r/appsync_graphql_api.html.markdown index b69b1dc48e44..ef2125f45e1e 100644 --- a/website/docs/r/appsync_graphql_api.html.markdown +++ b/website/docs/r/appsync_graphql_api.html.markdown @@ -126,6 +126,59 @@ resource "aws_appsync_graphql_api" "example" { } ``` +### Associate Web ACL (v2) + +```terraform +resource "aws_appsync_graphql_api" "example" { + authentication_type = "API_KEY" + name = "example" +} + +resource "aws_wafv2_web_acl_association" "example" { + resource_arn = aws_appsync_graphql_api.example.arn + web_acl_arn = aws_wafv2_web_acl.example.arn +} + +resource "aws_wafv2_web_acl" "example" { + name = "managed-rule-example" + description = "Example of a managed rule." + scope = "REGIONAL" + + default_action { + allow {} + } + + rule { + name = "rule-1" + priority = 1 + + override_action { + block {} + } + + statement { + managed_rule_group_statement { + name = "AWSManagedRulesCommonRuleSet" + vendor_name = "AWS" + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} + +``` + ## Argument Reference The following arguments are supported: From 0d84bbc706bcf1809c84cd0f797ecdd9a16b219f Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 31 May 2021 16:23:18 -0700 Subject: [PATCH 0113/1208] Documentation cleanup Addresses markdown-lint issue --- website/docs/r/lb_target_group.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lb_target_group.html.markdown b/website/docs/r/lb_target_group.html.markdown index 3d09b7762b8a..327909557844 100644 --- a/website/docs/r/lb_target_group.html.markdown +++ b/website/docs/r/lb_target_group.html.markdown @@ -60,7 +60,7 @@ The following arguments are supported: * `deregistration_delay` - (Optional) Amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused. The range is 0-3600 seconds. The default value is 300 seconds. * `health_check` - (Optional, Maximum of 1) Health Check configuration block. Detailed below. -* `lambda_multi_value_headers_enabled` - (Optional) Whether the request and response headers exchanged between the load balancer and the Lambda function include arrays of values or strings. Only applies when `target_type` is `lambda`. Default is `false`. +* `lambda_multi_value_headers_enabled` - (Optional) Whether the request and response headers exchanged between the load balancer and the Lambda function include arrays of values or strings. Only applies when `target_type` is `lambda`. Default is `false`. * `load_balancing_algorithm_type` - (Optional) Determines how the load balancer selects targets when routing requests. Only applicable for Application Load Balancer Target Groups. The value is `round_robin` or `least_outstanding_requests`. The default is `round_robin`. * `name_prefix` - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with `name`. Cannot be longer than 6 characters. * `name` - (Optional, Forces new resource) Name of the target group. If omitted, Terraform will assign a random, unique name. From bfcc8c1435fb161d9c89e58f1c0bc07a626ee15d Mon Sep 17 00:00:00 2001 From: ZeePal Date: Tue, 1 Jun 2021 18:24:08 +1000 Subject: [PATCH 0114/1208] fix default status for aws_iam_access_key --- .changelog/19606.txt | 3 +++ aws/resource_aws_iam_access_key.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .changelog/19606.txt diff --git a/.changelog/19606.txt b/.changelog/19606.txt new file mode 100644 index 000000000000..a41995893b13 --- /dev/null +++ b/.changelog/19606.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_iam_access_key: Fix status not defaulting to Active +``` diff --git a/aws/resource_aws_iam_access_key.go b/aws/resource_aws_iam_access_key.go index d8bcd7d50549..0b396760eb50 100644 --- a/aws/resource_aws_iam_access_key.go +++ b/aws/resource_aws_iam_access_key.go @@ -58,7 +58,7 @@ func resourceAwsIamAccessKey() *schema.Resource { "status": { Type: schema.TypeString, Optional: true, - Computed: true, + Default: "Active", ValidateFunc: validation.StringInSlice([]string{ iam.StatusTypeActive, iam.StatusTypeInactive, From 6e42da82268783bad70a5eb945984aec3757cae9 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 1 Jun 2021 10:21:30 -0400 Subject: [PATCH 0115/1208] hashibot: Migrate remove_labels_on_reply behavior to GitHub Actions (#19610) --- .github/workflows/issue-comment-created.yml | 15 +++++++++++++++ .hashibot.hcl | 5 ----- 2 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/issue-comment-created.yml diff --git a/.github/workflows/issue-comment-created.yml b/.github/workflows/issue-comment-created.yml new file mode 100644 index 000000000000..b8c4d6bfacc1 --- /dev/null +++ b/.github/workflows/issue-comment-created.yml @@ -0,0 +1,15 @@ +name: Issue Comment Created Triage + +on: + issue_comment: + types: [created] + +jobs: + issue_comment_triage: + runs-on: ubuntu-latest + steps: + - uses: actions-ecosystem/action-remove-labels@v1 + with: + labels: | + stale + waiting-reply diff --git a/.hashibot.hcl b/.hashibot.hcl index 18f7fba72371..b8d0b6e0377e 100644 --- a/.hashibot.hcl +++ b/.hashibot.hcl @@ -8,11 +8,6 @@ queued_behavior "release_commenter" "releases" { EOF } -behavior "remove_labels_on_reply" "remove_stale" { - labels = ["waiting-response", "stale"] - only_non_maintainers = true -} - behavior "pull_request_size_labeler" "size" { label_prefix = "size/" label_map = { From 0152d0ba7256bbeae1c38b6cd03f4ce82549c5e5 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 1 Jun 2021 15:19:43 +0000 Subject: [PATCH 0116/1208] Update CHANGELOG.md for #19594 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2f0ebac30ba..db7fc3cddb9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ BUG FIXES: * resource/aws_apprunner_service: Suppress `instance_configuration` `cpu` and `memory` differences ([#19483](https://github.com/hashicorp/terraform-provider-aws/issues/19483)) * resource/aws_batch_job_definition: Don't crash when setting `timeout.attempt_duration_seconds` to `null` ([#19505](https://github.com/hashicorp/terraform-provider-aws/issues/19505)) * resource/aws_cloudformation_stack: Avoid conflicts with `on_failure` and `disable_rollback` ([#10539](https://github.com/hashicorp/terraform-provider-aws/issues/10539)) +* resource/aws_cloudwatch_event_api_destination: Reduce the maximum allowed value for the `invocation_rate_limit_per_second` argument to `300` ([#19594](https://github.com/hashicorp/terraform-provider-aws/issues/19594)) * resource/aws_ec2_managed_prefix_list: Fix crash with multiple description-only updates ([#19517](https://github.com/hashicorp/terraform-provider-aws/issues/19517)) * resource/aws_eks_addon: Use `service_account_role_arn`, if set, on updates ([#19454](https://github.com/hashicorp/terraform-provider-aws/issues/19454)) * resource/aws_glue_connection: `connection_properties` are optional ([#19375](https://github.com/hashicorp/terraform-provider-aws/issues/19375)) From c406bbfde846e51b02cced0158c364e14dd98b4b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 11:24:37 -0400 Subject: [PATCH 0117/1208] r/aws_lambda_event_source_mapping: Add `queues` argument. --- .changelog/19425.txt | 4 + ...esource_aws_lambda_event_source_mapping.go | 26 ++- ...ce_aws_lambda_event_source_mapping_test.go | 161 +++++++++++++++++- .../lambda_event_source_mapping.html.markdown | 5 +- 4 files changed, 188 insertions(+), 8 deletions(-) diff --git a/.changelog/19425.txt b/.changelog/19425.txt index 0a98108c4deb..270d361e8a9c 100644 --- a/.changelog/19425.txt +++ b/.changelog/19425.txt @@ -8,4 +8,8 @@ resource/aws_lambda_event_source_mapping: Add `tumbling_window_in_seconds` argum ```release-notes:enhancement resource/aws_lambda_event_source_mapping: Add `function_response_types` argument to support AWS Lambda checkpointing +``` + +```release-notes:enhancement +resource/aws_lambda_event_source_mapping: Add `queues` argument to support Amazon MQ for Apache ActiveMQ event sources ``` \ No newline at end of file diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index 764d5f073428..2c8a89d6ae97 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -58,7 +58,7 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { } switch serviceName { - case "dynamodb", "kinesis", "kafka": + case "dynamodb", "kinesis", "kafka", "mq": return old == "100" case "sqs": return old == "10" @@ -176,6 +176,17 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { Computed: true, }, + "queues": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 1000), + }, + }, + "self_managed_event_source": { Type: schema.TypeList, Optional: true, @@ -205,7 +216,6 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { }, }, ExactlyOneOf: []string{"event_source_arn", "self_managed_event_source"}, - RequiredWith: []string{"source_access_configuration"}, }, "source_access_configuration": { @@ -225,7 +235,6 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { }, }, }, - RequiredWith: []string{"self_managed_event_source"}, }, "starting_position": { @@ -256,7 +265,11 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { Type: schema.TypeSet, Optional: true, ForceNew: true, - Elem: &schema.Schema{Type: schema.TypeString}, + MaxItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 249), + }, }, "tumbling_window_in_seconds": { @@ -323,6 +336,10 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte input.ParallelizationFactor = aws.Int64(int64(v.(int))) } + if v, ok := d.GetOk("queues"); ok && v.(*schema.Set).Len() > 0 { + input.Queues = expandStringSet(v.(*schema.Set)) + } + if v, ok := d.GetOk("self_managed_event_source"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.SelfManagedEventSource = expandLambdaSelfManagedEventSource(v.([]interface{})[0].(map[string]interface{})) @@ -431,6 +448,7 @@ func resourceAwsLambdaEventSourceMappingRead(d *schema.ResourceData, meta interf d.Set("maximum_record_age_in_seconds", eventSourceMappingConfiguration.MaximumRecordAgeInSeconds) d.Set("maximum_retry_attempts", eventSourceMappingConfiguration.MaximumRetryAttempts) d.Set("parallelization_factor", eventSourceMappingConfiguration.ParallelizationFactor) + d.Set("queues", aws.StringValueSlice(eventSourceMappingConfiguration.Queues)) if eventSourceMappingConfiguration.SelfManagedEventSource != nil { if err := d.Set("self_managed_event_source", []interface{}{flattenLambdaSelfManagedEventSource(eventSourceMappingConfiguration.SelfManagedEventSource)}); err != nil { return fmt.Errorf("error setting self_managed_event_source: %w", err) diff --git a/aws/resource_aws_lambda_event_source_mapping_test.go b/aws/resource_aws_lambda_event_source_mapping_test.go index 98815547e04d..15d324c5d230 100644 --- a/aws/resource_aws_lambda_event_source_mapping_test.go +++ b/aws/resource_aws_lambda_event_source_mapping_test.go @@ -698,7 +698,7 @@ func TestAccAWSLambdaEventSourceMapping_MSK(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID, "kafka"), //using kafka.EndpointsID will import kafka and make linters sad + ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID, "kafka"), Providers: testAccProviders, CheckDestroy: testAccCheckLambdaEventSourceMappingDestroy, Steps: []resource.TestStep{ @@ -747,7 +747,7 @@ func TestAccAWSLambdaEventSourceMapping_SelfManagedKafka(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID, "kafka"), //using kafka.EndpointsID will import kafka and make linters sad + ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckLambdaEventSourceMappingDestroy, Steps: []resource.TestStep{ @@ -777,6 +777,39 @@ func TestAccAWSLambdaEventSourceMapping_SelfManagedKafka(t *testing.T) { }) } +func TestAccAWSLambdaEventSourceMapping_ActiveMQ(t *testing.T) { + var v lambda.EventSourceMappingConfiguration + resourceName := "aws_lambda_event_source_mapping.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID, "mq", "secretsmanager"), + Providers: testAccProviders, + CheckDestroy: testAccCheckLambdaEventSourceMappingDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLambdaEventSourceMappingConfigActiveMQ(rName, "100"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsLambdaEventSourceMappingExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "batch_size", "100"), + resource.TestCheckResourceAttr(resourceName, "enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "queues.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "queues.*", "test"), + resource.TestCheckResourceAttr(resourceName, "source_access_configuration.#", "1"), + ), + }, + // batch_size became optional. Ensure that if the user supplies the default + // value, but then moves to not providing the value, that we don't consider this + // a diff. + { + PlanOnly: true, + Config: testAccAWSLambdaEventSourceMappingConfigActiveMQ(rName, "null"), + }, + }, + }) +} + func testAccCheckAWSLambdaEventSourceMappingIsBeingDisabled(conf *lambda.EventSourceMappingConfiguration) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).lambdaconn @@ -1147,6 +1180,109 @@ resource "aws_lambda_function" "test" { `, rName)) } +func testAccAWSLambdaEventSourceMappingConfigMQBase(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = < Date: Tue, 1 Jun 2021 11:35:34 -0400 Subject: [PATCH 0118/1208] Fix terrafmt errors. --- aws/resource_aws_lambda_event_source_mapping_test.go | 4 ++-- website/docs/r/lambda_event_source_mapping.html.markdown | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_lambda_event_source_mapping_test.go b/aws/resource_aws_lambda_event_source_mapping_test.go index 15d324c5d230..72571adfa2d7 100644 --- a/aws/resource_aws_lambda_event_source_mapping_test.go +++ b/aws/resource_aws_lambda_event_source_mapping_test.go @@ -1533,13 +1533,13 @@ resource "aws_lambda_event_source_mapping" "test" { for_each = aws_subnet.test.*.id content { type = "VPC_SUBNET" - uri = "subnet:${source_access_configuration.value}" + uri = "subnet:${source_access_configuration.value}" } } source_access_configuration { type = "VPC_SECURITY_GROUP" - uri = aws_security_group.test.id + uri = aws_security_group.test.id } } `, rName, batchSize, kafkaBootstrapServers)) diff --git a/website/docs/r/lambda_event_source_mapping.html.markdown b/website/docs/r/lambda_event_source_mapping.html.markdown index 761733ccc38d..8c529aed398f 100644 --- a/website/docs/r/lambda_event_source_mapping.html.markdown +++ b/website/docs/r/lambda_event_source_mapping.html.markdown @@ -62,17 +62,17 @@ resource "aws_lambda_event_source_mapping" "example" { source_access_configuration { type = "VPC_SUBNET" - uri = "subnet:subnet-example1" + uri = "subnet:subnet-example1" } source_access_configuration { type = "VPC_SUBNET" - uri = "subnet:subnet-example2" + uri = "subnet:subnet-example2" } source_access_configuration { type = "VPC_SECURITY_GROUP" - uri = "security_group:sg-example" + uri = "security_group:sg-example" } } ``` From 89e58959fea34c61b82677c23bc54c22ab62f0cf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 11:57:40 -0400 Subject: [PATCH 0119/1208] r/aws_lambda_event_source_mapping: Correctly handle deletion of 'destination_config'. --- aws/resource_aws_lambda_event_source_mapping.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index 2c8a89d6ae97..82bbb8fd0b27 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -637,7 +637,7 @@ func expandLambdaOnFailure(tfMap map[string]interface{}) *lambda.OnFailure { apiObject := &lambda.OnFailure{} - if v, ok := tfMap["destination_arn"].(string); ok && v != "" { + if v, ok := tfMap["destination_arn"].(string); ok { apiObject.Destination = aws.String(v) } From 2e077d90a849688f68bef1a606680df97994b96f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 11:59:24 -0400 Subject: [PATCH 0120/1208] Fix awsproviderlint errors. --- aws/resource_aws_lambda_event_source_mapping.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index 82bbb8fd0b27..dc96af1f1be0 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -180,7 +180,6 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { Type: schema.TypeSet, Optional: true, ForceNew: true, - MaxItems: 1, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.StringLenBetween(1, 1000), @@ -265,7 +264,6 @@ func resourceAwsLambdaEventSourceMapping() *schema.Resource { Type: schema.TypeSet, Optional: true, ForceNew: true, - MaxItems: 1, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.StringLenBetween(1, 249), From 7c9c511f722e6182f9727104fca910bb207a0bf6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 12:48:44 -0400 Subject: [PATCH 0121/1208] No MQ in GovCloud. --- aws/resource_aws_lambda_event_source_mapping_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_lambda_event_source_mapping_test.go b/aws/resource_aws_lambda_event_source_mapping_test.go index 72571adfa2d7..f5d7c9fe1276 100644 --- a/aws/resource_aws_lambda_event_source_mapping_test.go +++ b/aws/resource_aws_lambda_event_source_mapping_test.go @@ -697,7 +697,7 @@ func TestAccAWSLambdaEventSourceMapping_MSK(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMsk(t) }, ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID, "kafka"), Providers: testAccProviders, CheckDestroy: testAccCheckLambdaEventSourceMappingDestroy, @@ -783,7 +783,12 @@ func TestAccAWSLambdaEventSourceMapping_ActiveMQ(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckAWSSecretsManager(t) + testAccPartitionHasServicePreCheck("mq", t) + testAccPreCheckAWSMq(t) + }, ErrorCheck: testAccErrorCheck(t, lambda.EndpointsID, "mq", "secretsmanager"), Providers: testAccProviders, CheckDestroy: testAccCheckLambdaEventSourceMappingDestroy, From 9bcfb5520175f3b3e0b9a91cca16f29821543a21 Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Fri, 7 Feb 2020 01:21:27 +0900 Subject: [PATCH 0122/1208] Add aws_amplify_branch resource --- aws/provider.go | 1 + aws/resource_aws_amplify_branch.go | 406 ++++++++++++++ aws/resource_aws_amplify_branch_test.go | 588 ++++++++++++++++++++ website/docs/r/amplify_branch.html.markdown | 126 +++++ 4 files changed, 1121 insertions(+) create mode 100644 aws/resource_aws_amplify_branch.go create mode 100644 aws/resource_aws_amplify_branch_test.go create mode 100644 website/docs/r/amplify_branch.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 8cdb9f540662..81e43f047767 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -455,6 +455,7 @@ func Provider() *schema.Provider { "aws_ami_launch_permission": resourceAwsAmiLaunchPermission(), "aws_amplify_app": resourceAwsAmplifyApp(), "aws_amplify_backend_environment": resourceAwsAmplifyBackendEnvironment(), + "aws_amplify_branch": resourceAwsAmplifyBranch(), "aws_api_gateway_account": resourceAwsApiGatewayAccount(), "aws_api_gateway_api_key": resourceAwsApiGatewayApiKey(), "aws_api_gateway_authorizer": resourceAwsApiGatewayAuthorizer(), diff --git a/aws/resource_aws_amplify_branch.go b/aws/resource_aws_amplify_branch.go new file mode 100644 index 000000000000..a56b71d33fa1 --- /dev/null +++ b/aws/resource_aws_amplify_branch.go @@ -0,0 +1,406 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func resourceAwsAmplifyBranch() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAmplifyBranchCreate, + Read: resourceAwsAmplifyBranchRead, + Update: resourceAwsAmplifyBranchUpdate, + Delete: resourceAwsAmplifyBranchDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "app_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "associated_resources": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "backend_environment_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + }, + "basic_auth_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable_basic_auth": { + Type: schema.TypeBool, + Optional: true, + }, + "password": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "username": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + }, + }, + }, + "branch_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 255), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9/_.-]+$`), "should only contain letters, numbers, and the symbols /_.-"), + ), + }, + "build_spec": { + Type: schema.TypeString, + Optional: true, + }, + "custom_domains": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "destination_branch": { + Type: schema.TypeString, + Computed: true, + }, + "display_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 255), + validation.StringMatch(regexp.MustCompile(`^[a-z0-9-]+$`), "should only contain lowercase alphabets, numbers, and -"), + ), + }, + "enable_auto_build": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "enable_notification": { + Type: schema.TypeBool, + Optional: true, + }, + "enable_pull_request_preview": { + Type: schema.TypeBool, + Optional: true, + }, + "environment_variables": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "framework": { + Type: schema.TypeString, + Optional: true, + }, + "pull_request_environment_name": { + Type: schema.TypeString, + Optional: true, + }, + "source_branch": { + Type: schema.TypeString, + Computed: true, + }, + "stage": { + Type: schema.TypeString, + Optional: true, + Default: "NONE", + ValidateFunc: validation.StringInSlice([]string{ + amplify.StageProduction, + amplify.StageBeta, + amplify.StageDevelopment, + amplify.StageExperimental, + amplify.StagePullRequest, + }, false), + }, + "ttl": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // ttl is set to "5" by default + if old == "5" && new == "" { + return true + } + return false + }, + }, + // non-API + "sns_topic_name": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), + }, + } +} + +func resourceAwsAmplifyBranchCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Print("[DEBUG] Creating Amplify Branch") + + params := &lify.CreateBranchInput{ + AppId: aws.String(d.Get("app_id").(string)), + BranchName: aws.String(d.Get("branch_name").(string)), + } + + if v, ok := d.GetOk("backend_environment_arn"); ok { + params.BackendEnvironmentArn = aws.String(v.(string)) + } + + if v, ok := d.GetOk("basic_auth_config"); ok { + enable, credentials := expandAmplifyBasicAuthConfig(v.([]interface{})) + params.EnableBasicAuth = enable + params.BasicAuthCredentials = credentials + } + + if v, ok := d.GetOk("build_spec"); ok { + params.BuildSpec = aws.String(v.(string)) + } + + if v, ok := d.GetOk("description"); ok { + params.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("display_name"); ok { + params.DisplayName = aws.String(v.(string)) + } + + // Note: don't use GetOk here because enable_auto_build can be false + if v := d.Get("enable_auto_build"); v != nil { + params.EnableAutoBuild = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("enable_notification"); ok { + params.EnableNotification = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("enable_pull_request_preview"); ok { + params.EnablePullRequestPreview = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("environment_variables"); ok { + params.EnvironmentVariables = stringMapToPointers(v.(map[string]interface{})) + } + + if v, ok := d.GetOk("framework"); ok { + params.Framework = aws.String(v.(string)) + } + + if v, ok := d.GetOk("pull_request_environment_name"); ok { + params.PullRequestEnvironmentName = aws.String(v.(string)) + } + + if v, ok := d.GetOk("stage"); ok { + params.Stage = aws.String(v.(string)) + } + + if v, ok := d.GetOk("ttl"); ok { + params.Ttl = aws.String(v.(string)) + } + + if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { + params.Tags = keyvaluetags.New(v).IgnoreAws().AmplifyTags() + } + + resp, err := conn.CreateBranch(params) + if err != nil { + return fmt.Errorf("Error creating Amplify Branch: %s", err) + } + + arn := *resp.Branch.BranchArn + d.SetId(arn[strings.Index(arn, ":apps/")+len(":apps/"):]) + + return resourceAwsAmplifyBranchRead(d, meta) +} + +func resourceAwsAmplifyBranchRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Reading Amplify Branch: %s", d.Id()) + + s := strings.Split(d.Id(), "/") + app_id := s[0] + branch_name := s[2] + + resp, err := conn.GetBranch(&lify.GetBranchInput{ + AppId: aws.String(app_id), + BranchName: aws.String(branch_name), + }) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == amplify.ErrCodeNotFoundException { + log.Printf("[WARN] Amplify Branch (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + return err + } + + d.Set("app_id", app_id) + d.Set("associated_resources", resp.Branch.AssociatedResources) + d.Set("backend_environment_arn", resp.Branch.BackendEnvironmentArn) + d.Set("arn", resp.Branch.BranchArn) + if err := d.Set("basic_auth_config", flattenAmplifyBasicAuthConfig(resp.Branch.EnableBasicAuth, resp.Branch.BasicAuthCredentials)); err != nil { + return fmt.Errorf("error setting basic_auth_config: %s", err) + } + d.Set("branch_name", resp.Branch.BranchName) + d.Set("build_spec", resp.Branch.BuildSpec) + d.Set("custom_domains", resp.Branch.CustomDomains) + d.Set("description", resp.Branch.Description) + d.Set("destination_branch", resp.Branch.DestinationBranch) + d.Set("display_name", resp.Branch.DisplayName) + d.Set("enable_auto_build", resp.Branch.EnableAutoBuild) + d.Set("enable_notification", resp.Branch.EnableNotification) + d.Set("enable_pull_request_preview", resp.Branch.EnablePullRequestPreview) + if err := d.Set("environment_variables", aws.StringValueMap(resp.Branch.EnvironmentVariables)); err != nil { + return fmt.Errorf("error setting environment_variables: %s", err) + } + d.Set("framework", resp.Branch.Framework) + d.Set("pull_request_environment_name", resp.Branch.PullRequestEnvironmentName) + d.Set("source_branch", resp.Branch.SourceBranch) + d.Set("stage", resp.Branch.Stage) + d.Set("ttl", resp.Branch.Ttl) + + // Generate SNS topic name for notification + d.Set("sns_topic_name", fmt.Sprintf("amplify-%s_%s", app_id, branch_name)) + + if err := d.Set("tags", keyvaluetags.AmplifyKeyValueTags(resp.Branch.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} + +func resourceAwsAmplifyBranchUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Updating Amplify Branch: %s", d.Id()) + + s := strings.Split(d.Id(), "/") + app_id := s[0] + branch_name := s[2] + + params := &lify.UpdateBranchInput{ + AppId: aws.String(app_id), + BranchName: aws.String(branch_name), + } + + if d.HasChange("backend_environment_arn") { + params.BackendEnvironmentArn = aws.String(d.Get("backend_environment_arn").(string)) + } + + if d.HasChange("basic_auth_config") { + enable, credentials := expandAmplifyBasicAuthConfig(d.Get("basic_auth_config").([]interface{})) + params.EnableBasicAuth = enable + params.BasicAuthCredentials = credentials + } + + if d.HasChange("build_spec") { + params.BuildSpec = aws.String(d.Get("build_spec").(string)) + } + + if d.HasChange("description") { + params.Description = aws.String(d.Get("description").(string)) + } + + if d.HasChange("display_name") { + params.DisplayName = aws.String(d.Get("display_name").(string)) + } + + if d.HasChange("enable_auto_build") { + params.EnableAutoBuild = aws.Bool(d.Get("enable_auto_build").(bool)) + } + + if d.HasChange("enable_notification") { + params.EnableNotification = aws.Bool(d.Get("enable_notification").(bool)) + } + + if d.HasChange("enable_pull_request_preview") { + params.EnablePullRequestPreview = aws.Bool(d.Get("enable_pull_request_preview").(bool)) + } + + if d.HasChange("environment_variables") { + v := d.Get("environment_variables").(map[string]interface{}) + params.EnvironmentVariables = expandAmplifyEnvironmentVariables(v) + } + + if d.HasChange("framework") { + params.Framework = aws.String(d.Get("framework").(string)) + } + + if d.HasChange("pull_request_environment_name") { + params.PullRequestEnvironmentName = aws.String(d.Get("pull_request_environment_name").(string)) + } + + if d.HasChange("stage") { + params.Stage = aws.String(d.Get("stage").(string)) + } + + if d.HasChange("ttl") { + params.Ttl = aws.String(d.Get("ttl").(string)) + } + + _, err := conn.UpdateBranch(params) + if err != nil { + return fmt.Errorf("Error updating Amplify Branch: %s", err) + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.AmplifyUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } + } + + return resourceAwsAmplifyBranchRead(d, meta) +} + +func resourceAwsAmplifyBranchDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Deleting Amplify Branch: %s", d.Id()) + + s := strings.Split(d.Id(), "/") + app_id := s[0] + branch_name := s[2] + + params := &lify.DeleteBranchInput{ + AppId: aws.String(app_id), + BranchName: aws.String(branch_name), + } + + _, err := conn.DeleteBranch(params) + if err != nil { + return fmt.Errorf("Error deleting Amplify Branch: %s", err) + } + + return nil +} diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go new file mode 100644 index 000000000000..3d0b57093701 --- /dev/null +++ b/aws/resource_aws_amplify_branch_test.go @@ -0,0 +1,588 @@ +package aws + +import ( + "errors" + "fmt" + "regexp" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +// Note: updating 'build_spec' does not work on AWS side +func TestAccAWSAmplifyBranch_basic(t *testing.T) { + var branch amplify.Branch + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + branchName := "master" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/branches/[^/]+$")), + resource.TestCheckResourceAttr(resourceName, "branch_name", branchName), + resource.TestCheckResourceAttr(resourceName, "build_spec", ""), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "display_name", branchName), + resource.TestCheckResourceAttr(resourceName, "enable_auto_build", "true"), + resource.TestCheckResourceAttr(resourceName, "enable_notification", "false"), + resource.TestCheckResourceAttr(resourceName, "enable_pull_request_preview", "false"), + resource.TestCheckResourceAttr(resourceName, "pull_request_environment_name", ""), + resource.TestCheckResourceAttr(resourceName, "framework", ""), + resource.TestCheckResourceAttr(resourceName, "stage", "NONE"), + resource.TestCheckResourceAttr(resourceName, "ttl", "5"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.#", "0"), + resource.TestCheckResourceAttr(resourceName, "associated_resources.#", "0"), + resource.TestCheckResourceAttr(resourceName, "custom_domains.#", "0"), + resource.TestCheckResourceAttr(resourceName, "destination_branch", ""), + resource.TestCheckResourceAttr(resourceName, "source_branch", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyBranchConfigSimple(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "description", "description"), + resource.TestCheckResourceAttr(resourceName, "display_name", "displayname"), + resource.TestCheckResourceAttr(resourceName, "enable_auto_build", "false"), + resource.TestCheckResourceAttr(resourceName, "framework", "WEB"), + resource.TestCheckResourceAttr(resourceName, "stage", "PRODUCTION"), + resource.TestCheckResourceAttr(resourceName, "ttl", "10"), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyBranch_rename(t *testing.T) { + var branch1, branch2 amplify.Branch + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + branchName1 := "master" + branchName2 := "development" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigBranch(rName, branchName1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch1), + resource.TestCheckResourceAttr(resourceName, "branch_name", branchName1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyBranchConfigBranch(rName, branchName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch2), + testAccCheckAWSAmplifyBranchRecreated(&branch1, &branch2), + resource.TestCheckResourceAttr(resourceName, "branch_name", branchName2), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyBranch_simple(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigSimple(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "description", "description"), + resource.TestCheckResourceAttr(resourceName, "display_name", "displayname"), + resource.TestCheckResourceAttr(resourceName, "enable_auto_build", "false"), + resource.TestCheckResourceAttr(resourceName, "framework", "WEB"), + resource.TestCheckResourceAttr(resourceName, "stage", "PRODUCTION"), + resource.TestCheckResourceAttr(resourceName, "ttl", "10"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAmplifyBranch_backendEnvironment(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigBackendEnvironment(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestMatchResourceAttr(resourceName, "backend_environment_arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/backendenvironments/prod")), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAmplifyBranch_pullRequestPreview(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigPullRequestPreview(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "enable_pull_request_preview", "true"), + resource.TestCheckResourceAttr(resourceName, "pull_request_environment_name", "prod"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAmplifyBranch_basicAuthConfig(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + username1 := "username1" + password1 := "password1" + username2 := "username2" + password2 := "password2" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigBasicAuthConfig(rName, username1, password1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.enable_basic_auth", "true"), + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.username", username1), + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.password", password1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyBranchConfigBasicAuthConfig(rName, username2, password2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.enable_basic_auth", "true"), + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.username", username2), + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.password", password2), + ), + }, + { + Config: testAccAWSAmplifyBranchConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "0"), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyBranch_notification(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigNotification(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "enable_notification", "true"), + resource.TestMatchResourceAttr(resourceName, "sns_topic_name", regexp.MustCompile("^amplify-[a-z0-9]+_master")), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAmplifyBranch_environmentVariables(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigEnvironmentVariables1(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "1"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyBranchConfigEnvironmentVariables2(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "2"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "2"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR2", "2"), + ), + }, + { + Config: testAccAWSAmplifyBranchConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), + ), + }, + }, + }) +} + +func TestAccAWSAmplifyBranch_tags(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigTags1(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.TAG1", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyBranchConfigTags2(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.TAG1", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.TAG2", "2"), + ), + }, + { + Config: testAccAWSAmplifyBranchConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + }, + }) +} + +func testAccCheckAWSAmplifyBranchExists(resourceName string, v *amplify.Branch) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + id := strings.Split(rs.Primary.ID, "/") + app_id := id[0] + branch := id[2] + + output, err := conn.GetBranch(&lify.GetBranchInput{ + AppId: aws.String(app_id), + BranchName: aws.String(branch), + }) + if err != nil { + return err + } + + if output == nil || output.Branch == nil { + return fmt.Errorf("Amplify Branch (%s) not found", rs.Primary.ID) + } + + *v = *output.Branch + + return nil + } +} + +func testAccCheckAWSAmplifyBranchDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_amplify_branch" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + id := strings.Split(rs.Primary.ID, "/") + app_id := id[0] + branch := id[2] + + _, err := conn.GetBranch(&lify.GetBranchInput{ + AppId: aws.String(app_id), + BranchName: aws.String(branch), + }) + + if isAWSErr(err, amplify.ErrCodeNotFoundException, "") { + continue + } + + if err != nil { + return err + } + } + + return nil +} + +func testAccCheckAWSAmplifyBranchRecreated(i, j *amplify.Branch) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.TimeValue(i.CreateTime) == aws.TimeValue(j.CreateTime) { + return errors.New("Amplify Branch was not recreated") + } + + return nil + } +} + +func testAccAWSAmplifyBranchConfig_Required(rName string) string { + return testAccAWSAmplifyBranchConfigBranch(rName, "master") +} + +func testAccAWSAmplifyBranchConfigBranch(rName string, branchName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "%s" +} +`, rName, branchName) +} + +func testAccAWSAmplifyBranchConfigSimple(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" + + description = "description" + display_name = "displayname" + enable_auto_build = false + framework = "WEB" + stage = "PRODUCTION" + ttl = "10" +} +`, rName) +} + +func testAccAWSAmplifyBranchConfigBackendEnvironment(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_backend_environment" "test" { + app_id = aws_amplify_app.test.id + environment_name = "prod" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" + + backend_environment_arn = aws_amplify_backend_environment.test.arn +} +`, rName) +} + +func testAccAWSAmplifyBranchConfigPullRequestPreview(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" + + enable_pull_request_preview = true + pull_request_environment_name = "prod" +} +`, rName) +} + +func testAccAWSAmplifyBranchConfigBasicAuthConfig(rName string, username, password string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" + + basic_auth_config { + enable_basic_auth = true + username = "%s" + password = "%s" + } +} +`, rName, username, password) +} + +func testAccAWSAmplifyBranchConfigNotification(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" + + enable_notification = true +} + +resource "aws_sns_topic" "test" { + name = aws_amplify_branch.test.sns_topic_name +} +`, rName) +} + +func testAccAWSAmplifyBranchConfigEnvironmentVariables1(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" + + environment_variables = { + ENVVAR1 = "1" + } +} +`, rName) +} + +func testAccAWSAmplifyBranchConfigEnvironmentVariables2(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" + + environment_variables = { + ENVVAR1 = "2", + ENVVAR2 = "2" + } +} +`, rName) +} + +func testAccAWSAmplifyBranchConfigTags1(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" + + tags = { + TAG1 = "1", + } +} +`, rName) +} + +func testAccAWSAmplifyBranchConfigTags2(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" + + tags = { + TAG1 = "2", + TAG2 = "2", + } +} +`, rName) +} diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown new file mode 100644 index 000000000000..c360c077efa8 --- /dev/null +++ b/website/docs/r/amplify_branch.html.markdown @@ -0,0 +1,126 @@ +--- +subcategory: "Amplify" +layout: "aws" +page_title: "AWS: aws_amplify_branch" +description: |- + Provides an Amplify branch resource. +--- + +# Resource: aws_amplify_branch + +Provides an Amplify branch resource. + +## Example Usage + +```hcl +resource "aws_amplify_app" "app" { + name = "app" +} + +resource "aws_amplify_branch" "master" { + app_id = aws_amplify_app.app.id + branch_name = "master" + + framework = "React" + stage = "PRODUCTION" + + environment_variables = { + REACT_APP_API_SERVER = "https://api.example.com" + } +} +``` + +### Basic Authentication + +```hcl +resource "aws_amplify_app" "app" { + name = "app" +} + +resource "aws_amplify_branch" "master" { + app_id = aws_amplify_app.app.id + branch_name = "master" + + basic_auth_config { + // Enable basic authentication. + enable_basic_auth = true + + username = "username" + password = "password" + } +} +``` + +### Notifications + +Amplify uses SNS for email notifications. In order to enable notifications, you have to set `enable_notification` in a `aws_amplify_branch` resource, as well as creating a SNS topic and subscriptions. Use `sns_topic_name` to get a SNS topic name. You can select any subscription protocol, such as `lambda`. + +```hcl +resource "aws_amplify_app" "app" { + name = "app" +} + +resource "aws_amplify_branch" "master" { + app_id = aws_amplify_app.app.id + branch_name = "master" + + // Enable SNS notifications. + enable_notification = true +} + +resource "aws_sns_topic" "amplify_app_master" { + name = aws_amplify_branch.master.sns_topic_name +} + +resource "aws_sns_topic_subscription" "amplify_app_master_lambda" { + topic_arn = aws_sns_topic.amplify_app_master.arn + protocol = "lambda" + endpoint = "arn:aws:lambda:..." +} +``` + +## Argument Reference + +The following arguments are supported: + +* `app_id` - (Required) Unique Id for an Amplify App. +* `branch_name` - (Required) Name for the branch. +* `backend_environment_arn` - (Optional) ARN for a Backend Environment, part of an Amplify App. +* `basic_auth_config` - (Optional) Basic Authentication config for the branch. A `basic_auth_config` block is documented below. +* `build_spec` - (Optional) BuildSpec for the branch. +* `description` - (Optional) Description for the branch. +* `display_name` - (Optional) Display name for a branch, will use as the default domain prefix. +* `enable_auto_build` - (Optional) Enables auto building for the branch. +* `enable_notifications` - (Optional) Enables notifications for the branch. +* `enable_pull_request_preview` - (Optional) Enables Pull Request Preview for this branch. +* `environment_variables` - (Optional) Environment Variables for the branch. +* `framework` - (Optional) Framework for the branch. +* `pull_request_environment_name` - (Optional) The Amplify Environment name for the pull request. +* `stage` - (Optional) Stage for the branch. Possible values: "PRODUCTION", "BETA", "DEVELOPMENT", "EXPERIMENTAL", or "PULL_REQUEST". +* `tags` - (Optional) Key-value mapping of resource tags. +* `ttl` - (Optional) The content TTL for the website in seconds. + +An `basic_auth_config` block supports the following arguments: + +* `enable_basic_auth` - (Optional) Enables Basic Authorization. +* `username` - (Optional) Basic Authorization username. +* `password` - (Optional) Basic Authorization password. + +## Attribute Reference + +The following attributes are exported: + +* `arn` - ARN for the Amplify App. +* `associated_resources` - List of custom resources that are linked to this branch. +* `custom_domains` - Custom domains for a branch, part of an Amplify App. +* `destination_branch` - The destination branch if the branch is a pull request branch. +* `sns_topic_name` - SNS topic name for notifications. +* `source_branch` - The source branch if the branch is a pull request branch. + +## Import + +Amplify branch can be imported using `app_id` and `branch_name`, e.g. + +``` +$ terraform import aws_amplify_branch.master d2ypk4k47z8u6/branches/master +``` From f78c2f53003e41c81149440fbab7abd33cc9e397 Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Fri, 14 Feb 2020 18:49:54 +0900 Subject: [PATCH 0123/1208] Ensure that the number of tags is 0 --- aws/resource_aws_amplify_branch_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index 3d0b57093701..8cff76d877b8 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -49,6 +49,7 @@ func TestAccAWSAmplifyBranch_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "custom_domains.#", "0"), resource.TestCheckResourceAttr(resourceName, "destination_branch", ""), resource.TestCheckResourceAttr(resourceName, "source_branch", ""), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { From 8dac21b3900b624c0628a15ff27b5e3928384bf8 Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Fri, 14 Feb 2020 20:23:01 +0900 Subject: [PATCH 0124/1208] Delete "sns_topic_name" attribute --- aws/resource_aws_amplify_branch.go | 8 -- aws/resource_aws_amplify_branch_test.go | 5 -- website/docs/r/amplify_branch.html.markdown | 84 +++++++++++++++++++-- 3 files changed, 77 insertions(+), 20 deletions(-) diff --git a/aws/resource_aws_amplify_branch.go b/aws/resource_aws_amplify_branch.go index a56b71d33fa1..a31dedcf1d40 100644 --- a/aws/resource_aws_amplify_branch.go +++ b/aws/resource_aws_amplify_branch.go @@ -156,11 +156,6 @@ func resourceAwsAmplifyBranch() *schema.Resource { return false }, }, - // non-API - "sns_topic_name": { - Type: schema.TypeString, - Computed: true, - }, "tags": tagsSchema(), }, } @@ -291,9 +286,6 @@ func resourceAwsAmplifyBranchRead(d *schema.ResourceData, meta interface{}) erro d.Set("stage", resp.Branch.Stage) d.Set("ttl", resp.Branch.Ttl) - // Generate SNS topic name for notification - d.Set("sns_topic_name", fmt.Sprintf("amplify-%s_%s", app_id, branch_name)) - if err := d.Set("tags", keyvaluetags.AmplifyKeyValueTags(resp.Branch.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index 8cff76d877b8..86b8ac6b29c5 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -247,7 +247,6 @@ func TestAccAWSAmplifyBranch_notification(t *testing.T) { Config: testAccAWSAmplifyBranchConfigNotification(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "enable_notification", "true"), - resource.TestMatchResourceAttr(resourceName, "sns_topic_name", regexp.MustCompile("^amplify-[a-z0-9]+_master")), ), }, { @@ -511,10 +510,6 @@ resource "aws_amplify_branch" "test" { enable_notification = true } - -resource "aws_sns_topic" "test" { - name = aws_amplify_branch.test.sns_topic_name -} `, rName) } diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown index c360c077efa8..5a7dcd18b3d4 100644 --- a/website/docs/r/amplify_branch.html.markdown +++ b/website/docs/r/amplify_branch.html.markdown @@ -53,7 +53,7 @@ resource "aws_amplify_branch" "master" { ### Notifications -Amplify uses SNS for email notifications. In order to enable notifications, you have to set `enable_notification` in a `aws_amplify_branch` resource, as well as creating a SNS topic and subscriptions. Use `sns_topic_name` to get a SNS topic name. You can select any subscription protocol, such as `lambda`. +Amplify Console uses CloudWatch Events and SNS for email notifications. To implement the same functionality, you need to set `enable_notification` in a `aws_amplify_branch` resource, as well as creating a CloudWatch Events Rule, a SNS topic, and SNS subscriptions. ```hcl resource "aws_amplify_app" "app" { @@ -68,14 +68,85 @@ resource "aws_amplify_branch" "master" { enable_notification = true } +// CloudWatch Events Rule for Amplify notifications + +resource "aws_cloudwatch_event_rule" "amplify_app_master" { + name = "amplify-${aws_amplify_app.app.id}-${aws_amplify_branch.master.branch_name}-branch-notification" + description = "AWS Amplify build notifications for : App: ${aws_amplify_app.app.id} Branch: ${aws_amplify_branch.master.branch_name}" + + event_pattern = jsonencode({ + "detail" = { + "appId" = [ + aws_amplify_app.app.id + ] + "branchName" = [ + aws_amplify_branch.master.branch_name + ], + "jobStatus" = [ + "SUCCEED", + "FAILED", + "STARTED" + ] + } + "detail-type" = [ + "Amplify Deployment Status Change" + ] + "source" = [ + "aws.amplify" + ] + }) +} + +resource "aws_cloudwatch_event_target" "amplify_app_master" { + rule = aws_cloudwatch_event_rule.amplify_app_master.name + target_id = aws_amplify_branch.master.branch_name + arn = aws_sns_topic.amplify_app_master.arn + + input_transformer { + input_paths = { + jobId = "$.detail.jobId" + appId = "$.detail.appId" + region = "$.region" + branch = "$.detail.branchName" + status = "$.detail.jobStatus" + } + + input_template = "\"Build notification from the AWS Amplify Console for app: https://..amplifyapp.com/. Your build status is . Go to https://console.aws.amazon.com/amplify/home?region=#// to view details on your build. \"" + } +} + +// SNS Topic for Amplify notifications + resource "aws_sns_topic" "amplify_app_master" { - name = aws_amplify_branch.master.sns_topic_name + name = "amplify-${aws_amplify_app.app.id}_${aws_amplify_branch.master.branch_name}" +} + +data "aws_iam_policy_document" "amplify_app_master" { + statement { + sid = "Allow_Publish_Events ${aws_amplify_branch.master.arn}" + + effect = "Allow" + + actions = [ + "SNS:Publish", + ] + + principals { + type = "Service" + identifiers = [ + "events.amazonaws.com", + ] + } + + resources = [ + aws_sns_topic.amplify_app_master.arn, + ] + } } -resource "aws_sns_topic_subscription" "amplify_app_master_lambda" { - topic_arn = aws_sns_topic.amplify_app_master.arn - protocol = "lambda" - endpoint = "arn:aws:lambda:..." +resource "aws_sns_topic_policy" "amplify_app_master" { + arn = aws_sns_topic.amplify_app_master.arn + policy = data.aws_iam_policy_document.amplify_app_master.json } ``` @@ -114,7 +185,6 @@ The following attributes are exported: * `associated_resources` - List of custom resources that are linked to this branch. * `custom_domains` - Custom domains for a branch, part of an Amplify App. * `destination_branch` - The destination branch if the branch is a pull request branch. -* `sns_topic_name` - SNS topic name for notifications. * `source_branch` - The source branch if the branch is a pull request branch. ## Import From 341bc95a05be5f6cec636566c8e756c003098b86 Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Sat, 15 Feb 2020 02:57:20 +0900 Subject: [PATCH 0125/1208] use "${}" in docs --- website/docs/r/amplify_branch.html.markdown | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown index 5a7dcd18b3d4..024444396d8f 100644 --- a/website/docs/r/amplify_branch.html.markdown +++ b/website/docs/r/amplify_branch.html.markdown @@ -18,7 +18,7 @@ resource "aws_amplify_app" "app" { } resource "aws_amplify_branch" "master" { - app_id = aws_amplify_app.app.id + app_id = "${aws_amplify_app.app.id}" branch_name = "master" framework = "React" @@ -38,7 +38,7 @@ resource "aws_amplify_app" "app" { } resource "aws_amplify_branch" "master" { - app_id = aws_amplify_app.app.id + app_id = "${aws_amplify_app.app.id}" branch_name = "master" basic_auth_config { @@ -61,7 +61,7 @@ resource "aws_amplify_app" "app" { } resource "aws_amplify_branch" "master" { - app_id = aws_amplify_app.app.id + app_id = "${aws_amplify_app.app.id}" branch_name = "master" // Enable SNS notifications. @@ -77,10 +77,10 @@ resource "aws_cloudwatch_event_rule" "amplify_app_master" { event_pattern = jsonencode({ "detail" = { "appId" = [ - aws_amplify_app.app.id + "${aws_amplify_app.app.id}" ] "branchName" = [ - aws_amplify_branch.master.branch_name + "${aws_amplify_branch.master.branch_name}" ], "jobStatus" = [ "SUCCEED", @@ -98,9 +98,9 @@ resource "aws_cloudwatch_event_rule" "amplify_app_master" { } resource "aws_cloudwatch_event_target" "amplify_app_master" { - rule = aws_cloudwatch_event_rule.amplify_app_master.name - target_id = aws_amplify_branch.master.branch_name - arn = aws_sns_topic.amplify_app_master.arn + rule = "${aws_cloudwatch_event_rule.amplify_app_master.name}" + target_id = "${aws_amplify_branch.master.branch_name}" + arn = "${aws_sns_topic.amplify_app_master.arn}" input_transformer { input_paths = { @@ -139,14 +139,14 @@ data "aws_iam_policy_document" "amplify_app_master" { } resources = [ - aws_sns_topic.amplify_app_master.arn, + "${aws_sns_topic.amplify_app_master.arn}", ] } } resource "aws_sns_topic_policy" "amplify_app_master" { - arn = aws_sns_topic.amplify_app_master.arn - policy = data.aws_iam_policy_document.amplify_app_master.json + arn = "${aws_sns_topic.amplify_app_master.arn}" + policy = "${data.aws_iam_policy_document.amplify_app_master.json}" } ``` From 55a32a8590d195138bca036f91fee109894284a5 Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Tue, 1 Jun 2021 17:30:48 +0000 Subject: [PATCH 0126/1208] v3.43.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db7fc3cddb9b..cdbc545e197f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 3.43.0 (Unreleased) +## 3.43.0 (June 01, 2021) FEATURES: From 16fe9e7d96217351ced36284054caf79590638bb Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Tue, 1 Jun 2021 13:33:21 -0400 Subject: [PATCH 0127/1208] add SetTagsDiff function to CustomizeDiff sequence --- aws/resource_aws_elasticache_cluster.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_elasticache_cluster.go b/aws/resource_aws_elasticache_cluster.go index df67db37d2e7..2988a3e12f56 100644 --- a/aws/resource_aws_elasticache_cluster.go +++ b/aws/resource_aws_elasticache_cluster.go @@ -268,6 +268,7 @@ func resourceAwsElasticacheCluster() *schema.Resource { CustomizeDiffValidateClusterNumCacheNodes, CustomizeDiffClusterMemcachedNodeType, CustomizeDiffValidateClusterMemcachedSnapshotIdentifier, + SetTagsDiff, ), } } From bddf3a9d0609d0f598ad373705fc96e587e2b89e Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 1 Jun 2021 17:38:04 +0000 Subject: [PATCH 0128/1208] Update CHANGELOG.md after v3.43.0 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdbc545e197f..e34b0513b8d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## 3.44.0 (Unreleased) ## 3.43.0 (June 01, 2021) FEATURES: From 3d54dbc820b711ea2128d0c7ee74a866ec389b2f Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Tue, 1 Jun 2021 13:39:17 -0400 Subject: [PATCH 0129/1208] Update CHANGELOG for #19615 --- .changelog/19615.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19615.txt diff --git a/.changelog/19615.txt b/.changelog/19615.txt new file mode 100644 index 000000000000..109278c53372 --- /dev/null +++ b/.changelog/19615.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_elasticache_cluster: Fix provider-level `default_tags` support for resource +``` From 87c15df2382278c0c7b1af5dd346fd5be83ad4bf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 14:22:21 -0400 Subject: [PATCH 0130/1208] r/aws_amplify_branch: Build with Plugin SDK v2. --- aws/resource_aws_amplify_branch.go | 63 ++++++---------- aws/resource_aws_amplify_branch_test.go | 6 +- website/docs/r/amplify_branch.html.markdown | 84 ++++++++++----------- 3 files changed, 64 insertions(+), 89 deletions(-) diff --git a/aws/resource_aws_amplify_branch.go b/aws/resource_aws_amplify_branch.go index a31dedcf1d40..33afdc2ff901 100644 --- a/aws/resource_aws_amplify_branch.go +++ b/aws/resource_aws_amplify_branch.go @@ -9,8 +9,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/amplify" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "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" ) @@ -44,30 +44,14 @@ func resourceAwsAmplifyBranch() *schema.Resource { Optional: true, ValidateFunc: validateArn, }, - "basic_auth_config": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enable_basic_auth": { - Type: schema.TypeBool, - Optional: true, - }, - "password": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - "username": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, - }, + + "basic_auth_credentials": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.StringLenBetween(1, 2000), }, + "branch_name": { Type: schema.TypeString, Required: true, @@ -174,10 +158,8 @@ func resourceAwsAmplifyBranchCreate(d *schema.ResourceData, meta interface{}) er params.BackendEnvironmentArn = aws.String(v.(string)) } - if v, ok := d.GetOk("basic_auth_config"); ok { - enable, credentials := expandAmplifyBasicAuthConfig(v.([]interface{})) - params.EnableBasicAuth = enable - params.BasicAuthCredentials = credentials + if v, ok := d.GetOk("basic_auth_credentials"); ok { + params.BasicAuthCredentials = aws.String(v.(string)) } if v, ok := d.GetOk("build_spec"); ok { @@ -205,8 +187,8 @@ func resourceAwsAmplifyBranchCreate(d *schema.ResourceData, meta interface{}) er params.EnablePullRequestPreview = aws.Bool(v.(bool)) } - if v, ok := d.GetOk("environment_variables"); ok { - params.EnvironmentVariables = stringMapToPointers(v.(map[string]interface{})) + if v, ok := d.GetOk("environment_variables"); ok && len(v.(map[string]interface{})) > 0 { + params.EnvironmentVariables = expandStringMap(v.(map[string]interface{})) } if v, ok := d.GetOk("framework"); ok { @@ -265,9 +247,7 @@ func resourceAwsAmplifyBranchRead(d *schema.ResourceData, meta interface{}) erro d.Set("associated_resources", resp.Branch.AssociatedResources) d.Set("backend_environment_arn", resp.Branch.BackendEnvironmentArn) d.Set("arn", resp.Branch.BranchArn) - if err := d.Set("basic_auth_config", flattenAmplifyBasicAuthConfig(resp.Branch.EnableBasicAuth, resp.Branch.BasicAuthCredentials)); err != nil { - return fmt.Errorf("error setting basic_auth_config: %s", err) - } + d.Set("basic_auth_credentials", resp.Branch.EnableBasicAuth) d.Set("branch_name", resp.Branch.BranchName) d.Set("build_spec", resp.Branch.BuildSpec) d.Set("custom_domains", resp.Branch.CustomDomains) @@ -277,9 +257,7 @@ func resourceAwsAmplifyBranchRead(d *schema.ResourceData, meta interface{}) erro d.Set("enable_auto_build", resp.Branch.EnableAutoBuild) d.Set("enable_notification", resp.Branch.EnableNotification) d.Set("enable_pull_request_preview", resp.Branch.EnablePullRequestPreview) - if err := d.Set("environment_variables", aws.StringValueMap(resp.Branch.EnvironmentVariables)); err != nil { - return fmt.Errorf("error setting environment_variables: %s", err) - } + d.Set("environment_variables", aws.StringValueMap(resp.Branch.EnvironmentVariables)) d.Set("framework", resp.Branch.Framework) d.Set("pull_request_environment_name", resp.Branch.PullRequestEnvironmentName) d.Set("source_branch", resp.Branch.SourceBranch) @@ -311,9 +289,7 @@ func resourceAwsAmplifyBranchUpdate(d *schema.ResourceData, meta interface{}) er } if d.HasChange("basic_auth_config") { - enable, credentials := expandAmplifyBasicAuthConfig(d.Get("basic_auth_config").([]interface{})) - params.EnableBasicAuth = enable - params.BasicAuthCredentials = credentials + params.BasicAuthCredentials = aws.String(d.Get("basic_auth_credentials").(string)) } if d.HasChange("build_spec") { @@ -341,8 +317,11 @@ func resourceAwsAmplifyBranchUpdate(d *schema.ResourceData, meta interface{}) er } if d.HasChange("environment_variables") { - v := d.Get("environment_variables").(map[string]interface{}) - params.EnvironmentVariables = expandAmplifyEnvironmentVariables(v) + if v := d.Get("environment_variables").(map[string]interface{}); len(v) > 0 { + params.EnvironmentVariables = expandStringMap(v) + } else { + params.EnvironmentVariables = aws.StringMap(map[string]string{"": ""}) + } } if d.HasChange("framework") { diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index 86b8ac6b29c5..ad7be99a5fcb 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -9,9 +9,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "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" ) // Note: updating 'build_spec' does not work on AWS side diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown index 024444396d8f..58804a136551 100644 --- a/website/docs/r/amplify_branch.html.markdown +++ b/website/docs/r/amplify_branch.html.markdown @@ -1,24 +1,24 @@ --- -subcategory: "Amplify" +subcategory: "Amplify Console" layout: "aws" page_title: "AWS: aws_amplify_branch" description: |- - Provides an Amplify branch resource. + Provides an Amplify Branch resource. --- # Resource: aws_amplify_branch -Provides an Amplify branch resource. +Provides an Amplify Branch resource. ## Example Usage -```hcl -resource "aws_amplify_app" "app" { +```terraform +resource "aws_amplify_app" "example" { name = "app" } resource "aws_amplify_branch" "master" { - app_id = "${aws_amplify_app.app.id}" + app_id = aws_amplify_app.example.id branch_name = "master" framework = "React" @@ -32,13 +32,13 @@ resource "aws_amplify_branch" "master" { ### Basic Authentication -```hcl -resource "aws_amplify_app" "app" { +```terraform +resource "aws_amplify_app" "example" { name = "app" } resource "aws_amplify_branch" "master" { - app_id = "${aws_amplify_app.app.id}" + app_id = aws_amplify_app.example.id branch_name = "master" basic_auth_config { @@ -55,13 +55,13 @@ resource "aws_amplify_branch" "master" { Amplify Console uses CloudWatch Events and SNS for email notifications. To implement the same functionality, you need to set `enable_notification` in a `aws_amplify_branch` resource, as well as creating a CloudWatch Events Rule, a SNS topic, and SNS subscriptions. -```hcl -resource "aws_amplify_app" "app" { +```terraform +resource "aws_amplify_app" "example" { name = "app" } resource "aws_amplify_branch" "master" { - app_id = "${aws_amplify_app.app.id}" + app_id = aws_amplify_app.example.id branch_name = "master" // Enable SNS notifications. @@ -77,10 +77,10 @@ resource "aws_cloudwatch_event_rule" "amplify_app_master" { event_pattern = jsonencode({ "detail" = { "appId" = [ - "${aws_amplify_app.app.id}" + aws_amplify_app.example.id ] "branchName" = [ - "${aws_amplify_branch.master.branch_name}" + aws_amplify_branch.master.branch_name ], "jobStatus" = [ "SUCCEED", @@ -98,9 +98,9 @@ resource "aws_cloudwatch_event_rule" "amplify_app_master" { } resource "aws_cloudwatch_event_target" "amplify_app_master" { - rule = "${aws_cloudwatch_event_rule.amplify_app_master.name}" - target_id = "${aws_amplify_branch.master.branch_name}" - arn = "${aws_sns_topic.amplify_app_master.arn}" + rule = aws_cloudwatch_event_rule.amplify_app_master.name + target_id = aws_amplify_branch.master.branch_name + arn = aws_sns_topic.amplify_app_master.arn input_transformer { input_paths = { @@ -139,14 +139,14 @@ data "aws_iam_policy_document" "amplify_app_master" { } resources = [ - "${aws_sns_topic.amplify_app_master.arn}", + aws_sns_topic.amplify_app_master.arn, ] } } resource "aws_sns_topic_policy" "amplify_app_master" { - arn = "${aws_sns_topic.amplify_app_master.arn}" - policy = "${data.aws_iam_policy_document.amplify_app_master.json}" + arn = aws_sns_topic.amplify_app_master.arn + policy = data.aws_iam_policy_document.amplify_app_master.json } ``` @@ -154,43 +154,39 @@ resource "aws_sns_topic_policy" "amplify_app_master" { The following arguments are supported: -* `app_id` - (Required) Unique Id for an Amplify App. -* `branch_name` - (Required) Name for the branch. -* `backend_environment_arn` - (Optional) ARN for a Backend Environment, part of an Amplify App. -* `basic_auth_config` - (Optional) Basic Authentication config for the branch. A `basic_auth_config` block is documented below. -* `build_spec` - (Optional) BuildSpec for the branch. -* `description` - (Optional) Description for the branch. -* `display_name` - (Optional) Display name for a branch, will use as the default domain prefix. +* `app_id` - (Required) The unique ID for an Amplify app. +* `branch_name` - (Required) The name for the branch. +* `backend_environment_arn` - (Optional) The Amazon Resource Name (ARN) for a backend environment that is part of an Amplify app. +* `basic_auth_credentials` - (Optional) The basic authorization credentials for the branch. +* `build_spec` - (Optional) The build specification (build spec) for the branch. +* `description` - (Optional) The description for the branch. +* `display_name` - (Optional) The display name for a branch. This is used as the default domain prefix. * `enable_auto_build` - (Optional) Enables auto building for the branch. * `enable_notifications` - (Optional) Enables notifications for the branch. -* `enable_pull_request_preview` - (Optional) Enables Pull Request Preview for this branch. -* `environment_variables` - (Optional) Environment Variables for the branch. -* `framework` - (Optional) Framework for the branch. -* `pull_request_environment_name` - (Optional) The Amplify Environment name for the pull request. -* `stage` - (Optional) Stage for the branch. Possible values: "PRODUCTION", "BETA", "DEVELOPMENT", "EXPERIMENTAL", or "PULL_REQUEST". -* `tags` - (Optional) Key-value mapping of resource tags. -* `ttl` - (Optional) The content TTL for the website in seconds. - -An `basic_auth_config` block supports the following arguments: - -* `enable_basic_auth` - (Optional) Enables Basic Authorization. -* `username` - (Optional) Basic Authorization username. -* `password` - (Optional) Basic Authorization password. +* `enable_performance_mode` - (Optional) Enables performance mode for the branch. +* `enable_pull_request_preview` - (Optional) Enables pull request previews for this branch. +* `environment_variables` - (Optional) The environment variables for the branch. +* `framework` - (Optional) The framework for the branch. +* `pull_request_environment_name` - (Optional) The Amplify environment name for the pull request. +* `stage` - (Optional) Describes the current stage for the branch. Valid values: `PRODUCTION`, `BETA`, `DEVELOPMENT`, `EXPERIMENTAL`, `PULL_REQUEST`. +* `tags` - (Optional) Key-value mapping of resource tags. 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. +* `ttl` - (Optional) The content Time To Live (TTL) for the website in seconds. ## Attribute Reference The following attributes are exported: -* `arn` - ARN for the Amplify App. -* `associated_resources` - List of custom resources that are linked to this branch. -* `custom_domains` - Custom domains for a branch, part of an Amplify App. +* `arn` - The Amazon Resource Name (ARN) for the branch. +* `associated_resources` - A list of custom resources that are linked to this branch. +* `custom_domains` - The custom domains for a branch of an Amplify app. * `destination_branch` - The destination branch if the branch is a pull request branch. * `source_branch` - The source branch if the branch is a pull request branch. +* `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 Amplify branch can be imported using `app_id` and `branch_name`, e.g. ``` -$ terraform import aws_amplify_branch.master d2ypk4k47z8u6/branches/master +$ terraform import aws_amplify_branch.master d2ypk4k47z8u6/master ``` From a74828545b15ca5bdf113f7b8d6f3f5c03985206 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 18:25:47 +0000 Subject: [PATCH 0131/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.49 to 1.38.52 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.49 to 1.38.52. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.49...v1.38.52) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7887c5bc242e..d7de330e30a0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.49 + github.com/aws/aws-sdk-go v1.38.52 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index a842351ceedd..14d7c8704aa0 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.49 h1:E31vxjCe6a5I+mJLmUGaZobiWmg9KdWaud9IfceYeYQ= -github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.52 h1:7NKcUyTG/CyDX835kq04DDNe8vXaJhbGW8ThemHb18A= +github.com/aws/aws-sdk-go v1.38.52/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 7b0cc310b748ebbde53f9fe728e34434816b2f48 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 18:25:58 +0000 Subject: [PATCH 0132/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.49 to 1.38.52. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.49...v1.38.52) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 +- .../aws/aws-sdk-go/aws/endpoints/defaults.go | 129 +++++++++++++++++- .../aws/aws-sdk-go/aws/request/request.go | 17 ++- .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 6 files changed, 144 insertions(+), 12 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 57f3bc183d4e..cf9da5e68909 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.49 + github.com/aws/aws-sdk-go v1.38.52 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index defb3271b978..210cb5bdbce9 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.49 h1:E31vxjCe6a5I+mJLmUGaZobiWmg9KdWaud9IfceYeYQ= -github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.52 h1:7NKcUyTG/CyDX835kq04DDNe8vXaJhbGW8ThemHb18A= +github.com/aws/aws-sdk-go v1.38.52/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index 2de69cc5bc85..9d1266d5d4c9 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -3187,9 +3187,27 @@ var awsPartition = partition{ "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, + "fips-us-east-1": endpoint{ + Hostname: "forecast-fips.us-east-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-1", + }, + }, + "fips-us-east-2": endpoint{ + Hostname: "forecast-fips.us-east-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-2", + }, + }, + "fips-us-west-2": endpoint{ + Hostname: "forecast-fips.us-west-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-west-2", + }, + }, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-2": endpoint{}, }, }, "forecastquery": service{ @@ -3202,9 +3220,27 @@ var awsPartition = partition{ "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, + "fips-us-east-1": endpoint{ + Hostname: "forecastquery-fips.us-east-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-1", + }, + }, + "fips-us-east-2": endpoint{ + Hostname: "forecastquery-fips.us-east-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-2", + }, + }, + "fips-us-west-2": endpoint{ + Hostname: "forecastquery-fips.us-west-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-west-2", + }, + }, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-2": endpoint{}, }, }, "fsx": service{ @@ -5071,6 +5107,7 @@ var awsPartition = partition{ "ap-northeast-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, + "ca-central-1": endpoint{}, "eu-central-1": endpoint{}, "eu-west-2": endpoint{}, "us-east-1": endpoint{}, @@ -6137,6 +6174,61 @@ var awsPartition = partition{ }, }, }, + "servicecatalog-appregistry": service{ + + Endpoints: endpoints{ + "af-south-1": endpoint{}, + "ap-east-1": endpoint{}, + "ap-northeast-1": endpoint{}, + "ap-northeast-2": endpoint{}, + "ap-south-1": endpoint{}, + "ap-southeast-1": endpoint{}, + "ap-southeast-2": endpoint{}, + "ca-central-1": endpoint{}, + "eu-central-1": endpoint{}, + "eu-north-1": endpoint{}, + "eu-south-1": endpoint{}, + "eu-west-1": endpoint{}, + "eu-west-2": endpoint{}, + "eu-west-3": endpoint{}, + "fips-ca-central-1": endpoint{ + Hostname: "servicecatalog-appregistry-fips.ca-central-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "ca-central-1", + }, + }, + "fips-us-east-1": endpoint{ + Hostname: "servicecatalog-appregistry-fips.us-east-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-1", + }, + }, + "fips-us-east-2": endpoint{ + Hostname: "servicecatalog-appregistry-fips.us-east-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-2", + }, + }, + "fips-us-west-1": endpoint{ + Hostname: "servicecatalog-appregistry-fips.us-west-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-west-1", + }, + }, + "fips-us-west-2": endpoint{ + Hostname: "servicecatalog-appregistry-fips.us-west-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-west-2", + }, + }, + "me-south-1": endpoint{}, + "sa-east-1": endpoint{}, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-1": endpoint{}, + "us-west-2": endpoint{}, + }, + }, "servicediscovery": service{ Endpoints: endpoints{ @@ -9862,6 +9954,25 @@ var awsusgovPartition = partition{ }, }, }, + "servicecatalog-appregistry": service{ + + Endpoints: endpoints{ + "fips-us-gov-east-1": endpoint{ + Hostname: "servicecatalog-appregistry.us-gov-east-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-gov-east-1", + }, + }, + "fips-us-gov-west-1": endpoint{ + Hostname: "servicecatalog-appregistry.us-gov-west-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-gov-west-1", + }, + }, + "us-gov-east-1": endpoint{}, + "us-gov-west-1": endpoint{}, + }, + }, "servicequotas": service{ Defaults: endpoint{ Protocols: []string{"https"}, @@ -10501,6 +10612,12 @@ var awsisoPartition = partition{ "us-iso-east-1": endpoint{}, }, }, + "ram": service{ + + Endpoints: endpoints{ + "us-iso-east-1": endpoint{}, + }, + }, "rds": service{ Endpoints: endpoints{ diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/request/request.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/request/request.go index d597c6ead555..fb0a68fce3ed 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/request/request.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/request/request.go @@ -129,12 +129,27 @@ func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers, httpReq, _ := http.NewRequest(method, "", nil) var err error - httpReq.URL, err = url.Parse(clientInfo.Endpoint + operation.HTTPPath) + httpReq.URL, err = url.Parse(clientInfo.Endpoint) if err != nil { httpReq.URL = &url.URL{} err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err) } + if len(operation.HTTPPath) != 0 { + opHTTPPath := operation.HTTPPath + var opQueryString string + if idx := strings.Index(opHTTPPath, "?"); idx >= 0 { + opQueryString = opHTTPPath[idx+1:] + opHTTPPath = opHTTPPath[:idx] + } + + if strings.HasSuffix(httpReq.URL.Path, "/") && strings.HasPrefix(opHTTPPath, "/") { + opHTTPPath = opHTTPPath[1:] + } + httpReq.URL.Path += opHTTPPath + httpReq.URL.RawQuery = opQueryString + } + r := &Request{ Config: cfg, ClientInfo: clientInfo, diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index e0d4f2a86654..fb58b46640af 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.49" +const SDKVersion = "1.38.52" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 7b7c9f56fe2b..53f729f07fcc 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.49 +# github.com/aws/aws-sdk-go v1.38.52 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From d378a18f9ca4766050e413f0139814f5e8780a74 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 14:30:34 -0400 Subject: [PATCH 0133/1208] Add missing v3.43.0 entries. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e34b0513b8d4..bc497f3a719b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ## 3.44.0 (Unreleased) + ## 3.43.0 (June 01, 2021) FEATURES: @@ -24,6 +25,10 @@ ENHANCEMENTS: * resource/aws_ecs_service: Add support for ECS Anywhere with the `launch_type` `EXTERNAL` ([#19557](https://github.com/hashicorp/terraform-provider-aws/issues/19557)) * resource/aws_eks_node_group: Add `taint` argument ([#19482](https://github.com/hashicorp/terraform-provider-aws/issues/19482)) * resource/aws_elasticache_parameter_group: Add `tags` argument and `arn` and `tags_all` attributes ([#19551](https://github.com/hashicorp/terraform-provider-aws/issues/19551)) +* resource/aws_lambda_event_source_mapping: Add `function_response_types` argument to support AWS Lambda checkpointing ([#19425](https://github.com/hashicorp/terraform-provider-aws/issues/19425)) +* resource/aws_lambda_event_source_mapping: Add `queues` argument to support Amazon MQ for Apache ActiveMQ event sources ([#19425](https://github.com/hashicorp/terraform-provider-aws/issues/19425)) +* resource/aws_lambda_event_source_mapping: Add `self_managed_event_source` and `source_access_configuration` arguments to support self-managed Apache Kafka event sources ([#19425](https://github.com/hashicorp/terraform-provider-aws/issues/19425)) +* resource/aws_lambda_event_source_mapping: Add `tumbling_window_in_seconds` argument to support AWS Lambda streaming analytics calculations ([#19425](https://github.com/hashicorp/terraform-provider-aws/issues/19425)) * resource/aws_msk_cluster: Add `bootstrap_brokers_sasl_iam` attribute ([#19404](https://github.com/hashicorp/terraform-provider-aws/issues/19404)) * resource/aws_msk_cluster: Add `iam` argument to `client_authentication.sasl` configuration block ([#19404](https://github.com/hashicorp/terraform-provider-aws/issues/19404)) * resource/aws_msk_configuration: `kafka_versions` argument is optional ([#17571](https://github.com/hashicorp/terraform-provider-aws/issues/17571)) From 3585e7b1279f14920d4ea6786e526937787fa39d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 16:03:45 -0400 Subject: [PATCH 0134/1208] r/aws_amplify_branch: Simple tests working. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplifyBranch_basic\|TestAccAWSAmplifyBranch_disappears\|TestAccAWSAmplifyBranch_Tags' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplifyBranch_basic\|TestAccAWSAmplifyBranch_disappears\|TestAccAWSAmplifyBranch_Tags -timeout 180m === RUN TestAccAWSAmplifyBranch_basic === PAUSE TestAccAWSAmplifyBranch_basic === RUN TestAccAWSAmplifyBranch_disappears === PAUSE TestAccAWSAmplifyBranch_disappears === RUN TestAccAWSAmplifyBranch_Tags === PAUSE TestAccAWSAmplifyBranch_Tags === CONT TestAccAWSAmplifyBranch_basic === CONT TestAccAWSAmplifyBranch_Tags === CONT TestAccAWSAmplifyBranch_disappears --- PASS: TestAccAWSAmplifyBranch_disappears (13.52s) --- PASS: TestAccAWSAmplifyBranch_basic (15.00s) --- PASS: TestAccAWSAmplifyBranch_Tags (30.45s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 33.761s --- aws/internal/service/amplify/finder/finder.go | 29 ++ aws/internal/service/amplify/id.go | 19 + ...ce_aws_amplify_backend_environment_test.go | 2 +- aws/resource_aws_amplify_branch.go | 402 ++++++++++-------- aws/resource_aws_amplify_branch_test.go | 236 +++++----- website/docs/r/amplify_branch.html.markdown | 3 +- 6 files changed, 399 insertions(+), 292 deletions(-) diff --git a/aws/internal/service/amplify/finder/finder.go b/aws/internal/service/amplify/finder/finder.go index 46c91eac8872..7074fabb4c26 100644 --- a/aws/internal/service/amplify/finder/finder.go +++ b/aws/internal/service/amplify/finder/finder.go @@ -63,3 +63,32 @@ func BackendEnvironmentByAppIDAndEnvironmentName(conn *amplify.Amplify, appID, e return output.BackendEnvironment, nil } + +func BranchByAppIDAndBranchName(conn *amplify.Amplify, appID, branchName string) (*amplify.Branch, error) { + input := &lify.GetBranchInput{ + AppId: aws.String(appID), + BranchName: aws.String(branchName), + } + + output, err := conn.GetBranch(input) + + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Branch == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.Branch, nil +} diff --git a/aws/internal/service/amplify/id.go b/aws/internal/service/amplify/id.go index a6c3210b0f25..0306a36111d1 100644 --- a/aws/internal/service/amplify/id.go +++ b/aws/internal/service/amplify/id.go @@ -23,3 +23,22 @@ func BackendEnvironmentParseResourceID(id string) (string, string, error) { return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected APPID%[2]sENVIRONMENTNAME", id, backendEnvironmentResourceIDSeparator) } + +const branchResourceIDSeparator = "/" + +func BranchCreateResourceID(appID, branchName string) string { + parts := []string{appID, branchName} + id := strings.Join(parts, branchResourceIDSeparator) + + return id +} + +func BranchParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, branchResourceIDSeparator) + + if len(parts) == 2 && parts[0] != "" && parts[1] != "" { + return parts[0], parts[1], nil + } + + return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected APPID%[2]sBRANCHNAME", id, branchResourceIDSeparator) +} diff --git a/aws/resource_aws_amplify_backend_environment_test.go b/aws/resource_aws_amplify_backend_environment_test.go index 8d3b590463ba..0faf353cb9f3 100644 --- a/aws/resource_aws_amplify_backend_environment_test.go +++ b/aws/resource_aws_amplify_backend_environment_test.go @@ -160,7 +160,7 @@ func testAccCheckAWSAmplifyBackendEnvironmentDestroy(s *terraform.State) error { return err } - return fmt.Errorf("Amplify BackendEnvironment %s still exists", rs.Primary.ID) + return fmt.Errorf("Amplify Backend Environment %s still exists", rs.Primary.ID) } return nil diff --git a/aws/resource_aws_amplify_branch.go b/aws/resource_aws_amplify_branch.go index 33afdc2ff901..9fd82bd106ad 100644 --- a/aws/resource_aws_amplify_branch.go +++ b/aws/resource_aws_amplify_branch.go @@ -4,14 +4,16 @@ import ( "fmt" "log" "regexp" - "strings" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/amplify" + "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" + tfamplify "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsAmplifyBranch() *schema.Resource { @@ -24,21 +26,26 @@ func resourceAwsAmplifyBranch() *schema.Resource { State: schema.ImportStatePassthrough, }, + CustomizeDiff: SetTagsDiff, + Schema: map[string]*schema.Schema{ - "arn": { - Type: schema.TypeString, - Computed: true, - }, "app_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, + + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "associated_resources": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "backend_environment_arn": { Type: schema.TypeString, Optional: true, @@ -53,219 +60,265 @@ func resourceAwsAmplifyBranch() *schema.Resource { }, "branch_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 255), - validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9/_.-]+$`), "should only contain letters, numbers, and the symbols /_.-"), - ), + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[0-9A-Za-z/_.-]{1,255}$`), "should be not be more than 255 letters, numbers, and the symbols /_.-"), }, + "build_spec": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 25000), }, + "custom_domains": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "description": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1000), }, + "destination_branch": { Type: schema.TypeString, Computed: true, }, + "display_name": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 255), - validation.StringMatch(regexp.MustCompile(`^[a-z0-9-]+$`), "should only contain lowercase alphabets, numbers, and -"), - ), + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[0-9a-z-]{1,255}$`), "should be not be more than 255 lowercase alphanumeric or hyphen characters"), }, + "enable_auto_build": { Type: schema.TypeBool, Optional: true, Default: true, }, + + "enable_basic_auth": { + Type: schema.TypeBool, + Optional: true, + }, + "enable_notification": { Type: schema.TypeBool, Optional: true, }, + + "enable_performance_mode": { + Type: schema.TypeBool, + Optional: true, + }, + "enable_pull_request_preview": { Type: schema.TypeBool, Optional: true, }, + "environment_variables": { Type: schema.TypeMap, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "framework": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, + "pull_request_environment_name": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 20), }, + "source_branch": { Type: schema.TypeString, Computed: true, }, + "stage": { - Type: schema.TypeString, - Optional: true, - Default: "NONE", - ValidateFunc: validation.StringInSlice([]string{ - amplify.StageProduction, - amplify.StageBeta, - amplify.StageDevelopment, - amplify.StageExperimental, - amplify.StagePullRequest, - }, false), + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(amplify.Stage_Values(), false), + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // API returns "NONE" by default. + if old == tfamplify.StageNone && new == "" { + return true + } + + return old == new + }, }, + "ttl": { Type: schema.TypeString, Optional: true, DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - // ttl is set to "5" by default + // API returns "5" by default. if old == "5" && new == "" { return true } - return false + + return old == new }, }, - "tags": tagsSchema(), + + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, } } func resourceAwsAmplifyBranchCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Print("[DEBUG] Creating Amplify Branch") + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) + + appID := d.Get("app_id").(string) + branchName := d.Get("branch_name").(string) + id := tfamplify.BranchCreateResourceID(appID, branchName) - params := &lify.CreateBranchInput{ - AppId: aws.String(d.Get("app_id").(string)), - BranchName: aws.String(d.Get("branch_name").(string)), + input := &lify.CreateBranchInput{ + AppId: aws.String(appID), + BranchName: aws.String(branchName), + EnableAutoBuild: aws.Bool(d.Get("enable_auto_build").(bool)), } if v, ok := d.GetOk("backend_environment_arn"); ok { - params.BackendEnvironmentArn = aws.String(v.(string)) + input.BackendEnvironmentArn = aws.String(v.(string)) } if v, ok := d.GetOk("basic_auth_credentials"); ok { - params.BasicAuthCredentials = aws.String(v.(string)) + input.BasicAuthCredentials = aws.String(v.(string)) } if v, ok := d.GetOk("build_spec"); ok { - params.BuildSpec = aws.String(v.(string)) + input.BuildSpec = aws.String(v.(string)) } if v, ok := d.GetOk("description"); ok { - params.Description = aws.String(v.(string)) + input.Description = aws.String(v.(string)) } if v, ok := d.GetOk("display_name"); ok { - params.DisplayName = aws.String(v.(string)) + input.DisplayName = aws.String(v.(string)) } - // Note: don't use GetOk here because enable_auto_build can be false - if v := d.Get("enable_auto_build"); v != nil { - params.EnableAutoBuild = aws.Bool(v.(bool)) + if v, ok := d.GetOk("enable_basic_auth"); ok { + input.EnableBasicAuth = aws.Bool(v.(bool)) } if v, ok := d.GetOk("enable_notification"); ok { - params.EnableNotification = aws.Bool(v.(bool)) + input.EnableNotification = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("enable_performance_mode"); ok { + input.EnablePerformanceMode = aws.Bool(v.(bool)) } if v, ok := d.GetOk("enable_pull_request_preview"); ok { - params.EnablePullRequestPreview = aws.Bool(v.(bool)) + input.EnablePullRequestPreview = aws.Bool(v.(bool)) } if v, ok := d.GetOk("environment_variables"); ok && len(v.(map[string]interface{})) > 0 { - params.EnvironmentVariables = expandStringMap(v.(map[string]interface{})) + input.EnvironmentVariables = expandStringMap(v.(map[string]interface{})) } if v, ok := d.GetOk("framework"); ok { - params.Framework = aws.String(v.(string)) + input.Framework = aws.String(v.(string)) } if v, ok := d.GetOk("pull_request_environment_name"); ok { - params.PullRequestEnvironmentName = aws.String(v.(string)) + input.PullRequestEnvironmentName = aws.String(v.(string)) } if v, ok := d.GetOk("stage"); ok { - params.Stage = aws.String(v.(string)) + input.Stage = aws.String(v.(string)) } if v, ok := d.GetOk("ttl"); ok { - params.Ttl = aws.String(v.(string)) + input.Ttl = aws.String(v.(string)) } - if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { - params.Tags = keyvaluetags.New(v).IgnoreAws().AmplifyTags() + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().AmplifyTags() } - resp, err := conn.CreateBranch(params) + log.Printf("[DEBUG] Creating Amplify Branch: %s", input) + _, err := conn.CreateBranch(input) + if err != nil { - return fmt.Errorf("Error creating Amplify Branch: %s", err) + return fmt.Errorf("error creating Amplify Branch (%s): %w", id, err) } - arn := *resp.Branch.BranchArn - d.SetId(arn[strings.Index(arn, ":apps/")+len(":apps/"):]) + d.SetId(id) return resourceAwsAmplifyBranchRead(d, meta) } func resourceAwsAmplifyBranchRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Reading Amplify Branch: %s", d.Id()) + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - s := strings.Split(d.Id(), "/") - app_id := s[0] - branch_name := s[2] + appID, branchName, err := tfamplify.BranchParseResourceID(d.Id()) - resp, err := conn.GetBranch(&lify.GetBranchInput{ - AppId: aws.String(app_id), - BranchName: aws.String(branch_name), - }) if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == amplify.ErrCodeNotFoundException { - log.Printf("[WARN] Amplify Branch (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - return err + return fmt.Errorf("error parsing Amplify Branch ID: %w", err) } - d.Set("app_id", app_id) - d.Set("associated_resources", resp.Branch.AssociatedResources) - d.Set("backend_environment_arn", resp.Branch.BackendEnvironmentArn) - d.Set("arn", resp.Branch.BranchArn) - d.Set("basic_auth_credentials", resp.Branch.EnableBasicAuth) - d.Set("branch_name", resp.Branch.BranchName) - d.Set("build_spec", resp.Branch.BuildSpec) - d.Set("custom_domains", resp.Branch.CustomDomains) - d.Set("description", resp.Branch.Description) - d.Set("destination_branch", resp.Branch.DestinationBranch) - d.Set("display_name", resp.Branch.DisplayName) - d.Set("enable_auto_build", resp.Branch.EnableAutoBuild) - d.Set("enable_notification", resp.Branch.EnableNotification) - d.Set("enable_pull_request_preview", resp.Branch.EnablePullRequestPreview) - d.Set("environment_variables", aws.StringValueMap(resp.Branch.EnvironmentVariables)) - d.Set("framework", resp.Branch.Framework) - d.Set("pull_request_environment_name", resp.Branch.PullRequestEnvironmentName) - d.Set("source_branch", resp.Branch.SourceBranch) - d.Set("stage", resp.Branch.Stage) - d.Set("ttl", resp.Branch.Ttl) - - if err := d.Set("tags", keyvaluetags.AmplifyKeyValueTags(resp.Branch.Tags).IgnoreAws().Map()); err != nil { - return fmt.Errorf("error setting tags: %s", err) + branch, err := finder.BranchByAppIDAndBranchName(conn, appID, branchName) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Amplify Branch (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading Amplify Branch (%s): %w", d.Id(), err) + } + + d.Set("app_id", appID) + d.Set("arn", branch.BranchArn) + d.Set("associated_resources", aws.StringValueSlice(branch.AssociatedResources)) + d.Set("backend_environment_arn", branch.BackendEnvironmentArn) + d.Set("basic_auth_credentials", branch.BasicAuthCredentials) + d.Set("branch_name", branch.BranchName) + d.Set("build_spec", branch.BuildSpec) + d.Set("custom_domains", aws.StringValueSlice(branch.CustomDomains)) + d.Set("description", branch.Description) + d.Set("destination_branch", branch.DestinationBranch) + d.Set("display_name", branch.DisplayName) + d.Set("enable_auto_build", branch.EnableAutoBuild) + d.Set("enable_basic_auth", branch.EnableBasicAuth) + d.Set("enable_notification", branch.EnableNotification) + d.Set("enable_performance_mode", branch.EnablePerformanceMode) + d.Set("enable_pull_request_preview", branch.EnablePullRequestPreview) + d.Set("environment_variables", aws.StringValueMap(branch.EnvironmentVariables)) + d.Set("framework", branch.Framework) + d.Set("pull_request_environment_name", branch.PullRequestEnvironmentName) + d.Set("source_branch", branch.SourceBranch) + d.Set("stage", branch.Stage) + d.Set("ttl", branch.Ttl) + + tags := keyvaluetags.AmplifyKeyValueTags(branch.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + + if err := d.Set("tags_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) } return nil @@ -273,82 +326,90 @@ func resourceAwsAmplifyBranchRead(d *schema.ResourceData, meta interface{}) erro func resourceAwsAmplifyBranchUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Updating Amplify Branch: %s", d.Id()) - s := strings.Split(d.Id(), "/") - app_id := s[0] - branch_name := s[2] + if d.HasChangesExcept("tags", "tags_all") { + appID, branchName, err := tfamplify.BranchParseResourceID(d.Id()) - params := &lify.UpdateBranchInput{ - AppId: aws.String(app_id), - BranchName: aws.String(branch_name), - } + if err != nil { + return fmt.Errorf("error parsing Amplify Branch ID: %w", err) + } - if d.HasChange("backend_environment_arn") { - params.BackendEnvironmentArn = aws.String(d.Get("backend_environment_arn").(string)) - } + input := &lify.UpdateBranchInput{ + AppId: aws.String(appID), + BranchName: aws.String(branchName), + } - if d.HasChange("basic_auth_config") { - params.BasicAuthCredentials = aws.String(d.Get("basic_auth_credentials").(string)) - } + if d.HasChange("backend_environment_arn") { + input.BackendEnvironmentArn = aws.String(d.Get("backend_environment_arn").(string)) + } - if d.HasChange("build_spec") { - params.BuildSpec = aws.String(d.Get("build_spec").(string)) - } + if d.HasChange("basic_auth_credentials") { + input.BasicAuthCredentials = aws.String(d.Get("basic_auth_credentials").(string)) + } - if d.HasChange("description") { - params.Description = aws.String(d.Get("description").(string)) - } + if d.HasChange("build_spec") { + input.BuildSpec = aws.String(d.Get("build_spec").(string)) + } - if d.HasChange("display_name") { - params.DisplayName = aws.String(d.Get("display_name").(string)) - } + if d.HasChange("description") { + input.Description = aws.String(d.Get("description").(string)) + } - if d.HasChange("enable_auto_build") { - params.EnableAutoBuild = aws.Bool(d.Get("enable_auto_build").(bool)) - } + if d.HasChange("display_name") { + input.DisplayName = aws.String(d.Get("display_name").(string)) + } - if d.HasChange("enable_notification") { - params.EnableNotification = aws.Bool(d.Get("enable_notification").(bool)) - } + if d.HasChange("enable_auto_build") { + input.EnableAutoBuild = aws.Bool(d.Get("enable_auto_build").(bool)) + } - if d.HasChange("enable_pull_request_preview") { - params.EnablePullRequestPreview = aws.Bool(d.Get("enable_pull_request_preview").(bool)) - } + if d.HasChange("enable_notification") { + input.EnableNotification = aws.Bool(d.Get("enable_notification").(bool)) + } - if d.HasChange("environment_variables") { - if v := d.Get("environment_variables").(map[string]interface{}); len(v) > 0 { - params.EnvironmentVariables = expandStringMap(v) - } else { - params.EnvironmentVariables = aws.StringMap(map[string]string{"": ""}) + if d.HasChange("enable_performance_mode") { + input.EnablePullRequestPreview = aws.Bool(d.Get("enable_performance_mode").(bool)) } - } - if d.HasChange("framework") { - params.Framework = aws.String(d.Get("framework").(string)) - } + if d.HasChange("enable_pull_request_preview") { + input.EnablePullRequestPreview = aws.Bool(d.Get("enable_pull_request_preview").(bool)) + } - if d.HasChange("pull_request_environment_name") { - params.PullRequestEnvironmentName = aws.String(d.Get("pull_request_environment_name").(string)) - } + if d.HasChange("environment_variables") { + if v := d.Get("environment_variables").(map[string]interface{}); len(v) > 0 { + input.EnvironmentVariables = expandStringMap(v) + } else { + input.EnvironmentVariables = aws.StringMap(map[string]string{"": ""}) + } + } - if d.HasChange("stage") { - params.Stage = aws.String(d.Get("stage").(string)) - } + if d.HasChange("framework") { + input.Framework = aws.String(d.Get("framework").(string)) + } - if d.HasChange("ttl") { - params.Ttl = aws.String(d.Get("ttl").(string)) - } + if d.HasChange("pull_request_environment_name") { + input.PullRequestEnvironmentName = aws.String(d.Get("pull_request_environment_name").(string)) + } - _, err := conn.UpdateBranch(params) - if err != nil { - return fmt.Errorf("Error updating Amplify Branch: %s", err) + if d.HasChange("stage") { + input.Stage = aws.String(d.Get("stage").(string)) + } + + if d.HasChange("ttl") { + input.Ttl = aws.String(d.Get("ttl").(string)) + } + + _, err = conn.UpdateBranch(input) + + if err != nil { + return fmt.Errorf("error updating Amplify Branch (%s): %w", d.Id(), err) + } } - if d.HasChange("tags") { - o, n := d.GetChange("tags") + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") if err := keyvaluetags.AmplifyUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating tags: %s", err) + return fmt.Errorf("error updating tags: %w", err) } } @@ -357,20 +418,25 @@ func resourceAwsAmplifyBranchUpdate(d *schema.ResourceData, meta interface{}) er func resourceAwsAmplifyBranchDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Deleting Amplify Branch: %s", d.Id()) - s := strings.Split(d.Id(), "/") - app_id := s[0] - branch_name := s[2] + appID, branchName, err := tfamplify.BranchParseResourceID(d.Id()) + + if err != nil { + return fmt.Errorf("error parsing Amplify Branch ID: %w", err) + } + + log.Printf("[DEBUG] Deleting Amplify Branch: %s", d.Id()) + _, err = conn.DeleteBranch(&lify.DeleteBranchInput{ + AppId: aws.String(appID), + BranchName: aws.String(branchName), + }) - params := &lify.DeleteBranchInput{ - AppId: aws.String(app_id), - BranchName: aws.String(branch_name), + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeNotFoundException) { + return nil } - _, err := conn.DeleteBranch(params) if err != nil { - return fmt.Errorf("Error deleting Amplify Branch: %s", err) + return fmt.Errorf("error deleting Amplify Branch (%s): %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index ad7be99a5fcb..ce9ddd300be9 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -1,54 +1,55 @@ package aws import ( - "errors" "fmt" "regexp" - "strings" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" "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" + tfamplify "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -// Note: updating 'build_spec' does not work on AWS side func TestAccAWSAmplifyBranch_basic(t *testing.T) { var branch amplify.Branch rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_branch.test" - branchName := "master" - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyBranchConfig_Required(rName), + Config: testAccAWSAmplifyBranchConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyBranchExists(resourceName, &branch), - resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/branches/[^/]+$")), - resource.TestCheckResourceAttr(resourceName, "branch_name", branchName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+/branches/.+`)), + resource.TestCheckResourceAttr(resourceName, "associated_resources.#", "0"), + resource.TestCheckResourceAttr(resourceName, "backend_environment_arn", ""), + resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", ""), + resource.TestCheckResourceAttr(resourceName, "branch_name", rName), resource.TestCheckResourceAttr(resourceName, "build_spec", ""), + resource.TestCheckResourceAttr(resourceName, "custom_domains.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", ""), - resource.TestCheckResourceAttr(resourceName, "display_name", branchName), + resource.TestCheckResourceAttr(resourceName, "destination_branch", ""), + resource.TestCheckResourceAttr(resourceName, "display_name", rName), resource.TestCheckResourceAttr(resourceName, "enable_auto_build", "true"), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "false"), resource.TestCheckResourceAttr(resourceName, "enable_notification", "false"), + resource.TestCheckResourceAttr(resourceName, "enable_performance_mode", "false"), resource.TestCheckResourceAttr(resourceName, "enable_pull_request_preview", "false"), - resource.TestCheckResourceAttr(resourceName, "pull_request_environment_name", ""), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), resource.TestCheckResourceAttr(resourceName, "framework", ""), + resource.TestCheckResourceAttr(resourceName, "pull_request_environment_name", ""), + resource.TestCheckResourceAttr(resourceName, "source_branch", ""), resource.TestCheckResourceAttr(resourceName, "stage", "NONE"), resource.TestCheckResourceAttr(resourceName, "ttl", "5"), - resource.TestCheckResourceAttr(resourceName, "environment_variables.#", "0"), - resource.TestCheckResourceAttr(resourceName, "tags.#", "0"), - resource.TestCheckResourceAttr(resourceName, "associated_resources.#", "0"), - resource.TestCheckResourceAttr(resourceName, "custom_domains.#", "0"), - resource.TestCheckResourceAttr(resourceName, "destination_branch", ""), - resource.TestCheckResourceAttr(resourceName, "source_branch", ""), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, @@ -57,39 +58,50 @@ func TestAccAWSAmplifyBranch_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + }, + }) +} + +func TestAccAWSAmplifyBranch_disappears(t *testing.T) { + var branch amplify.Branch + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyBranchConfigSimple(rName), + Config: testAccAWSAmplifyBranchConfigName(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "description", "description"), - resource.TestCheckResourceAttr(resourceName, "display_name", "displayname"), - resource.TestCheckResourceAttr(resourceName, "enable_auto_build", "false"), - resource.TestCheckResourceAttr(resourceName, "framework", "WEB"), - resource.TestCheckResourceAttr(resourceName, "stage", "PRODUCTION"), - resource.TestCheckResourceAttr(resourceName, "ttl", "10"), + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAmplifyBranch(), resourceName), ), + ExpectNonEmptyPlan: true, }, }, }) } -func TestAccAWSAmplifyBranch_rename(t *testing.T) { - var branch1, branch2 amplify.Branch +func TestAccAWSAmplifyBranch_Tags(t *testing.T) { + var branch amplify.Branch rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_branch.test" - branchName1 := "master" - branchName2 := "development" - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyBranchConfigBranch(rName, branchName1), + Config: testAccAWSAmplifyBranchConfigTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyBranchExists(resourceName, &branch1), - resource.TestCheckResourceAttr(resourceName, "branch_name", branchName1), + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { @@ -98,11 +110,20 @@ func TestAccAWSAmplifyBranch_rename(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyBranchConfigBranch(rName, branchName2), + Config: testAccAWSAmplifyBranchConfigTags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyBranchExists(resourceName, &branch2), - testAccCheckAWSAmplifyBranchRecreated(&branch1, &branch2), - resource.TestCheckResourceAttr(resourceName, "branch_name", branchName2), + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSAmplifyBranchConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, }, @@ -114,7 +135,8 @@ func TestAccAWSAmplifyBranch_simple(t *testing.T) { resourceName := "aws_amplify_branch.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ @@ -143,7 +165,8 @@ func TestAccAWSAmplifyBranch_backendEnvironment(t *testing.T) { resourceName := "aws_amplify_branch.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ @@ -167,7 +190,8 @@ func TestAccAWSAmplifyBranch_pullRequestPreview(t *testing.T) { resourceName := "aws_amplify_branch.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ @@ -187,7 +211,7 @@ func TestAccAWSAmplifyBranch_pullRequestPreview(t *testing.T) { }) } -func TestAccAWSAmplifyBranch_basicAuthConfig(t *testing.T) { +func TestAccAWSAmplifyBranch_BasicAuthCredentials(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_branch.test" @@ -197,7 +221,8 @@ func TestAccAWSAmplifyBranch_basicAuthConfig(t *testing.T) { password2 := "password2" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ @@ -239,7 +264,8 @@ func TestAccAWSAmplifyBranch_notification(t *testing.T) { resourceName := "aws_amplify_branch.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ @@ -263,7 +289,8 @@ func TestAccAWSAmplifyBranch_environmentVariables(t *testing.T) { resourceName := "aws_amplify_branch.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ @@ -297,45 +324,6 @@ func TestAccAWSAmplifyBranch_environmentVariables(t *testing.T) { }) } -func TestAccAWSAmplifyBranch_tags(t *testing.T) { - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_amplify_branch.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyBranchConfigTags1(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.TAG1", "1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyBranchConfigTags2(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.TAG1", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.TAG2", "2"), - ), - }, - { - Config: testAccAWSAmplifyBranchConfig_Required(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - ), - }, - }, - }) -} - func testAccCheckAWSAmplifyBranchExists(resourceName string, v *amplify.Branch) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -343,67 +331,71 @@ func testAccCheckAWSAmplifyBranchExists(resourceName string, v *amplify.Branch) return fmt.Errorf("Not found: %s", resourceName) } - conn := testAccProvider.Meta().(*AWSClient).amplifyconn + if rs.Primary.ID == "" { + return fmt.Errorf("No Amplify Branch ID is set") + } - id := strings.Split(rs.Primary.ID, "/") - app_id := id[0] - branch := id[2] + appID, branchName, err := tfamplify.BranchParseResourceID(rs.Primary.ID) - output, err := conn.GetBranch(&lify.GetBranchInput{ - AppId: aws.String(app_id), - BranchName: aws.String(branch), - }) if err != nil { return err } - if output == nil || output.Branch == nil { - return fmt.Errorf("Amplify Branch (%s) not found", rs.Primary.ID) + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + branch, err := finder.BranchByAppIDAndBranchName(conn, appID, branchName) + + if err != nil { + return err } - *v = *output.Branch + *v = *branch return nil } } func testAccCheckAWSAmplifyBranchDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_amplify_branch" { continue } - conn := testAccProvider.Meta().(*AWSClient).amplifyconn + appID, branchName, err := tfamplify.BranchParseResourceID(rs.Primary.ID) - id := strings.Split(rs.Primary.ID, "/") - app_id := id[0] - branch := id[2] + if err != nil { + return err + } - _, err := conn.GetBranch(&lify.GetBranchInput{ - AppId: aws.String(app_id), - BranchName: aws.String(branch), - }) + _, err = finder.BranchByAppIDAndBranchName(conn, appID, branchName) - if isAWSErr(err, amplify.ErrCodeNotFoundException, "") { + if tfresource.NotFound(err) { continue } if err != nil { return err } + + return fmt.Errorf("Amplify Branch %s still exists", rs.Primary.ID) } return nil } -func testAccCheckAWSAmplifyBranchRecreated(i, j *amplify.Branch) resource.TestCheckFunc { - return func(s *terraform.State) error { - if aws.TimeValue(i.CreateTime) == aws.TimeValue(j.CreateTime) { - return errors.New("Amplify Branch was not recreated") - } +func testAccAWSAmplifyBranchConfigName(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q +} - return nil - } +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = %[1]q +} +`, rName) } func testAccAWSAmplifyBranchConfig_Required(rName string) string { @@ -548,37 +540,37 @@ resource "aws_amplify_branch" "test" { `, rName) } -func testAccAWSAmplifyBranchConfigTags1(rName string) string { +func testAccAWSAmplifyBranchConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q } resource "aws_amplify_branch" "test" { app_id = aws_amplify_app.test.id - branch_name = "master" + branch_name = %[1]q tags = { - TAG1 = "1", + %[2]q = %[3]q } } -`, rName) +`, rName, tagKey1, tagValue1) } -func testAccAWSAmplifyBranchConfigTags2(rName string) string { +func testAccAWSAmplifyBranchConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q } resource "aws_amplify_branch" "test" { app_id = aws_amplify_app.test.id - branch_name = "master" + branch_name = %[1]q tags = { - TAG1 = "2", - TAG2 = "2", + %[2]q = %[3]q + %[4]q = %[5]q } } -`, rName) +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) } diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown index 58804a136551..55992ca9bf19 100644 --- a/website/docs/r/amplify_branch.html.markdown +++ b/website/docs/r/amplify_branch.html.markdown @@ -162,6 +162,7 @@ The following arguments are supported: * `description` - (Optional) The description for the branch. * `display_name` - (Optional) The display name for a branch. This is used as the default domain prefix. * `enable_auto_build` - (Optional) Enables auto building for the branch. +* `enable_basic_auth` - (Optional) Enables basic authorization for the branch. * `enable_notifications` - (Optional) Enables notifications for the branch. * `enable_performance_mode` - (Optional) Enables performance mode for the branch. * `enable_pull_request_preview` - (Optional) Enables pull request previews for this branch. @@ -178,7 +179,7 @@ The following attributes are exported: * `arn` - The Amazon Resource Name (ARN) for the branch. * `associated_resources` - A list of custom resources that are linked to this branch. -* `custom_domains` - The custom domains for a branch of an Amplify app. +* `custom_domains` - The custom domains for the branch. * `destination_branch` - The destination branch if the branch is a pull request branch. * `source_branch` - The source branch if the branch is a pull request branch. * `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). From 7a947543a5dcb2b7a29ec9bc58032a0e4f5404e6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 16:04:46 -0400 Subject: [PATCH 0135/1208] Add CHANGELOG entry. --- .changelog/11937.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/11937.txt diff --git a/.changelog/11937.txt b/.changelog/11937.txt new file mode 100644 index 000000000000..f520349bd25b --- /dev/null +++ b/.changelog/11937.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_amplify_branch +``` \ No newline at end of file From 0061ac57f321a107209790be95accb1034568785 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 16:32:57 -0400 Subject: [PATCH 0136/1208] r/aws_amplify_branch: Test 'backend_environment_arn'. --- aws/resource_aws_amplify_branch.go | 10 +- aws/resource_aws_amplify_branch_test.go | 163 ++++++++++++++++++------ aws/resource_aws_amplify_test.go | 6 + 3 files changed, 140 insertions(+), 39 deletions(-) diff --git a/aws/resource_aws_amplify_branch.go b/aws/resource_aws_amplify_branch.go index 9fd82bd106ad..b6aecd4fb157 100644 --- a/aws/resource_aws_amplify_branch.go +++ b/aws/resource_aws_amplify_branch.go @@ -1,6 +1,7 @@ package aws import ( + "context" "fmt" "log" "regexp" @@ -8,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "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" @@ -26,7 +28,13 @@ func resourceAwsAmplifyBranch() *schema.Resource { State: schema.ImportStatePassthrough, }, - CustomizeDiff: SetTagsDiff, + CustomizeDiff: customdiff.Sequence( + SetTagsDiff, + customdiff.ForceNewIfChange("backend_environment_arn", func(_ context.Context, old, new, meta interface{}) bool { + // Any existing value cannot be cleared. + return new.(string) == "" + }), + ), Schema: map[string]*schema.Schema{ "app_id": { diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index ce9ddd300be9..59dc3f267dfb 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -5,6 +5,7 @@ import ( "regexp" "testing" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -14,7 +15,7 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -func TestAccAWSAmplifyBranch_basic(t *testing.T) { +func testAccAWSAmplifyBranch_basic(t *testing.T) { var branch amplify.Branch rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_branch.test" @@ -62,7 +63,7 @@ func TestAccAWSAmplifyBranch_basic(t *testing.T) { }) } -func TestAccAWSAmplifyBranch_disappears(t *testing.T) { +func testAccAWSAmplifyBranch_disappears(t *testing.T) { var branch amplify.Branch rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_branch.test" @@ -85,7 +86,7 @@ func TestAccAWSAmplifyBranch_disappears(t *testing.T) { }) } -func TestAccAWSAmplifyBranch_Tags(t *testing.T) { +func testAccAWSAmplifyBranch_Tags(t *testing.T) { var branch amplify.Branch rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_branch.test" @@ -130,6 +131,52 @@ func TestAccAWSAmplifyBranch_Tags(t *testing.T) { }) } +func testAccAWSAmplifyBranch_BackendEnvironmentArn(t *testing.T) { + var branch1, branch2, branch3 amplify.Branch + rName := acctest.RandomWithPrefix("tf-acc-test") + environmentName1 := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) + environmentName2 := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) + resourceName := "aws_amplify_branch.test" + backendEnvironmentResourceName := "aws_amplify_backend_environment.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch1), + resource.TestCheckResourceAttrPair(resourceName, "backend_environment_arn", backendEnvironmentResourceName, "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch2), + testAccCheckAWSAmplifyBranchNotRecreated(&branch1, &branch2), + resource.TestCheckResourceAttrPair(resourceName, "backend_environment_arn", backendEnvironmentResourceName, "arn"), + ), + }, + { + Config: testAccAWSAmplifyBranchConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch3), + testAccCheckAWSAmplifyBranchRecreated(&branch2, &branch3), + resource.TestCheckResourceAttr(resourceName, "backend_environment_arn", ""), + ), + }, + }, + }) +} + func TestAccAWSAmplifyBranch_simple(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_branch.test" @@ -385,6 +432,26 @@ func testAccCheckAWSAmplifyBranchDestroy(s *terraform.State) error { return nil } +func testAccCheckAWSAmplifyBranchNotRecreated(before, after *amplify.Branch) resource.TestCheckFunc { + return func(s *terraform.State) error { + if before, after := aws.TimeValue(before.CreateTime), aws.TimeValue(after.CreateTime); before != after { + return fmt.Errorf("Amplify Branch (%s/%s) recreated", before, after) + } + + return nil + } +} + +func testAccCheckAWSAmplifyBranchRecreated(before, after *amplify.Branch) resource.TestCheckFunc { + return func(s *terraform.State) error { + if before, after := aws.TimeValue(before.CreateTime), aws.TimeValue(after.CreateTime); before == after { + return fmt.Errorf("Amplify Branch (%s) not recreated", before) + } + + return nil + } +} + func testAccAWSAmplifyBranchConfigName(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { @@ -398,6 +465,61 @@ resource "aws_amplify_branch" "test" { `, rName) } +func testAccAWSAmplifyBranchConfigTags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = %[1]q + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccAWSAmplifyBranchConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = %[1]q + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} + +func testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q +} + +resource "aws_amplify_backend_environment" "test" { + app_id = aws_amplify_app.test.id + environment_name = %[2]q +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = %[1]q + + backend_environment_arn = aws_amplify_backend_environment.test.arn +} +`, rName, environmentName) +} + func testAccAWSAmplifyBranchConfig_Required(rName string) string { return testAccAWSAmplifyBranchConfigBranch(rName, "master") } @@ -539,38 +661,3 @@ resource "aws_amplify_branch" "test" { } `, rName) } - -func testAccAWSAmplifyBranchConfigTags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = %[1]q -} - -resource "aws_amplify_branch" "test" { - app_id = aws_amplify_app.test.id - branch_name = %[1]q - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccAWSAmplifyBranchConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = %[1]q -} - -resource "aws_amplify_branch" "test" { - app_id = aws_amplify_app.test.id - branch_name = %[1]q - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) -} diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index 46f5fab62790..dd845329ea1f 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -27,6 +27,12 @@ func TestAccAWSAmplify_serial(t *testing.T) { "disappears": testAccAWSAmplifyBackendEnvironment_disappears, "DeploymentArtifacts_StackName": testAccAWSAmplifyBackendEnvironment_DeploymentArtifacts_StackName, }, + "Branch": { + "basic": testAccAWSAmplifyBranch_basic, + "disappears": testAccAWSAmplifyBranch_disappears, + "Tags": testAccAWSAmplifyBranch_Tags, + "BackendEnvironmentArn": testAccAWSAmplifyBranch_BackendEnvironmentArn, + }, } for group, m := range testCases { From 60214e9e7ec27ef08622bae3040d1d90f27e98cf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 16:34:56 -0400 Subject: [PATCH 0137/1208] Fix terrafmt errors. --- website/docs/r/amplify_branch.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown index 55992ca9bf19..58f32c6ca921 100644 --- a/website/docs/r/amplify_branch.html.markdown +++ b/website/docs/r/amplify_branch.html.markdown @@ -21,8 +21,8 @@ resource "aws_amplify_branch" "master" { app_id = aws_amplify_app.example.id branch_name = "master" - framework = "React" - stage = "PRODUCTION" + framework = "React" + stage = "PRODUCTION" environment_variables = { REACT_APP_API_SERVER = "https://api.example.com" @@ -132,7 +132,7 @@ data "aws_iam_policy_document" "amplify_app_master" { ] principals { - type = "Service" + type = "Service" identifiers = [ "events.amazonaws.com", ] From 6ef614f2e1e0061f486849ed3f849001ca78ca11 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 16:37:50 -0400 Subject: [PATCH 0138/1208] Fix validate-terraform errors. --- website/docs/r/amplify_branch.html.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown index 58f32c6ca921..155eb34a6b91 100644 --- a/website/docs/r/amplify_branch.html.markdown +++ b/website/docs/r/amplify_branch.html.markdown @@ -42,7 +42,7 @@ resource "aws_amplify_branch" "master" { branch_name = "master" basic_auth_config { - // Enable basic authentication. + # Enable basic authentication. enable_basic_auth = true username = "username" @@ -64,11 +64,11 @@ resource "aws_amplify_branch" "master" { app_id = aws_amplify_app.example.id branch_name = "master" - // Enable SNS notifications. + # Enable SNS notifications. enable_notification = true } -// CloudWatch Events Rule for Amplify notifications +# CloudWatch Events Rule for Amplify notifications resource "aws_cloudwatch_event_rule" "amplify_app_master" { name = "amplify-${aws_amplify_app.app.id}-${aws_amplify_branch.master.branch_name}-branch-notification" @@ -115,7 +115,7 @@ resource "aws_cloudwatch_event_target" "amplify_app_master" { } } -// SNS Topic for Amplify notifications +# SNS Topic for Amplify notifications resource "aws_sns_topic" "amplify_app_master" { name = "amplify-${aws_amplify_app.app.id}_${aws_amplify_branch.master.branch_name}" From 045f100fc70f66be2f5cbd8369739399cabda973 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 16:38:40 -0400 Subject: [PATCH 0139/1208] Fix tfproviderdocs errors. --- website/docs/r/amplify_branch.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown index 155eb34a6b91..540a66797ef1 100644 --- a/website/docs/r/amplify_branch.html.markdown +++ b/website/docs/r/amplify_branch.html.markdown @@ -173,7 +173,7 @@ The following arguments are supported: * `tags` - (Optional) Key-value mapping of resource tags. 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. * `ttl` - (Optional) The content Time To Live (TTL) for the website in seconds. -## Attribute Reference +## Attributes Reference The following attributes are exported: From ca839400ffafbf9ef575b1d5623b6dc7be7debab Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 1 Jun 2021 16:39:58 -0400 Subject: [PATCH 0140/1208] Comment out currently unused tests. --- aws/resource_aws_amplify_branch_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index 59dc3f267dfb..72f8704e0d8e 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -177,6 +177,7 @@ func testAccAWSAmplifyBranch_BackendEnvironmentArn(t *testing.T) { }) } +/* func TestAccAWSAmplifyBranch_simple(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_branch.test" @@ -370,6 +371,7 @@ func TestAccAWSAmplifyBranch_environmentVariables(t *testing.T) { }, }) } +*/ func testAccCheckAWSAmplifyBranchExists(resourceName string, v *amplify.Branch) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -520,6 +522,7 @@ resource "aws_amplify_branch" "test" { `, rName, environmentName) } +/* func testAccAWSAmplifyBranchConfig_Required(rName string) string { return testAccAWSAmplifyBranchConfigBranch(rName, "master") } @@ -661,3 +664,4 @@ resource "aws_amplify_branch" "test" { } `, rName) } +*/ From 8507bdb943f5889989011d74d804bd841aee15a4 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 1 Jun 2021 20:47:38 +0000 Subject: [PATCH 0141/1208] Update CHANGELOG.md for #19615 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc497f3a719b..92bf9e6749d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 3.44.0 (Unreleased) +BUG FIXES: + +* resource/aws_elasticache_cluster: Fix provider-level `default_tags` support for resource ([#19615](https://github.com/hashicorp/terraform-provider-aws/issues/19615)) + ## 3.43.0 (June 01, 2021) FEATURES: From 888fa205ce35883cdda4b0cf398f0886e0a74b2e Mon Sep 17 00:00:00 2001 From: nikhil-goenka <70277861+nikhil-goenka@users.noreply.github.com> Date: Wed, 2 Jun 2021 02:43:27 +0530 Subject: [PATCH 0142/1208] F/resource aws acmpca certificate authority: support for S3ObjectAcl (#19578) * support for S3ObjectAcl in the acmpca_certificate_authority * Add CHANGELOG entry. * r/aws_acmpca_certificate_authority: Tweak acceptance tests. Co-authored-by: Kit Ewbank --- .changelog/19578.txt | 3 + ...source_aws_acmpca_certificate_authority.go | 10 +++ ...e_aws_acmpca_certificate_authority_test.go | 81 +++++++++++++++++++ ...acmpca_certificate_authority.html.markdown | 1 + 4 files changed, 95 insertions(+) create mode 100644 .changelog/19578.txt diff --git a/.changelog/19578.txt b/.changelog/19578.txt new file mode 100644 index 000000000000..c02aad104ece --- /dev/null +++ b/.changelog/19578.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_acmpca_certificate_authority: Add `s3_object_acl` argument to `revocation_configuration.crl_configuration` configuration block +``` \ No newline at end of file diff --git a/aws/resource_aws_acmpca_certificate_authority.go b/aws/resource_aws_acmpca_certificate_authority.go index a569d394a812..c667f22507e2 100644 --- a/aws/resource_aws_acmpca_certificate_authority.go +++ b/aws/resource_aws_acmpca_certificate_authority.go @@ -236,6 +236,12 @@ func resourceAwsAcmpcaCertificateAuthority() *schema.Resource { Optional: true, ValidateFunc: validation.StringLenBetween(0, 255), }, + "s3_object_acl": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(acmpca.S3ObjectAcl_Values(), false), + }, }, }, }, @@ -602,6 +608,9 @@ func expandAcmpcaCrlConfiguration(l []interface{}) *acmpca.CrlConfiguration { if v, ok := m["s3_bucket_name"]; ok && v.(string) != "" { config.S3BucketName = aws.String(v.(string)) } + if v, ok := m["s3_object_acl"]; ok && v.(string) != "" { + config.S3ObjectAcl = aws.String(v.(string)) + } return config } @@ -668,6 +677,7 @@ func flattenAcmpcaCrlConfiguration(config *acmpca.CrlConfiguration) []interface{ "enabled": aws.BoolValue(config.Enabled), "expiration_in_days": int(aws.Int64Value(config.ExpirationInDays)), "s3_bucket_name": aws.StringValue(config.S3BucketName), + "s3_object_acl": aws.StringValue(config.S3ObjectAcl), } return []interface{}{m} diff --git a/aws/resource_aws_acmpca_certificate_authority_test.go b/aws/resource_aws_acmpca_certificate_authority_test.go index f2543d6ce261..274be1562785 100644 --- a/aws/resource_aws_acmpca_certificate_authority_test.go +++ b/aws/resource_aws_acmpca_certificate_authority_test.go @@ -403,6 +403,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.enabled", "true"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.expiration_in_days", "1"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.s3_bucket_name", rName), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.s3_object_acl", "PUBLIC_READ"), ), }, // Test importing revocation configuration @@ -440,6 +441,56 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }) } +func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfiguration_S3ObjectAcl(t *testing.T) { + var certificateAuthority acmpca.CertificateAuthority + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_acmpca_certificate_authority.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsAcmpcaCertificateAuthorityDestroy, + Steps: []resource.TestStep{ + // Test creating revocation configuration on resource creation + { + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_s3ObjectAcl(rName, "BUCKET_OWNER_FULL_CONTROL"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.expiration_in_days", "1"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.s3_bucket_name", rName), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.s3_object_acl", "BUCKET_OWNER_FULL_CONTROL"), + ), + }, + // Test importing revocation configuration + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "permanent_deletion_time_in_days", + }, + }, + // Test updating revocation configuration + { + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_s3ObjectAcl(rName, "PUBLIC_READ"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.expiration_in_days", "1"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.s3_bucket_name", rName), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.s3_object_acl", "PUBLIC_READ"), + ), + }, + }, + }) +} + func TestAccAwsAcmpcaCertificateAuthority_Tags(t *testing.T) { var certificateAuthority acmpca.CertificateAuthority resourceName := "aws_acmpca_certificate_authority.test" @@ -797,6 +848,36 @@ resource "aws_acmpca_certificate_authority" "test" { `, testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName), expirationInDays) } +func testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_s3ObjectAcl(rName, s3ObjectAcl string) string { + return fmt.Sprintf(` +%s + +resource "aws_acmpca_certificate_authority" "test" { + permanent_deletion_time_in_days = 7 + + certificate_authority_configuration { + key_algorithm = "RSA_4096" + signing_algorithm = "SHA512WITHRSA" + + subject { + common_name = "terraformtesting.com" + } + } + + revocation_configuration { + crl_configuration { + enabled = true + expiration_in_days = 1 + s3_bucket_name = aws_s3_bucket.test.id + s3_object_acl = "%s" + } + } + + depends_on = [aws_s3_bucket_policy.test] +} +`, testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName), s3ObjectAcl) +} + func testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { diff --git a/website/docs/r/acmpca_certificate_authority.html.markdown b/website/docs/r/acmpca_certificate_authority.html.markdown index b01d4fb27553..8e53c7298ce6 100644 --- a/website/docs/r/acmpca_certificate_authority.html.markdown +++ b/website/docs/r/acmpca_certificate_authority.html.markdown @@ -132,6 +132,7 @@ Contains information about the certificate subject. Identifies the entity that o * `enabled` - (Optional) Boolean value that specifies whether certificate revocation lists (CRLs) are enabled. Defaults to `false`. * `expiration_in_days` - (Required) Number of days until a certificate expires. Must be between 1 and 5000. * `s3_bucket_name` - (Optional) Name of the S3 bucket that contains the CRL. If you do not provide a value for the `custom_cname` argument, the name of your S3 bucket is placed into the CRL Distribution Points extension of the issued certificate. You must specify a bucket policy that allows ACM PCA to write the CRL to your bucket. Must be less than or equal to 255 characters in length. +* `s3_object_acl` - (Optional) Determines whether the CRL will be publicly readable or privately held in the CRL Amazon S3 bucket. Defaults to `PUBLIC_READ`. ## Attributes Reference From 48173cc60ed391978596dcdd00cda2e5fc3ee07a Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 1 Jun 2021 21:17:24 +0000 Subject: [PATCH 0143/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92bf9e6749d2..63b097b10d92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 3.44.0 (Unreleased) +ENHANCEMENTS: + +* resource/aws_acmpca_certificate_authority: Add `s3_object_acl` argument to `revocation_configuration.crl_configuration` configuration block ([#19578](https://github.com/hashicorp/terraform-provider-aws/issues/19578)) + BUG FIXES: * resource/aws_elasticache_cluster: Fix provider-level `default_tags` support for resource ([#19615](https://github.com/hashicorp/terraform-provider-aws/issues/19615)) From a33bcb9fb3f6d7b87ebc2b9dc4b7c8aada7eeb65 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 1 Jun 2021 16:36:16 -0700 Subject: [PATCH 0144/1208] Adds default third region to sweepers --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index f58c56bd867c..1df97ab3f132 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -SWEEP?=us-east-1,us-west-2 +SWEEP?=us-east-1,us-east-2,us-west-2 TEST?=./... SWEEP_DIR?=./aws PKG_NAME=aws From e38f478cc5d51c644154eddafbe8d6d642b310c1 Mon Sep 17 00:00:00 2001 From: Erik Paasonen Date: Tue, 1 Jun 2021 21:24:54 -0500 Subject: [PATCH 0145/1208] fix mislabeled block in codebuild proj documentation --- website/docs/r/codebuild_project.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/codebuild_project.html.markdown b/website/docs/r/codebuild_project.html.markdown index cdf681092f38..ddec94b02c7e 100755 --- a/website/docs/r/codebuild_project.html.markdown +++ b/website/docs/r/codebuild_project.html.markdown @@ -353,12 +353,12 @@ This block is only valid when the `type` is `CODECOMMIT`, `GITHUB` or `GITHUB_EN * `fetch_submodules` - (Required) Whether to fetch Git submodules for the AWS CodeBuild build project. -`build_status_config` supports the following: +#### secondary_sources: build_status_config * `context` - (Optional) Specifies the context of the build status CodeBuild sends to the source provider. The usage of this parameter depends on the source provider. * `target_url` - (Optional) Specifies the target url of the build status CodeBuild sends to the source provider. The usage of this parameter depends on the source provider. -`vpc_config` supports the following: +### source * `auth` - (Optional, **Deprecated**) Configuration block with the authorization settings for AWS CodeBuild to access the source code to be built. This information is for the AWS CodeBuild console's use only. Use the [`aws_codebuild_source_credential` resource](codebuild_source_credential.html) instead. Auth blocks are documented below. * `buildspec` - (Optional) Build specification to use for this build project's related builds. This must be set when `type` is `NO_SOURCE`. From cdb6b28f4a3cfad0f913f2681c9c2595574e10d7 Mon Sep 17 00:00:00 2001 From: Roberth Kulbin Date: Tue, 1 Jun 2021 10:45:51 +0100 Subject: [PATCH 0146/1208] r/aws_cloudwatch_log_metric_filter: support dimensions --- ...source_aws_cloudwatch_log_metric_filter.go | 5 ++ ...e_aws_cloudwatch_log_metric_filter_test.go | 75 +++++++++++++++++++ aws/structure.go | 10 +++ ...cloudwatch_log_metric_filter.html.markdown | 3 +- 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudwatch_log_metric_filter.go b/aws/resource_aws_cloudwatch_log_metric_filter.go index 74aa7ef1b85b..fff90aab0c9d 100644 --- a/aws/resource_aws_cloudwatch_log_metric_filter.go +++ b/aws/resource_aws_cloudwatch_log_metric_filter.go @@ -78,6 +78,11 @@ func resourceAwsCloudWatchLogMetricFilter() *schema.Resource { Optional: true, ValidateFunc: validateTypeStringNullableFloat, }, + "dimensions": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, }, }, }, diff --git a/aws/resource_aws_cloudwatch_log_metric_filter_test.go b/aws/resource_aws_cloudwatch_log_metric_filter_test.go index 53a9274a0d2e..6823121a15d8 100644 --- a/aws/resource_aws_cloudwatch_log_metric_filter_test.go +++ b/aws/resource_aws_cloudwatch_log_metric_filter_test.go @@ -34,6 +34,7 @@ func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.name", "EventCount"), resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.namespace", "YourNamespace"), resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.value", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.dimensions.%", "0"), testAccCheckCloudWatchLogMetricFilterTransformation(&mf, &cloudwatchlogs.MetricTransformation{ MetricName: aws.String("EventCount"), MetricNamespace: aws.String("YourNamespace"), @@ -60,6 +61,7 @@ func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.namespace", "MyNamespace"), resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.value", "2"), resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.default_value", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.dimensions.%", "0"), testAccCheckCloudWatchLogMetricFilterTransformation(&mf, &cloudwatchlogs.MetricTransformation{ MetricName: aws.String("AccessDeniedCount"), MetricNamespace: aws.String("MyNamespace"), @@ -68,6 +70,32 @@ func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) { }), ), }, + { + Config: testAccAWSCloudWatchLogMetricFilterConfigModifiedWithDimensions(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchLogMetricFilterExists(resourceName, &mf), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("MyAppAccessCount-%d", rInt)), + testAccCheckCloudWatchLogMetricFilterName(&mf, fmt.Sprintf("MyAppAccessCount-%d", rInt)), + resource.TestCheckResourceAttr(resourceName, "pattern", "{ $.errorCode = \"AccessDenied\" }"), + testAccCheckCloudWatchLogMetricFilterPattern(&mf, "{ $.errorCode = \"AccessDenied\" }"), + resource.TestCheckResourceAttr(resourceName, "log_group_name", fmt.Sprintf("MyApp/access-%d.log", rInt)), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.name", "AccessDeniedCount"), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.namespace", "MyNamespace"), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.value", "2"), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.dimensions.%", "2"), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.dimensions.ErrorCode", "$.errorCode"), + resource.TestCheckResourceAttr(resourceName, "metric_transformation.0.dimensions.Dummy", "$.dummy"), + testAccCheckCloudWatchLogMetricFilterTransformation(&mf, &cloudwatchlogs.MetricTransformation{ + MetricName: aws.String("AccessDeniedCount"), + MetricNamespace: aws.String("MyNamespace"), + MetricValue: aws.String("2"), + Dimensions: aws.StringMap(map[string]string{ + "ErrorCode": "$.errorCode", + "Dummy": "$.dummy", + }), + }), + ), + }, { Config: testAccAWSCloudwatchLogMetricFilterConfigMany(rInt), Check: testAccCheckCloudwatchLogMetricFilterManyExist("aws_cloudwatch_log_metric_filter.count_dracula", &mf), @@ -130,6 +158,24 @@ func testAccCheckCloudWatchLogMetricFilterTransformation(mf *cloudwatchlogs.Metr *expected.DefaultValue, *given.DefaultValue) } + if len(expected.Dimensions) > 0 || len(given.Dimensions) > 0 { + e, g := aws.StringValueMap(expected.Dimensions), aws.StringValueMap(given.Dimensions) + + if len(e) != len(g) { + return fmt.Errorf("Expected %d dimensions, received %d", len(e), len(g)) + } + + for ek, ev := range e { + gv, ok := g[ek] + if !ok { + return fmt.Errorf("Expected dimension %s, received nothing", ek) + } + if gv != ev { + return fmt.Errorf("Expected dimension %s to be %s, received %s", ek, ev, gv) + } + } + } + return nil } } @@ -231,6 +277,35 @@ resource "aws_cloudwatch_log_group" "dada" { `, rInt, rInt) } +func testAccAWSCloudWatchLogMetricFilterConfigModifiedWithDimensions(rInt int) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_log_metric_filter" "foobar" { + name = "MyAppAccessCount-%d" + + pattern = < 0 { + transformation.Dimensions = expandStringMap(dims) + } + return []*cloudwatchlogs.MetricTransformation{&transformation} } @@ -1936,6 +1940,12 @@ func flattenCloudWatchLogMetricTransformations(ts []*cloudwatchlogs.MetricTransf m["default_value"] = strconv.FormatFloat(aws.Float64Value(ts[0].DefaultValue), 'f', -1, 64) } + if dims := ts[0].Dimensions; len(dims) > 0 { + m["dimensions"] = pointersMapToStringList(dims) + } else { + m["dimensions"] = nil + } + mts = append(mts, m) return mts diff --git a/website/docs/r/cloudwatch_log_metric_filter.html.markdown b/website/docs/r/cloudwatch_log_metric_filter.html.markdown index 61e7c068b4e8..0d9721a5d869 100644 --- a/website/docs/r/cloudwatch_log_metric_filter.html.markdown +++ b/website/docs/r/cloudwatch_log_metric_filter.html.markdown @@ -45,7 +45,8 @@ The `metric_transformation` block supports the following arguments: * `name` - (Required) The name of the CloudWatch metric to which the monitored log information should be published (e.g. `ErrorCount`) * `namespace` - (Required) The destination namespace of the CloudWatch metric. * `value` - (Required) What to publish to the metric. For example, if you're counting the occurrences of a particular term like "Error", the value will be "1" for each occurrence. If you're counting the bytes transferred the published value will be the value in the log event. -* `default_value` - (Optional) The value to emit when a filter pattern does not match a log event. +* `default_value` - (Optional) The value to emit when a filter pattern does not match a log event. Conflicts with `dimensions`. +* `dimensions` - (Optional) Map of fields to use as dimensions for the metric. Up to 3 dimensions are allowed. Conflicts with `default_value`. ## Attributes Reference From 91997a48f6c7018b3e8eb46abaa5f67e5b4fe9ae Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 10:17:04 -0400 Subject: [PATCH 0147/1208] Add CHANGELOG entry. --- .changelog/19625.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19625.txt diff --git a/.changelog/19625.txt b/.changelog/19625.txt new file mode 100644 index 000000000000..4c3e1cc1ddac --- /dev/null +++ b/.changelog/19625.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_cloudwatch_log_metric_filter: Add `dimensions` argument to `metric_transformation` configuration block +``` \ No newline at end of file From 3009c086d8b148bbff2ef043fa23ea6b5f518f0f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 10:36:16 -0400 Subject: [PATCH 0148/1208] Fix tfproviderdocs error. --- website/docs/r/amplify_branch.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown index 540a66797ef1..5c29b7acf482 100644 --- a/website/docs/r/amplify_branch.html.markdown +++ b/website/docs/r/amplify_branch.html.markdown @@ -175,7 +175,7 @@ The following arguments are supported: ## Attributes Reference -The following attributes are exported: +In addition to all arguments above, the following attributes are exported: * `arn` - The Amazon Resource Name (ARN) for the branch. * `associated_resources` - A list of custom resources that are linked to this branch. From 3725755f39099a07bd81e933e0a5e2e7711b3ba5 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 2 Jun 2021 14:38:41 +0000 Subject: [PATCH 0149/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63b097b10d92..ee8c39a3a3ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,16 @@ ENHANCEMENTS: * resource/aws_acmpca_certificate_authority: Add `s3_object_acl` argument to `revocation_configuration.crl_configuration` configuration block ([#19578](https://github.com/hashicorp/terraform-provider-aws/issues/19578)) +* resource/aws_cloudwatch_log_metric_filter: Add `dimensions` argument to `metric_transformation` configuration block ([#19625](https://github.com/hashicorp/terraform-provider-aws/issues/19625)) +* resource/aws_cloudwatch_metric_alarm: Add plan time validation to `metric_query.metric.stat`. ([#19571](https://github.com/hashicorp/terraform-provider-aws/issues/19571)) +* resource/aws_devicefarm_project: Add `default_job_timeout_minutes` and `tags` argument ([#19574](https://github.com/hashicorp/terraform-provider-aws/issues/19574)) +* resource/aws_devicefarm_project: Add plan time validation for `name` ([#19574](https://github.com/hashicorp/terraform-provider-aws/issues/19574)) +* resource/aws_fsx_lustre_filesystem: Allow updating `storage_capacity`. ([#19568](https://github.com/hashicorp/terraform-provider-aws/issues/19568)) BUG FIXES: * resource/aws_elasticache_cluster: Fix provider-level `default_tags` support for resource ([#19615](https://github.com/hashicorp/terraform-provider-aws/issues/19615)) +* resource/aws_iam_access_key: Fix status not defaulting to Active ([#19606](https://github.com/hashicorp/terraform-provider-aws/issues/19606)) ## 3.43.0 (June 01, 2021) From 2099b32b02715650a85117d43cd30ef286677271 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 11:28:50 -0400 Subject: [PATCH 0150/1208] r/servicecat_princ_port_assoc: New resource --- ...catalog_principal_portfolio_association.go | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_principal_portfolio_association.go diff --git a/aws/resource_aws_servicecatalog_principal_portfolio_association.go b/aws/resource_aws_servicecatalog_principal_portfolio_association.go new file mode 100644 index 000000000000..07d32199b92f --- /dev/null +++ b/aws/resource_aws_servicecatalog_principal_portfolio_association.go @@ -0,0 +1,185 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func resourceAwsServiceCatalogPrincipalPortfolioAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsServiceCatalogPrincipalPortfolioAssociationCreate, + Read: resourceAwsServiceCatalogPrincipalPortfolioAssociationRead, + Delete: resourceAwsServiceCatalogPrincipalPortfolioAssociationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "accept_language": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "en", + ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), + }, + "portfolio_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "principal_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "principal_unique_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "principal_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: servicecatalog.PrincipalTypeIam, + ValidateFunc: validation.StringInSlice(servicecatalog.PrincipalType_Values(), false), + }, + }, + } +} + +func resourceAwsServiceCatalogPrincipalPortfolioAssociationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + input := &servicecatalog.AssociatePrincipalWithPortfolioInput{ + PortfolioId: aws.String(d.Get("portfolio_id").(string)), + PrincipalARN: aws.String(d.Get("principal_arn").(string)), + } + + if v, ok := d.GetOk("accept_language"); ok { + input.AcceptLanguage = aws.String(v.(string)) + } + + if v, ok := d.GetOk("principal_type"); ok { + input.PrincipalType = aws.String(v.(string)) + } + + var output *servicecatalog.AssociatePrincipalWithPortfolioOutput + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + var err error + + output, err = conn.AssociatePrincipalWithPortfolio(input) + + if tfawserr.ErrMessageContains(err, servicecatalog.ErrCodeInvalidParametersException, "profile does not exist") { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + output, err = conn.AssociatePrincipalWithPortfolio(input) + } + + if err != nil { + return fmt.Errorf("error associating Service Catalog Principal with Portfolio: %w", err) + } + + if output == nil { + return fmt.Errorf("error creating Service Catalog Principal Portfolio Association: empty response") + } + + d.SetId(tfservicecatalog.PrincipalPortfolioAssociationID(d.Get("accept_language").(string), d.Get("principal_arn").(string), d.Get("portfolio_id").(string))) + + return resourceAwsServiceCatalogPrincipalPortfolioAssociationRead(d, meta) +} + +func resourceAwsServiceCatalogPrincipalPortfolioAssociationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + acceptLanguage, principalARN, portfolioID, err := tfservicecatalog.PrincipalPortfolioAssociationParseID(d.Id()) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", d.Id(), err) + } + + if acceptLanguage == "" { + acceptLanguage = tfservicecatalog.ServiceCatalogAcceptLanguageEnglish + } + + output, err := waiter.PrincipalPortfolioAssociationReady(conn, acceptLanguage, principalARN, portfolioID) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Service Catalog Principal Portfolio Association (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error describing Service Catalog Principal Portfolio Association (%s): %w", d.Id(), err) + } + + if output == nil { + return fmt.Errorf("error getting Service Catalog Principal Portfolio Association (%s): empty response", d.Id()) + } + + d.Set("accept_language", acceptLanguage) + d.Set("portfolio_id", portfolioID) + d.Set("principal_arn", output.PrincipalARN) + d.Set("principal_type", output.PrincipalType) + + return nil +} + +func resourceAwsServiceCatalogPrincipalPortfolioAssociationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + acceptLanguage, principalARN, portfolioID, err := tfservicecatalog.PrincipalPortfolioAssociationParseID(d.Id()) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", d.Id(), err) + } + + if acceptLanguage == "" { + acceptLanguage = tfservicecatalog.ServiceCatalogAcceptLanguageEnglish + } + + input := &servicecatalog.DisassociatePrincipalFromPortfolioInput{ + PortfolioId: aws.String(portfolioID), + PrincipalARN: aws.String(principalARN), + AcceptLanguage: aws.String(acceptLanguage), + } + + _, err = conn.DisassociatePrincipalFromPortfolio(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return fmt.Errorf("error disassociating Service Catalog Principal from Portfolio (%s): %w", d.Id(), err) + } + + err = waiter.PrincipalPortfolioAssociationDeleted(conn, acceptLanguage, principalARN, portfolioID) + + if err != nil && !tfresource.NotFound(err) { + return fmt.Errorf("error waiting for Service Catalog Principal Portfolio Disassociation (%s): %w", d.Id(), err) + } + + return nil +} From ccfcbf1bba5868ad76d1bfed78d2c92a9b7ba275 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 11:29:43 -0400 Subject: [PATCH 0151/1208] tests/r/servicecat_princ_port_assoc: New resource --- ...og_principal_portfolio_association_test.go | 237 ++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_principal_portfolio_association_test.go diff --git a/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go b/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go new file mode 100644 index 000000000000..86efcdc56b83 --- /dev/null +++ b/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go @@ -0,0 +1,237 @@ +package aws + +import ( + "fmt" + "log" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/servicecatalog" + multierror "github.com/hashicorp/go-multierror" + "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" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +// add sweeper to delete known test servicecat principal portfolio associations +func init() { + resource.AddTestSweepers("aws_servicecatalog_principal_portfolio_association", &resource.Sweeper{ + Name: "aws_servicecatalog_principal_portfolio_association", + Dependencies: []string{}, + F: testSweepServiceCatalogPrincipalPortfolioAssociations, + }) +} + +func testSweepServiceCatalogPrincipalPortfolioAssociations(region string) error { + client, err := sharedClientForRegion(region) + + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + + conn := client.(*AWSClient).scconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + + input := &servicecatalog.ListPortfoliosInput{} + + err = conn.ListPortfoliosPages(input, func(page *servicecatalog.ListPortfoliosOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, detail := range page.PortfolioDetails { + if detail == nil { + continue + } + + pInput := &servicecatalog.ListPrincipalsForPortfolioInput{ + PortfolioId: detail.Id, + } + + err = conn.ListPrincipalsForPortfolioPages(pInput, func(page *servicecatalog.ListPrincipalsForPortfolioOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, principal := range page.Principals { + if principal == nil { + continue + } + + r := resourceAwsServiceCatalogPrincipalPortfolioAssociation() + d := r.Data(nil) + d.SetId(tfservicecatalog.PrincipalPortfolioAssociationID("en", aws.StringValue(principal.PrincipalARN), aws.StringValue(detail.Id))) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing Service Catalog Portfolios for Principals %s: %w", region, err)) + continue + } + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing Service Catalog Principal Portfolio Associations for %s: %w", region, err)) + } + + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Service Catalog Principal Portfolio Associations for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping Service Catalog Principal Portfolio Associations sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} + +func TestAccAWSServiceCatalogPrincipalPortfolioAssociation_basic(t *testing.T) { + resourceName := "aws_servicecatalog_principal_portfolio_association.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogPrincipalPortfolioAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogPrincipalPortfolioAssociationConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogPrincipalPortfolioAssociationExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "portfolio_id", "aws_servicecatalog_portfolio.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "principal_arn", "aws_servicecatalog_principal.test", "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSServiceCatalogPrincipalPortfolioAssociation_disappears(t *testing.T) { + resourceName := "aws_servicecatalog_principal_portfolio_association.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogPrincipalPortfolioAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogPrincipalPortfolioAssociationConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogPrincipalPortfolioAssociationExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsServiceCatalogPrincipalPortfolioAssociation(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAwsServiceCatalogPrincipalPortfolioAssociationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).scconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_servicecatalog_principal_portfolio_association" { + continue + } + + acceptLanguage, principalARN, portfolioID, err := tfservicecatalog.PrincipalPortfolioAssociationParseID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", rs.Primary.ID, err) + } + + err = waiter.PrincipalPortfolioAssociationDeleted(conn, acceptLanguage, principalARN, portfolioID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return fmt.Errorf("waiting for Service Catalog Principal Portfolio Association to be destroyed (%s): %w", rs.Primary.ID, err) + } + } + + return nil +} + +func testAccCheckAwsServiceCatalogPrincipalPortfolioAssociationExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + + if !ok { + return fmt.Errorf("resource not found: %s", resourceName) + } + + acceptLanguage, principalARN, portfolioID, err := tfservicecatalog.PrincipalPortfolioAssociationParseID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("could not parse ID (%s): %w", rs.Primary.ID, err) + } + + conn := testAccProvider.Meta().(*AWSClient).scconn + + _, err = waiter.PrincipalPortfolioAssociationReady(conn, acceptLanguage, principalARN, portfolioID) + + if err != nil { + return fmt.Errorf("waiting for Service Catalog Principal Portfolio Association existence (%s): %w", rs.Primary.ID, err) + } + + return nil + } +} + +func testAccAWSServiceCatalogPrincipalPortfolioAssociationConfig_base(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "servicecatalog.${data.aws_partition.current.dns_suffix}" + } + Sid = "" + }] + }) +} + +resource "aws_servicecatalog_portfolio" "test" { + name = %[1]q + provider_name = %[1]q +} +`, rName) +} + +func testAccAWSServiceCatalogPrincipalPortfolioAssociationConfig_basic(rName string) string { + return composeConfig(testAccAWSServiceCatalogPrincipalPortfolioAssociationConfig_base(rName), ` +resource "aws_servicecatalog_principal_portfolio_association" "test" { + portfolio_id = aws_servicecatalog_portfolio.test.id + principal_arn = aws_iam_role.test.unique_id +} +`) +} From 1d171d31cb7c11408bbc49776e77d13bb44b1424 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 11:30:03 -0400 Subject: [PATCH 0152/1208] docs/r/servicecat_princ_port_assoc: New resource --- ...ncipal_portfolio_association.html.markdown | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 website/docs/r/servicecatalog_principal_portfolio_association.html.markdown diff --git a/website/docs/r/servicecatalog_principal_portfolio_association.html.markdown b/website/docs/r/servicecatalog_principal_portfolio_association.html.markdown new file mode 100644 index 000000000000..90c537123506 --- /dev/null +++ b/website/docs/r/servicecatalog_principal_portfolio_association.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_principal_portfolio_association" +description: |- + Manages a Service Catalog Principal Portfolio Association +--- + +# Resource: aws_servicecatalog_principal_portfolio_association + +Manages a Service Catalog Principal Portfolio Association. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_servicecatalog_principal_portfolio_association" "example" { + portfolio_id = "port-68656c6c6f" + principal_arn = "arn:aws:iam::123456789012:user/Eleanor" +} +``` + +## Argument Reference + +The following arguments are required: + +* `portfolio_id` - (Required) Portfolio identifier. +* `principal_arn` - (Required) Principal ARN. + +The following arguments are optional: + +* `accept_language` - (Optional) Language code. Valid values: `en` (English), `jp` (Japanese), `zh` (Chinese). Default value is `en`. +* `principal_type` - (Optional) Principal type. Setting this argument empty (e.g., `principal_type = ""`) will result in an error. Valid value is `IAM`. Default is `IAM`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - Identifier of the association. + +## Import + +`aws_servicecatalog_principal_portfolio_association` can be imported using the accept language, principal ARN, and portfolio ID, separated by a comma, e.g. + +``` +$ terraform import aws_servicecatalog_principal_portfolio_association.example en,arn:aws:iam::123456789012:user/Eleanor,port-68656c6c6f +``` From e5c04a9fefa50746887b880bd49bff8390bfbc35 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 11:30:20 -0400 Subject: [PATCH 0153/1208] provider: Add new resource --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index 8cdb9f540662..4a1bd2fbeaa9 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1040,6 +1040,7 @@ func Provider() *schema.Provider { "aws_servicecatalog_service_action": resourceAwsServiceCatalogServiceAction(), "aws_servicecatalog_tag_option": resourceAwsServiceCatalogTagOption(), "aws_servicecatalog_tag_option_resource_association": resourceAwsServiceCatalogTagOptionResourceAssociation(), + "aws_servicecatalog_principal_portfolio_association": resourceAwsServiceCatalogPrincipalPortfolioAssociation(), "aws_servicecatalog_product_portfolio_association": resourceAwsServiceCatalogProductPortfolioAssociation(), "aws_servicecatalog_provisioning_artifact": resourceAwsServiceCatalogProvisioningArtifact(), "aws_service_discovery_http_namespace": resourceAwsServiceDiscoveryHttpNamespace(), From 48328795dae648743c8d9968a3f9679054ed5ae6 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 11:31:20 -0400 Subject: [PATCH 0154/1208] r/servicecat: Add finder --- .../service/servicecatalog/finder/finder.go | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/aws/internal/service/servicecatalog/finder/finder.go b/aws/internal/service/servicecatalog/finder/finder.go index 791578044793..d433eeb44b2a 100644 --- a/aws/internal/service/servicecatalog/finder/finder.go +++ b/aws/internal/service/servicecatalog/finder/finder.go @@ -1,6 +1,7 @@ package finder import ( + "fmt" "strings" "github.com/aws/aws-sdk-go/aws" @@ -127,3 +128,44 @@ func TagOptionResourceAssociation(conn *servicecatalog.ServiceCatalog, tagOption return result, err } + +func PrincipalPortfolioAssociation(conn *servicecatalog.ServiceCatalog, acceptLanguage, principalARN, portfolioID string) (*servicecatalog.Principal, error) { + input := &servicecatalog.ListPrincipalsForPortfolioInput{ + PortfolioId: aws.String(portfolioID), + } + + if acceptLanguage != "" { + input.AcceptLanguage = aws.String(acceptLanguage) + } + + arns := make([]string, 3) + + var result *servicecatalog.Principal + + err := conn.ListPrincipalsForPortfolioPages(input, func(page *servicecatalog.ListPrincipalsForPortfolioOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, deet := range page.Principals { + if deet == nil { + continue + } + + arns = append(arns, aws.StringValue(deet.PrincipalARN)) + + if aws.StringValue(deet.PrincipalARN) == principalARN { + result = deet + return false + } + } + + return !lastPage + }) + + if true { + return nil, fmt.Errorf("wut?? %v\narn: %s\narns: %v", input, principalARN, arns) + } + + return result, err +} From 2f05b0b3f5b41a2faae7a3d1db015e0a35ac2fe2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 11:31:57 -0400 Subject: [PATCH 0155/1208] i/r/servicecat: Add ID funcs for new resource --- aws/internal/service/servicecatalog/id.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/aws/internal/service/servicecatalog/id.go b/aws/internal/service/servicecatalog/id.go index 03a7f4ef7fe6..3eb0a6f8a418 100644 --- a/aws/internal/service/servicecatalog/id.go +++ b/aws/internal/service/servicecatalog/id.go @@ -73,3 +73,17 @@ func ProvisioningArtifactParseID(id string) (string, string, error) { } return parts[0], parts[1], nil } + +func PrincipalPortfolioAssociationParseID(id string) (string, string, string, error) { + parts := strings.SplitN(id, ",", 3) + + if len(parts) != 3 || parts[0] == "" || parts[1] == "" || parts[2] == "" { + return "", "", "", fmt.Errorf("unexpected format of ID (%s), expected acceptLanguage,principalARN,portfolioID", id) + } + + return parts[0], parts[1], parts[2], nil +} + +func PrincipalPortfolioAssociationID(acceptLanguage, principalARN, portfolioID string) string { + return strings.Join([]string{acceptLanguage, principalARN, portfolioID}, ",") +} From d5721e774312c6f2605d049fb7cdf97ecf667b36 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 21 May 2021 11:32:19 -0400 Subject: [PATCH 0156/1208] i/r/servicecat: Add waiter for new resource --- .../service/servicecatalog/waiter/status.go | 24 ++++++++++++++ .../service/servicecatalog/waiter/waiter.go | 33 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/aws/internal/service/servicecatalog/waiter/status.go b/aws/internal/service/servicecatalog/waiter/status.go index 371aa8c8aa5c..ca3b480309c8 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -299,3 +299,27 @@ func ProvisioningArtifactStatus(conn *servicecatalog.ServiceCatalog, id, product return output, aws.StringValue(output.Status), err } } + +func PrincipalPortfolioAssociationStatus(conn *servicecatalog.ServiceCatalog, acceptLanguage, principalARN, portfolioID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.PrincipalPortfolioAssociation(conn, acceptLanguage, principalARN, portfolioID) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil, StatusNotFound, &resource.NotFoundError{ + Message: fmt.Sprintf("principal portfolio association not found (%s): %s", tfservicecatalog.PrincipalPortfolioAssociationID(acceptLanguage, principalARN, portfolioID), err), + } + } + + if err != nil { + return nil, servicecatalog.StatusFailed, fmt.Errorf("error describing principal portfolio association: %w", err) + } + + if output == nil { + return nil, StatusNotFound, &resource.NotFoundError{ + Message: fmt.Sprintf("finding principal portfolio association (%s): empty response", tfservicecatalog.PrincipalPortfolioAssociationID(acceptLanguage, principalARN, portfolioID)), + } + } + + return output, servicecatalog.StatusAvailable, err + } +} diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index 8374a859dbd1..e4df4eefc6da 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -38,6 +38,9 @@ const ( ProvisioningArtifactReadyTimeout = 3 * time.Minute ProvisioningArtifactDeletedTimeout = 3 * time.Minute + PrincipalPortfolioAssociationReadyTimeout = 3 * time.Minute + PrincipalPortfolioAssociationDeleteTimeout = 3 * time.Minute + StatusNotFound = "NOT_FOUND" StatusUnavailable = "UNAVAILABLE" @@ -407,3 +410,33 @@ func ProvisioningArtifactDeleted(conn *servicecatalog.ServiceCatalog, id, produc return nil } + +func PrincipalPortfolioAssociationReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, principalARN, portfolioID string) (*servicecatalog.Principal, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusNotFound, StatusUnavailable}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: PrincipalPortfolioAssociationStatus(conn, acceptLanguage, principalARN, portfolioID), + Timeout: PrincipalPortfolioAssociationReadyTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*servicecatalog.Principal); ok { + return output, err + } + + return nil, err +} + +func PrincipalPortfolioAssociationDeleted(conn *servicecatalog.ServiceCatalog, acceptLanguage, principalARN, portfolioID string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{servicecatalog.StatusAvailable}, + Target: []string{StatusNotFound, StatusUnavailable}, + Refresh: PrincipalPortfolioAssociationStatus(conn, acceptLanguage, principalARN, portfolioID), + Timeout: PrincipalPortfolioAssociationDeleteTimeout, + } + + _, err := stateConf.WaitForState() + + return err +} From aa01528a1094a8a96f1d90559107cf18e193b65c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 1 Jun 2021 15:48:12 -0400 Subject: [PATCH 0157/1208] i/servicecat_principal_portfolio_assoc: Remove debug --- aws/internal/service/servicecatalog/finder/finder.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/aws/internal/service/servicecatalog/finder/finder.go b/aws/internal/service/servicecatalog/finder/finder.go index d433eeb44b2a..0cf7c7496b82 100644 --- a/aws/internal/service/servicecatalog/finder/finder.go +++ b/aws/internal/service/servicecatalog/finder/finder.go @@ -1,7 +1,6 @@ package finder import ( - "fmt" "strings" "github.com/aws/aws-sdk-go/aws" @@ -138,8 +137,6 @@ func PrincipalPortfolioAssociation(conn *servicecatalog.ServiceCatalog, acceptLa input.AcceptLanguage = aws.String(acceptLanguage) } - arns := make([]string, 3) - var result *servicecatalog.Principal err := conn.ListPrincipalsForPortfolioPages(input, func(page *servicecatalog.ListPrincipalsForPortfolioOutput, lastPage bool) bool { @@ -152,8 +149,6 @@ func PrincipalPortfolioAssociation(conn *servicecatalog.ServiceCatalog, acceptLa continue } - arns = append(arns, aws.StringValue(deet.PrincipalARN)) - if aws.StringValue(deet.PrincipalARN) == principalARN { result = deet return false @@ -163,9 +158,5 @@ func PrincipalPortfolioAssociation(conn *servicecatalog.ServiceCatalog, acceptLa return !lastPage }) - if true { - return nil, fmt.Errorf("wut?? %v\narn: %s\narns: %v", input, principalARN, arns) - } - return result, err } From dbefaed95b14339ab654e6ae493851d4e0d54a58 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 1 Jun 2021 15:49:01 -0400 Subject: [PATCH 0158/1208] i/servicecat_princ_port_assoc: Rework not found errors --- aws/internal/service/servicecatalog/waiter/status.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/aws/internal/service/servicecatalog/waiter/status.go b/aws/internal/service/servicecatalog/waiter/status.go index ca3b480309c8..338e821b70b4 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -305,9 +305,7 @@ func PrincipalPortfolioAssociationStatus(conn *servicecatalog.ServiceCatalog, ac output, err := finder.PrincipalPortfolioAssociation(conn, acceptLanguage, principalARN, portfolioID) if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { - return nil, StatusNotFound, &resource.NotFoundError{ - Message: fmt.Sprintf("principal portfolio association not found (%s): %s", tfservicecatalog.PrincipalPortfolioAssociationID(acceptLanguage, principalARN, portfolioID), err), - } + return nil, StatusNotFound, err } if err != nil { @@ -315,9 +313,7 @@ func PrincipalPortfolioAssociationStatus(conn *servicecatalog.ServiceCatalog, ac } if output == nil { - return nil, StatusNotFound, &resource.NotFoundError{ - Message: fmt.Sprintf("finding principal portfolio association (%s): empty response", tfservicecatalog.PrincipalPortfolioAssociationID(acceptLanguage, principalARN, portfolioID)), - } + return nil, StatusNotFound, err } return output, servicecatalog.StatusAvailable, err From 2873244c954c9cc5c1047c8bd1979813f515a29d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 1 Jun 2021 15:49:44 -0400 Subject: [PATCH 0159/1208] i/servicecat_princ_port_assoc: Rework not found errors --- .../service/servicecatalog/waiter/waiter.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index e4df4eefc6da..b388ff87ff66 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -413,10 +413,12 @@ func ProvisioningArtifactDeleted(conn *servicecatalog.ServiceCatalog, id, produc func PrincipalPortfolioAssociationReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, principalARN, portfolioID string) (*servicecatalog.Principal, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{StatusNotFound, StatusUnavailable}, - Target: []string{servicecatalog.StatusAvailable}, - Refresh: PrincipalPortfolioAssociationStatus(conn, acceptLanguage, principalARN, portfolioID), - Timeout: PrincipalPortfolioAssociationReadyTimeout, + Pending: []string{StatusNotFound, StatusUnavailable}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: PrincipalPortfolioAssociationStatus(conn, acceptLanguage, principalARN, portfolioID), + Timeout: PrincipalPortfolioAssociationReadyTimeout, + NotFoundChecks: 5, + MinTimeout: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -430,10 +432,11 @@ func PrincipalPortfolioAssociationReady(conn *servicecatalog.ServiceCatalog, acc func PrincipalPortfolioAssociationDeleted(conn *servicecatalog.ServiceCatalog, acceptLanguage, principalARN, portfolioID string) error { stateConf := &resource.StateChangeConf{ - Pending: []string{servicecatalog.StatusAvailable}, - Target: []string{StatusNotFound, StatusUnavailable}, - Refresh: PrincipalPortfolioAssociationStatus(conn, acceptLanguage, principalARN, portfolioID), - Timeout: PrincipalPortfolioAssociationDeleteTimeout, + Pending: []string{servicecatalog.StatusAvailable}, + Target: []string{StatusNotFound, StatusUnavailable}, + Refresh: PrincipalPortfolioAssociationStatus(conn, acceptLanguage, principalARN, portfolioID), + Timeout: PrincipalPortfolioAssociationDeleteTimeout, + NotFoundChecks: 1, } _, err := stateConf.WaitForState() From 02feeca0b3a0225e58bc303d53eec51b16bbca69 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 1 Jun 2021 15:50:57 -0400 Subject: [PATCH 0160/1208] tests/r/servicecat_prin_port_assoc: Fix tests --- ..._servicecatalog_principal_portfolio_association_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go b/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go index 86efcdc56b83..78996e59c324 100644 --- a/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go +++ b/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go @@ -7,6 +7,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -112,7 +113,7 @@ func TestAccAWSServiceCatalogPrincipalPortfolioAssociation_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogPrincipalPortfolioAssociationExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "portfolio_id", "aws_servicecatalog_portfolio.test", "id"), - resource.TestCheckResourceAttrPair(resourceName, "principal_arn", "aws_servicecatalog_principal.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "principal_arn", "aws_iam_role.test", "arn"), ), }, { @@ -162,7 +163,7 @@ func testAccCheckAwsServiceCatalogPrincipalPortfolioAssociationDestroy(s *terraf err = waiter.PrincipalPortfolioAssociationDeleted(conn, acceptLanguage, principalARN, portfolioID) - if tfresource.NotFound(err) { + if tfresource.NotFound(err) || tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { continue } @@ -231,7 +232,7 @@ func testAccAWSServiceCatalogPrincipalPortfolioAssociationConfig_basic(rName str return composeConfig(testAccAWSServiceCatalogPrincipalPortfolioAssociationConfig_base(rName), ` resource "aws_servicecatalog_principal_portfolio_association" "test" { portfolio_id = aws_servicecatalog_portfolio.test.id - principal_arn = aws_iam_role.test.unique_id + principal_arn = aws_iam_role.test.arn } `) } From 67e36644908557088b40ba75338fece6aba37de8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 1 Jun 2021 15:51:27 -0400 Subject: [PATCH 0161/1208] r/servicecat_prin_port_assoc: Rework not found handling --- ...catalog_principal_portfolio_association.go | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_servicecatalog_principal_portfolio_association.go b/aws/resource_aws_servicecatalog_principal_portfolio_association.go index 07d32199b92f..69db6453856c 100644 --- a/aws/resource_aws_servicecatalog_principal_portfolio_association.go +++ b/aws/resource_aws_servicecatalog_principal_portfolio_association.go @@ -43,11 +43,13 @@ func resourceAwsServiceCatalogPrincipalPortfolioAssociation() *schema.Resource { Required: true, ForceNew: true, }, - "principal_unique_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, + /* + "principal_unique_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + */ "principal_type": { Type: schema.TypeString, Optional: true, @@ -124,7 +126,7 @@ func resourceAwsServiceCatalogPrincipalPortfolioAssociationRead(d *schema.Resour output, err := waiter.PrincipalPortfolioAssociationReady(conn, acceptLanguage, principalARN, portfolioID) - if !d.IsNewResource() && tfresource.NotFound(err) { + if !d.IsNewResource() && (tfresource.NotFound(err) || tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException)) { log.Printf("[WARN] Service Catalog Principal Portfolio Association (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -177,7 +179,11 @@ func resourceAwsServiceCatalogPrincipalPortfolioAssociationDelete(d *schema.Reso err = waiter.PrincipalPortfolioAssociationDeleted(conn, acceptLanguage, principalARN, portfolioID) - if err != nil && !tfresource.NotFound(err) { + if tfresource.NotFound(err) || tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { return fmt.Errorf("error waiting for Service Catalog Principal Portfolio Disassociation (%s): %w", d.Id(), err) } From 6fac1a8899d9bc7143d7d4f597840dfcc725d0e7 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 1 Jun 2021 16:09:43 -0400 Subject: [PATCH 0162/1208] r/servicecat_principal_port_assoc: Remove extraneous argument --- ...e_aws_servicecatalog_principal_portfolio_association.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/aws/resource_aws_servicecatalog_principal_portfolio_association.go b/aws/resource_aws_servicecatalog_principal_portfolio_association.go index 69db6453856c..369265f30100 100644 --- a/aws/resource_aws_servicecatalog_principal_portfolio_association.go +++ b/aws/resource_aws_servicecatalog_principal_portfolio_association.go @@ -43,13 +43,6 @@ func resourceAwsServiceCatalogPrincipalPortfolioAssociation() *schema.Resource { Required: true, ForceNew: true, }, - /* - "principal_unique_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - */ "principal_type": { Type: schema.TypeString, Optional: true, From d61ea81c079ca66632bb70174a0bf170f18ae126 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 10:50:22 -0400 Subject: [PATCH 0163/1208] r/servicecat_principal_port_assoc: Use enum --- ...source_aws_servicecatalog_principal_portfolio_association.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_principal_portfolio_association.go b/aws/resource_aws_servicecatalog_principal_portfolio_association.go index 369265f30100..546cff586229 100644 --- a/aws/resource_aws_servicecatalog_principal_portfolio_association.go +++ b/aws/resource_aws_servicecatalog_principal_portfolio_association.go @@ -30,7 +30,7 @@ func resourceAwsServiceCatalogPrincipalPortfolioAssociation() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - Default: "en", + Default: tfservicecatalog.ServiceCatalogAcceptLanguageEnglish, ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, "portfolio_id": { From f904e0590c6c57c09ee4df7635cecd2041be8863 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 11:06:50 -0400 Subject: [PATCH 0164/1208] r/aws_amplify_branch: Test 'backend_environment_arn'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplify_serial/Branch/BackendEnvironmentArn' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplify_serial/Branch/BackendEnvironmentArn -timeout 180m === RUN TestAccAWSAmplify_serial === RUN TestAccAWSAmplify_serial/Branch === RUN TestAccAWSAmplify_serial/Branch/BackendEnvironmentArn === PAUSE TestAccAWSAmplify_serial/Branch/BackendEnvironmentArn === CONT TestAccAWSAmplify_serial/Branch/BackendEnvironmentArn --- PASS: TestAccAWSAmplify_serial (28.27s) --- PASS: TestAccAWSAmplify_serial/Branch (0.00s) --- PASS: TestAccAWSAmplify_serial/Branch/BackendEnvironmentArn (28.27s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 31.532s --- ...ce_aws_amplify_backend_environment_test.go | 2 - aws/resource_aws_amplify_branch.go | 10 +-- aws/resource_aws_amplify_branch_test.go | 65 ++++++------------- 3 files changed, 21 insertions(+), 56 deletions(-) diff --git a/aws/resource_aws_amplify_backend_environment_test.go b/aws/resource_aws_amplify_backend_environment_test.go index 0faf353cb9f3..5d5e6c63596d 100644 --- a/aws/resource_aws_amplify_backend_environment_test.go +++ b/aws/resource_aws_amplify_backend_environment_test.go @@ -103,8 +103,6 @@ func testAccAWSAmplifyBackendEnvironment_DeploymentArtifacts_StackName(t *testin }) } -// testAccAWSAmplifyBackendEnvironmentConfigDeploymentArtifactsAndStackName(rname, environmentName) - func testAccCheckAWSAmplifyBackendEnvironmentExists(resourceName string, v *amplify.BackendEnvironment) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] diff --git a/aws/resource_aws_amplify_branch.go b/aws/resource_aws_amplify_branch.go index b6aecd4fb157..9fd82bd106ad 100644 --- a/aws/resource_aws_amplify_branch.go +++ b/aws/resource_aws_amplify_branch.go @@ -1,7 +1,6 @@ package aws import ( - "context" "fmt" "log" "regexp" @@ -9,7 +8,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "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" @@ -28,13 +26,7 @@ func resourceAwsAmplifyBranch() *schema.Resource { State: schema.ImportStatePassthrough, }, - CustomizeDiff: customdiff.Sequence( - SetTagsDiff, - customdiff.ForceNewIfChange("backend_environment_arn", func(_ context.Context, old, new, meta interface{}) bool { - // Any existing value cannot be cleared. - return new.(string) == "" - }), - ), + CustomizeDiff: SetTagsDiff, Schema: map[string]*schema.Schema{ "app_id": { diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index 72f8704e0d8e..4f5cef5185e6 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -5,7 +5,6 @@ import ( "regexp" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -132,12 +131,12 @@ func testAccAWSAmplifyBranch_Tags(t *testing.T) { } func testAccAWSAmplifyBranch_BackendEnvironmentArn(t *testing.T) { - var branch1, branch2, branch3 amplify.Branch + var branch amplify.Branch rName := acctest.RandomWithPrefix("tf-acc-test") - environmentName1 := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) - environmentName2 := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) + environmentName := acctest.RandStringFromCharSet(9, acctest.CharSetAlpha) resourceName := "aws_amplify_branch.test" - backendEnvironmentResourceName := "aws_amplify_backend_environment.test" + backendEnvironment1ResourceName := "aws_amplify_backend_environment.test1" + backendEnvironment2ResourceName := "aws_amplify_backend_environment.test2" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, @@ -146,10 +145,10 @@ func testAccAWSAmplifyBranch_BackendEnvironmentArn(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName1), + Config: testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName, 1), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyBranchExists(resourceName, &branch1), - resource.TestCheckResourceAttrPair(resourceName, "backend_environment_arn", backendEnvironmentResourceName, "arn"), + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttrPair(resourceName, "backend_environment_arn", backendEnvironment1ResourceName, "arn"), ), }, { @@ -158,19 +157,10 @@ func testAccAWSAmplifyBranch_BackendEnvironmentArn(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName2), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyBranchExists(resourceName, &branch2), - testAccCheckAWSAmplifyBranchNotRecreated(&branch1, &branch2), - resource.TestCheckResourceAttrPair(resourceName, "backend_environment_arn", backendEnvironmentResourceName, "arn"), - ), - }, - { - Config: testAccAWSAmplifyBranchConfigName(rName), + Config: testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName, 2), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyBranchExists(resourceName, &branch3), - testAccCheckAWSAmplifyBranchRecreated(&branch2, &branch3), - resource.TestCheckResourceAttr(resourceName, "backend_environment_arn", ""), + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttrPair(resourceName, "backend_environment_arn", backendEnvironment2ResourceName, "arn"), ), }, }, @@ -434,26 +424,6 @@ func testAccCheckAWSAmplifyBranchDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSAmplifyBranchNotRecreated(before, after *amplify.Branch) resource.TestCheckFunc { - return func(s *terraform.State) error { - if before, after := aws.TimeValue(before.CreateTime), aws.TimeValue(after.CreateTime); before != after { - return fmt.Errorf("Amplify Branch (%s/%s) recreated", before, after) - } - - return nil - } -} - -func testAccCheckAWSAmplifyBranchRecreated(before, after *amplify.Branch) resource.TestCheckFunc { - return func(s *terraform.State) error { - if before, after := aws.TimeValue(before.CreateTime), aws.TimeValue(after.CreateTime); before == after { - return fmt.Errorf("Amplify Branch (%s) not recreated", before) - } - - return nil - } -} - func testAccAWSAmplifyBranchConfigName(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { @@ -502,24 +472,29 @@ resource "aws_amplify_branch" "test" { `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } -func testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName string) string { +func testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName string, index int) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { name = %[1]q } -resource "aws_amplify_backend_environment" "test" { +resource "aws_amplify_backend_environment" "test1" { app_id = aws_amplify_app.test.id - environment_name = %[2]q + environment_name = "%[2]sa" +} + +resource "aws_amplify_backend_environment" "test2" { + app_id = aws_amplify_app.test.id + environment_name = "%[2]sb" } resource "aws_amplify_branch" "test" { app_id = aws_amplify_app.test.id branch_name = %[1]q - backend_environment_arn = aws_amplify_backend_environment.test.arn + backend_environment_arn = aws_amplify_backend_environment.test%[3]d.arn } -`, rName, environmentName) +`, rName, environmentName, index) } /* From b1c114b240dd6affb2dc98763f27866f56815c94 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:21:03 -0400 Subject: [PATCH 0165/1208] r/servicecat_prin_port_assoc: Changelog --- .changelog/19470.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19470.txt diff --git a/.changelog/19470.txt b/.changelog/19470.txt new file mode 100644 index 000000000000..6d33e3739695 --- /dev/null +++ b/.changelog/19470.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_servicecatalog_principal_portfolio_association +``` \ No newline at end of file From 2f2e90523eee0c1701ada7045c2af762481711a7 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:21:32 -0400 Subject: [PATCH 0166/1208] i/servicecat: Refactor enum --- aws/internal/service/servicecatalog/enum.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/internal/service/servicecatalog/enum.go b/aws/internal/service/servicecatalog/enum.go index d8b8db7bc8ec..90f3ea3ccfed 100644 --- a/aws/internal/service/servicecatalog/enum.go +++ b/aws/internal/service/servicecatalog/enum.go @@ -3,9 +3,9 @@ package servicecatalog const ( // If AWS adds these to the API, we should use those and remove these. - ServiceCatalogAcceptLanguageEnglish = "en" - ServiceCatalogAcceptLanguageJapanese = "jp" - ServiceCatalogAcceptLanguageChinese = "zh" + AcceptLanguageEnglish = "en" + AcceptLanguageJapanese = "jp" + AcceptLanguageChinese = "zh" ConstraintTypeLaunch = "LAUNCH" ConstraintTypeNotification = "NOTIFICATION" @@ -16,9 +16,9 @@ const ( func AcceptLanguage_Values() []string { return []string{ - ServiceCatalogAcceptLanguageEnglish, - ServiceCatalogAcceptLanguageJapanese, - ServiceCatalogAcceptLanguageChinese, + AcceptLanguageEnglish, + AcceptLanguageJapanese, + AcceptLanguageChinese, } } From 3632d3c3d2b36ce9cd5195ac8895d4559358f7ca Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:22:18 -0400 Subject: [PATCH 0167/1208] ds/servicecat_constraint: Refactor enum --- aws/data_source_aws_servicecatalog_constraint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/data_source_aws_servicecatalog_constraint.go b/aws/data_source_aws_servicecatalog_constraint.go index 71e2a863782e..a8b29de52c5e 100644 --- a/aws/data_source_aws_servicecatalog_constraint.go +++ b/aws/data_source_aws_servicecatalog_constraint.go @@ -18,7 +18,7 @@ func dataSourceAwsServiceCatalogConstraint() *schema.Resource { "accept_language": { Type: schema.TypeString, Optional: true, - Default: "en", + Default: tfservicecatalog.AcceptLanguageEnglish, ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, "description": { From b3a75ba8371aef43c7e9c3b4700297329e59b440 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:23:32 -0400 Subject: [PATCH 0168/1208] r/servicecat_constraint: Refactor enum --- aws/resource_aws_servicecatalog_constraint.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_servicecatalog_constraint.go b/aws/resource_aws_servicecatalog_constraint.go index 6bc38d756ed5..730a57020da4 100644 --- a/aws/resource_aws_servicecatalog_constraint.go +++ b/aws/resource_aws_servicecatalog_constraint.go @@ -30,7 +30,7 @@ func resourceAwsServiceCatalogConstraint() *schema.Resource { "accept_language": { Type: schema.TypeString, Optional: true, - Default: "en", + Default: tfservicecatalog.AcceptLanguageEnglish, ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, "description": { @@ -151,7 +151,7 @@ func resourceAwsServiceCatalogConstraintRead(d *schema.ResourceData, meta interf acceptLanguage := d.Get("accept_language").(string) if acceptLanguage == "" { - acceptLanguage = "en" + acceptLanguage = tfservicecatalog.AcceptLanguageEnglish } d.Set("accept_language", acceptLanguage) From 862f91c3d9821ffb68de9c5a0d69e61d79b64681 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:24:07 -0400 Subject: [PATCH 0169/1208] r/servicecat_service_action: Refactor enum --- aws/resource_aws_servicecatalog_service_action.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_service_action.go b/aws/resource_aws_servicecatalog_service_action.go index 349cf26cabcb..319119e0a6b4 100644 --- a/aws/resource_aws_servicecatalog_service_action.go +++ b/aws/resource_aws_servicecatalog_service_action.go @@ -30,7 +30,7 @@ func resourceAwsServiceCatalogServiceAction() *schema.Resource { "accept_language": { Type: schema.TypeString, Optional: true, - Default: "en", + Default: tfservicecatalog.AcceptLanguageEnglish, ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, "definition": { From 539b84601929f29aab2e49d15c5183ac9067fd54 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:24:36 -0400 Subject: [PATCH 0170/1208] tests/r/servicecat_service_action: Refactor enum --- aws/resource_aws_servicecatalog_service_action_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_servicecatalog_service_action_test.go b/aws/resource_aws_servicecatalog_service_action_test.go index b3a798b5a3b9..63adb8775b13 100644 --- a/aws/resource_aws_servicecatalog_service_action_test.go +++ b/aws/resource_aws_servicecatalog_service_action_test.go @@ -12,6 +12,7 @@ import ( "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" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" ) // add sweeper to delete known test servicecat service actions @@ -88,7 +89,7 @@ func TestAccAWSServiceCatalogServiceAction_basic(t *testing.T) { Config: testAccAWSServiceCatalogServiceActionConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogServiceActionExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), resource.TestCheckResourceAttr(resourceName, "definition.0.name", "AWS-RestartEC2Instance"), resource.TestCheckResourceAttr(resourceName, "definition.0.version", "1"), resource.TestCheckResourceAttr(resourceName, "description", rName), @@ -144,7 +145,7 @@ func TestAccAWSServiceCatalogServiceAction_update(t *testing.T) { Config: testAccAWSServiceCatalogServiceActionConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogServiceActionExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), resource.TestCheckResourceAttr(resourceName, "definition.0.name", "AWS-RestartEC2Instance"), resource.TestCheckResourceAttr(resourceName, "definition.0.version", "1"), resource.TestCheckResourceAttr(resourceName, "description", rName), @@ -155,7 +156,7 @@ func TestAccAWSServiceCatalogServiceAction_update(t *testing.T) { Config: testAccAWSServiceCatalogServiceActionConfig_update(rName2), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogServiceActionExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), resource.TestCheckResourceAttrPair(resourceName, "definition.0.assume_role", "aws_iam_role.test", "arn"), resource.TestCheckResourceAttr(resourceName, "description", rName2), resource.TestCheckResourceAttr(resourceName, "name", rName2), From 872d61abe39a4fcb655675c997efb725bf7f2479 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:25:07 -0400 Subject: [PATCH 0171/1208] r/servicecat_provisioning_artifact: Refactor enum --- aws/resource_aws_servicecatalog_provisioning_artifact.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact.go b/aws/resource_aws_servicecatalog_provisioning_artifact.go index b767586f25d6..cdd73138c828 100644 --- a/aws/resource_aws_servicecatalog_provisioning_artifact.go +++ b/aws/resource_aws_servicecatalog_provisioning_artifact.go @@ -31,7 +31,7 @@ func resourceAwsServiceCatalogProvisioningArtifact() *schema.Resource { "accept_language": { Type: schema.TypeString, Optional: true, - Default: "en", + Default: tfservicecatalog.AcceptLanguageEnglish, ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, "active": { From 41d6b390f19c2b7e7e00c9dd94f1ff1697d7c409 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:25:30 -0400 Subject: [PATCH 0172/1208] tests/r/servicecat_provisioning_artifact: Refactor enum --- ...esource_aws_servicecatalog_provisioning_artifact_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go index 008ef7b58d36..05ab38d337f8 100644 --- a/aws/resource_aws_servicecatalog_provisioning_artifact_test.go +++ b/aws/resource_aws_servicecatalog_provisioning_artifact_test.go @@ -119,7 +119,7 @@ func TestAccAWSServiceCatalogProvisioningArtifact_basic(t *testing.T) { Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogProvisioningArtifactExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), resource.TestCheckResourceAttr(resourceName, "active", "true"), resource.TestCheckResourceAttr(resourceName, "description", rName), resource.TestCheckResourceAttr(resourceName, "disable_template_validation", "true"), @@ -181,7 +181,7 @@ func TestAccAWSServiceCatalogProvisioningArtifact_update(t *testing.T) { Config: testAccAWSServiceCatalogProvisioningArtifactConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogProvisioningArtifactExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), resource.TestCheckResourceAttr(resourceName, "active", "true"), resource.TestCheckResourceAttr(resourceName, "description", rName), resource.TestCheckResourceAttr(resourceName, "guidance", servicecatalog.ProvisioningArtifactGuidanceDefault), @@ -226,7 +226,7 @@ func TestAccAWSServiceCatalogProvisioningArtifact_physicalID(t *testing.T) { Config: testAccAWSServiceCatalogProvisioningArtifactConfig_physicalID(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogProvisioningArtifactExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), resource.TestCheckResourceAttr(resourceName, "active", "true"), resource.TestCheckResourceAttr(resourceName, "description", rName), resource.TestCheckResourceAttr(resourceName, "disable_template_validation", "false"), From feebc1f12e8d32d48db5f26bfc518f758ba470dd Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:26:04 -0400 Subject: [PATCH 0173/1208] tests/r/servicecat_product: Refactor enum --- aws/resource_aws_servicecatalog_product_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_product_test.go b/aws/resource_aws_servicecatalog_product_test.go index bd7d153e6b1a..f3ed7fa89aed 100644 --- a/aws/resource_aws_servicecatalog_product_test.go +++ b/aws/resource_aws_servicecatalog_product_test.go @@ -13,6 +13,7 @@ import ( "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" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" ) @@ -93,7 +94,7 @@ func TestAccAWSServiceCatalogProduct_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogProductExists(resourceName), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "catalog", regexp.MustCompile(`product/prod-.*`)), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), testAccCheckResourceAttrRfc3339(resourceName, "created_time"), resource.TestCheckResourceAttr(resourceName, "description", "beskrivning"), resource.TestCheckResourceAttr(resourceName, "distributor", "distributör"), From 149a1bd5439fa77bfdacffac2a74e46c9ffb653b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:26:25 -0400 Subject: [PATCH 0174/1208] r/servicecat_product: Refactor enum --- aws/resource_aws_servicecatalog_product.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_product.go b/aws/resource_aws_servicecatalog_product.go index fe692427ef13..e73856735e2d 100644 --- a/aws/resource_aws_servicecatalog_product.go +++ b/aws/resource_aws_servicecatalog_product.go @@ -36,7 +36,7 @@ func resourceAwsServiceCatalogProduct() *schema.Resource { "accept_language": { Type: schema.TypeString, Optional: true, - Default: "en", + Default: tfservicecatalog.AcceptLanguageEnglish, ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, "created_time": { From 48153772ef375cf1b5d7ed2634febde3a56e9662 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:27:05 -0400 Subject: [PATCH 0175/1208] tests/r/servicecat_constraint: Refactor enum --- aws/resource_aws_servicecatalog_constraint_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_constraint_test.go b/aws/resource_aws_servicecatalog_constraint_test.go index 7d4d41799995..135b8ff70fe0 100644 --- a/aws/resource_aws_servicecatalog_constraint_test.go +++ b/aws/resource_aws_servicecatalog_constraint_test.go @@ -12,6 +12,7 @@ import ( "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" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" ) // add sweeper to delete known test servicecat constraints @@ -106,7 +107,7 @@ func TestAccAWSServiceCatalogConstraint_basic(t *testing.T) { Config: testAccAWSServiceCatalogConstraintConfig_basic(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogConstraintExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), resource.TestCheckResourceAttr(resourceName, "description", rName), resource.TestCheckResourceAttr(resourceName, "type", "NOTIFICATION"), resource.TestCheckResourceAttrPair(resourceName, "portfolio_id", "aws_servicecatalog_portfolio.test", "id"), From d96f1803b496a137eaa905aa7deff92ea4a87ca9 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:27:24 -0400 Subject: [PATCH 0176/1208] r/servicecat_portfolio: Refactor enum --- aws/resource_aws_servicecatalog_portfolio.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_servicecatalog_portfolio.go b/aws/resource_aws_servicecatalog_portfolio.go index 4dce2bcb5b29..cff401e65e77 100644 --- a/aws/resource_aws_servicecatalog_portfolio.go +++ b/aws/resource_aws_servicecatalog_portfolio.go @@ -12,6 +12,7 @@ import ( "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" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" ) func resourceAwsServiceCatalogPortfolio() *schema.Resource { @@ -68,7 +69,7 @@ func resourceAwsServiceCatalogPortfolioCreate(d *schema.ResourceData, meta inter defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) input := servicecatalog.CreatePortfolioInput{ - AcceptLanguage: aws.String("en"), + AcceptLanguage: aws.String(tfservicecatalog.AcceptLanguageEnglish), DisplayName: aws.String(d.Get("name").(string)), IdempotencyToken: aws.String(resource.UniqueId()), Tags: tags.IgnoreAws().ServicecatalogTags(), @@ -98,7 +99,7 @@ func resourceAwsServiceCatalogPortfolioRead(d *schema.ResourceData, meta interfa ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig input := servicecatalog.DescribePortfolioInput{ - AcceptLanguage: aws.String("en"), + AcceptLanguage: aws.String(tfservicecatalog.AcceptLanguageEnglish), } input.Id = aws.String(d.Id()) @@ -138,7 +139,7 @@ func resourceAwsServiceCatalogPortfolioRead(d *schema.ResourceData, meta interfa func resourceAwsServiceCatalogPortfolioUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).scconn input := servicecatalog.UpdatePortfolioInput{ - AcceptLanguage: aws.String("en"), + AcceptLanguage: aws.String(tfservicecatalog.AcceptLanguageEnglish), Id: aws.String(d.Id()), } From 1242e3c6ffd42fa5805369d8c77170f61decb240 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:27:53 -0400 Subject: [PATCH 0177/1208] r/servicecat_portfolio_share: Refactor enum --- aws/resource_aws_servicecatalog_portfolio_share.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_portfolio_share.go b/aws/resource_aws_servicecatalog_portfolio_share.go index 2f12c649afce..97375e835aab 100644 --- a/aws/resource_aws_servicecatalog_portfolio_share.go +++ b/aws/resource_aws_servicecatalog_portfolio_share.go @@ -32,7 +32,7 @@ func resourceAwsServiceCatalogPortfolioShare() *schema.Resource { "accept_language": { Type: schema.TypeString, Optional: true, - Default: "en", + Default: tfservicecatalog.AcceptLanguageEnglish, ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, "accepted": { From a553ae5d0d804dfab56a0e95b7821ead4a32cb90 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:28:25 -0400 Subject: [PATCH 0178/1208] tests/r/servicecat_portfolio_share: Refactor enum --- aws/resource_aws_servicecatalog_portfolio_share_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_servicecatalog_portfolio_share_test.go b/aws/resource_aws_servicecatalog_portfolio_share_test.go index 62afd2a22d85..e4dd573a85a4 100644 --- a/aws/resource_aws_servicecatalog_portfolio_share_test.go +++ b/aws/resource_aws_servicecatalog_portfolio_share_test.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/finder" ) @@ -34,7 +35,7 @@ func TestAccAWSServiceCatalogPortfolioShare_basic(t *testing.T) { Config: testAccAWSServiceCatalogPortfolioShareConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogPortfolioShareExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), resource.TestCheckResourceAttr(resourceName, "accepted", "false"), resource.TestCheckResourceAttrPair(resourceName, "principal_id", dataSourceName, "account_id"), resource.TestCheckResourceAttrPair(resourceName, "portfolio_id", compareName, "id"), @@ -74,7 +75,7 @@ func TestAccAWSServiceCatalogPortfolioShare_organizationalUnit(t *testing.T) { Config: testAccAWSServiceCatalogPortfolioShareConfig_organizationalUnit(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogPortfolioShareExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), resource.TestCheckResourceAttr(resourceName, "accepted", "true"), resource.TestCheckResourceAttrPair(resourceName, "principal_id", "aws_organizations_organizational_unit.test", "id"), resource.TestCheckResourceAttrPair(resourceName, "portfolio_id", compareName, "id"), From 7e83d31d445ce4d0495dc4376985e6eaa10352fe Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 11:28:33 -0400 Subject: [PATCH 0179/1208] r/aws_amplify_branch: Test 'basic_auth_credentials'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplify_serial/Branch/BasicAuthCredentials' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplify_serial/Branch/BasicAuthCredentials -timeout 180m === RUN TestAccAWSAmplify_serial === RUN TestAccAWSAmplify_serial/Branch === RUN TestAccAWSAmplify_serial/Branch/BasicAuthCredentials === PAUSE TestAccAWSAmplify_serial/Branch/BasicAuthCredentials === CONT TestAccAWSAmplify_serial/Branch/BasicAuthCredentials --- PASS: TestAccAWSAmplify_serial (38.99s) --- PASS: TestAccAWSAmplify_serial/Branch (0.00s) --- PASS: TestAccAWSAmplify_serial/Branch/BasicAuthCredentials (38.99s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 43.099s --- aws/resource_aws_amplify_branch.go | 12 +++++ aws/resource_aws_amplify_branch_test.go | 65 +++++++++++++++++++++++++ aws/resource_aws_amplify_test.go | 1 + 3 files changed, 78 insertions(+) diff --git a/aws/resource_aws_amplify_branch.go b/aws/resource_aws_amplify_branch.go index 9fd82bd106ad..63dfd74d475c 100644 --- a/aws/resource_aws_amplify_branch.go +++ b/aws/resource_aws_amplify_branch.go @@ -57,6 +57,14 @@ func resourceAwsAmplifyBranch() *schema.Resource { Optional: true, Sensitive: true, ValidateFunc: validation.StringLenBetween(1, 2000), + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // These credentials are ignored if basic auth is not enabled. + if d.Get("enable_basic_auth").(bool) { + return old == new + } + + return true + }, }, "branch_name": { @@ -363,6 +371,10 @@ func resourceAwsAmplifyBranchUpdate(d *schema.ResourceData, meta interface{}) er input.EnableAutoBuild = aws.Bool(d.Get("enable_auto_build").(bool)) } + if d.HasChange("enable_basic_auth") { + input.EnableBasicAuth = aws.Bool(d.Get("enable_basic_auth").(bool)) + } + if d.HasChange("enable_notification") { input.EnableNotification = aws.Bool(d.Get("enable_notification").(bool)) } diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index 4f5cef5185e6..68c0cf84c464 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -1,6 +1,7 @@ package aws import ( + "encoding/base64" "fmt" "regexp" "testing" @@ -167,6 +168,54 @@ func testAccAWSAmplifyBranch_BackendEnvironmentArn(t *testing.T) { }) } +func testAccAWSAmplifyBranch_BasicAuthCredentials(t *testing.T) { + var branch amplify.Branch + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + credentials1 := base64.StdEncoding.EncodeToString([]byte("username1:password1")) + credentials2 := base64.StdEncoding.EncodeToString([]byte("username2:password2")) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigBasicAuthCredentials(rName, credentials1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", credentials1), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyBranchConfigBasicAuthCredentials(rName, credentials2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", credentials2), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "true"), + ), + }, + { + Config: testAccAWSAmplifyBranchConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + // Clearing basic_auth_credentials not reflected in API. + // resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", ""), + resource.TestCheckResourceAttr(resourceName, "enable_basic_auth", "false"), + ), + }, + }, + }) +} + /* func TestAccAWSAmplifyBranch_simple(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") @@ -497,6 +546,22 @@ resource "aws_amplify_branch" "test" { `, rName, environmentName, index) } +func testAccAWSAmplifyBranchConfigBasicAuthCredentials(rName, basicAuthCredentials string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = %[1]q + + basic_auth_credentials = %[2]q + enable_basic_auth = true +} +`, rName, basicAuthCredentials) +} + /* func testAccAWSAmplifyBranchConfig_Required(rName string) string { return testAccAWSAmplifyBranchConfigBranch(rName, "master") diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index dd845329ea1f..1cb2d1893948 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -32,6 +32,7 @@ func TestAccAWSAmplify_serial(t *testing.T) { "disappears": testAccAWSAmplifyBranch_disappears, "Tags": testAccAWSAmplifyBranch_Tags, "BackendEnvironmentArn": testAccAWSAmplifyBranch_BackendEnvironmentArn, + "BasicAuthCredentials": testAccAWSAmplifyBranch_BasicAuthCredentials, }, } From b911e58c51aeb968e24d132bb89561e9c565b05a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:28:58 -0400 Subject: [PATCH 0180/1208] r/servicecat_prin_port_assoc: Refactor enum --- ...ce_aws_servicecatalog_principal_portfolio_association.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_servicecatalog_principal_portfolio_association.go b/aws/resource_aws_servicecatalog_principal_portfolio_association.go index 546cff586229..3099cbef5ee8 100644 --- a/aws/resource_aws_servicecatalog_principal_portfolio_association.go +++ b/aws/resource_aws_servicecatalog_principal_portfolio_association.go @@ -30,7 +30,7 @@ func resourceAwsServiceCatalogPrincipalPortfolioAssociation() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - Default: tfservicecatalog.ServiceCatalogAcceptLanguageEnglish, + Default: tfservicecatalog.AcceptLanguageEnglish, ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, "portfolio_id": { @@ -114,7 +114,7 @@ func resourceAwsServiceCatalogPrincipalPortfolioAssociationRead(d *schema.Resour } if acceptLanguage == "" { - acceptLanguage = tfservicecatalog.ServiceCatalogAcceptLanguageEnglish + acceptLanguage = tfservicecatalog.AcceptLanguageEnglish } output, err := waiter.PrincipalPortfolioAssociationReady(conn, acceptLanguage, principalARN, portfolioID) @@ -151,7 +151,7 @@ func resourceAwsServiceCatalogPrincipalPortfolioAssociationDelete(d *schema.Reso } if acceptLanguage == "" { - acceptLanguage = tfservicecatalog.ServiceCatalogAcceptLanguageEnglish + acceptLanguage = tfservicecatalog.AcceptLanguageEnglish } input := &servicecatalog.DisassociatePrincipalFromPortfolioInput{ From 182f4f47199583be63f74ed3098bc954fa9804f2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:29:21 -0400 Subject: [PATCH 0181/1208] tests/r/servicecat_prin_port_assoc: Refactor enum --- ...e_aws_servicecatalog_principal_portfolio_association_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go b/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go index 78996e59c324..2d2737c0e0e1 100644 --- a/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go +++ b/aws/resource_aws_servicecatalog_principal_portfolio_association_test.go @@ -65,7 +65,7 @@ func testSweepServiceCatalogPrincipalPortfolioAssociations(region string) error r := resourceAwsServiceCatalogPrincipalPortfolioAssociation() d := r.Data(nil) - d.SetId(tfservicecatalog.PrincipalPortfolioAssociationID("en", aws.StringValue(principal.PrincipalARN), aws.StringValue(detail.Id))) + d.SetId(tfservicecatalog.PrincipalPortfolioAssociationID(tfservicecatalog.AcceptLanguageEnglish, aws.StringValue(principal.PrincipalARN), aws.StringValue(detail.Id))) sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } From 400990c666bc1f7c302e8d8ec04cb64029dbc795 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:29:50 -0400 Subject: [PATCH 0182/1208] r/servicecat_prod_port_assoc: Refactor enum --- ...resource_aws_servicecatalog_product_portfolio_association.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_product_portfolio_association.go b/aws/resource_aws_servicecatalog_product_portfolio_association.go index 74644d5b3419..20522207ac23 100644 --- a/aws/resource_aws_servicecatalog_product_portfolio_association.go +++ b/aws/resource_aws_servicecatalog_product_portfolio_association.go @@ -30,7 +30,7 @@ func resourceAwsServiceCatalogProductPortfolioAssociation() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - Default: "en", + Default: tfservicecatalog.AcceptLanguageEnglish, ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, "portfolio_id": { From 3fdc4b72c6750a07a633616851ecb567a90bc19c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 2 Jun 2021 11:30:17 -0400 Subject: [PATCH 0183/1208] tests/r/servicecat_prod_port_assoc: Refactor enum --- ...rce_aws_servicecatalog_product_portfolio_association_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_product_portfolio_association_test.go b/aws/resource_aws_servicecatalog_product_portfolio_association_test.go index f81472914aea..66843c5fbe45 100644 --- a/aws/resource_aws_servicecatalog_product_portfolio_association_test.go +++ b/aws/resource_aws_servicecatalog_product_portfolio_association_test.go @@ -86,7 +86,7 @@ func testSweepServiceCatalogProductPortfolioAssociations(region string) error { r := resourceAwsServiceCatalogProductPortfolioAssociation() d := r.Data(nil) - d.SetId(tfservicecatalog.ProductPortfolioAssociationCreateID("en", aws.StringValue(detail.Id), productID)) + d.SetId(tfservicecatalog.ProductPortfolioAssociationCreateID(tfservicecatalog.AcceptLanguageEnglish, aws.StringValue(detail.Id), productID)) sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } From 4cff17c0e5652ae092d88107b556971372b02af4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 11:32:49 -0400 Subject: [PATCH 0184/1208] r/aws_amplify_branch: Test 'environment_variables'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplify_serial/Branch/EnvironmentVariables' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplify_serial/Branch/EnvironmentVariables -timeout 180m === RUN TestAccAWSAmplify_serial === RUN TestAccAWSAmplify_serial/Branch === RUN TestAccAWSAmplify_serial/Branch/EnvironmentVariables === PAUSE TestAccAWSAmplify_serial/Branch/EnvironmentVariables === CONT TestAccAWSAmplify_serial/Branch/EnvironmentVariables --- PASS: TestAccAWSAmplify_serial (35.71s) --- PASS: TestAccAWSAmplify_serial/Branch (0.00s) --- PASS: TestAccAWSAmplify_serial/Branch/EnvironmentVariables (35.71s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 38.947s --- aws/resource_aws_amplify_branch_test.go | 79 +++++++++++++++++++++++++ aws/resource_aws_amplify_test.go | 1 + 2 files changed, 80 insertions(+) diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index 68c0cf84c464..7a39ead43f4e 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -216,6 +216,50 @@ func testAccAWSAmplifyBranch_BasicAuthCredentials(t *testing.T) { }) } +func testAccAWSAmplifyBranch_EnvironmentVariables(t *testing.T) { + var branch amplify.Branch + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_branch.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyBranchConfigEnvironmentVariables(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "1"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyBranchConfigEnvironmentVariablesUpdated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "2"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "2"), + resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR2", "2"), + ), + }, + { + Config: testAccAWSAmplifyBranchConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), + ), + }, + }, + }) +} + /* func TestAccAWSAmplifyBranch_simple(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") @@ -562,6 +606,41 @@ resource "aws_amplify_branch" "test" { `, rName, basicAuthCredentials) } +func testAccAWSAmplifyBranchConfigEnvironmentVariables(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = %[1]q + + environment_variables = { + ENVVAR1 = "1" + } +} +`, rName) +} + +func testAccAWSAmplifyBranchConfigEnvironmentVariablesUpdated(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = %[1]q + + environment_variables = { + ENVVAR1 = "2", + ENVVAR2 = "2" + } +} +`, rName) +} + /* func testAccAWSAmplifyBranchConfig_Required(rName string) string { return testAccAWSAmplifyBranchConfigBranch(rName, "master") diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index 1cb2d1893948..40e0e19383c0 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -33,6 +33,7 @@ func TestAccAWSAmplify_serial(t *testing.T) { "Tags": testAccAWSAmplifyBranch_Tags, "BackendEnvironmentArn": testAccAWSAmplifyBranch_BackendEnvironmentArn, "BasicAuthCredentials": testAccAWSAmplifyBranch_BasicAuthCredentials, + "EnvironmentVariables": testAccAWSAmplifyBranch_EnvironmentVariables, }, } From bdf6db1de3d182d80ce7ddef67f93d6237e5fb27 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 2 Jun 2021 15:58:17 +0000 Subject: [PATCH 0185/1208] Update CHANGELOG.md for #19470 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee8c39a3a3ab..09907417efe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 3.44.0 (Unreleased) +FEATURES: + +* **New Resource:** `aws_servicecatalog_principal_portfolio_association` ([#19470](https://github.com/hashicorp/terraform-provider-aws/issues/19470)) + ENHANCEMENTS: * resource/aws_acmpca_certificate_authority: Add `s3_object_acl` argument to `revocation_configuration.crl_configuration` configuration block ([#19578](https://github.com/hashicorp/terraform-provider-aws/issues/19578)) From 7c89c520f1905458d9def5c7fae877201b9a566a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 12:59:43 -0400 Subject: [PATCH 0186/1208] r/aws_amplify_branch: Test other optional arguments. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplify_serial/Branch/OptionalArguments' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplify_serial/Branch/OptionalArguments -timeout 180m === RUN TestAccAWSAmplify_serial === RUN TestAccAWSAmplify_serial/Branch === RUN TestAccAWSAmplify_serial/Branch/OptionalArguments === PAUSE TestAccAWSAmplify_serial/Branch/OptionalArguments === CONT TestAccAWSAmplify_serial/Branch/OptionalArguments --- PASS: TestAccAWSAmplify_serial (30.92s) --- PASS: TestAccAWSAmplify_serial/Branch (0.00s) --- PASS: TestAccAWSAmplify_serial/Branch/OptionalArguments (30.92s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 33.969s --- aws/resource_aws_amplify_branch.go | 16 +- aws/resource_aws_amplify_branch_test.go | 345 +++----------------- aws/resource_aws_amplify_test.go | 1 + website/docs/r/amplify_branch.html.markdown | 1 - 4 files changed, 54 insertions(+), 309 deletions(-) diff --git a/aws/resource_aws_amplify_branch.go b/aws/resource_aws_amplify_branch.go index 63dfd74d475c..d63bc5a2dbe7 100644 --- a/aws/resource_aws_amplify_branch.go +++ b/aws/resource_aws_amplify_branch.go @@ -74,12 +74,6 @@ func resourceAwsAmplifyBranch() *schema.Resource { ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[0-9A-Za-z/_.-]{1,255}$`), "should be not be more than 255 letters, numbers, and the symbols /_.-"), }, - "build_spec": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 25000), - }, - "custom_domains": { Type: schema.TypeList, Computed: true, @@ -123,6 +117,7 @@ func resourceAwsAmplifyBranch() *schema.Resource { "enable_performance_mode": { Type: schema.TypeBool, Optional: true, + ForceNew: true, }, "enable_pull_request_preview": { @@ -209,10 +204,6 @@ func resourceAwsAmplifyBranchCreate(d *schema.ResourceData, meta interface{}) er input.BasicAuthCredentials = aws.String(v.(string)) } - if v, ok := d.GetOk("build_spec"); ok { - input.BuildSpec = aws.String(v.(string)) - } - if v, ok := d.GetOk("description"); ok { input.Description = aws.String(v.(string)) } @@ -302,7 +293,6 @@ func resourceAwsAmplifyBranchRead(d *schema.ResourceData, meta interface{}) erro d.Set("backend_environment_arn", branch.BackendEnvironmentArn) d.Set("basic_auth_credentials", branch.BasicAuthCredentials) d.Set("branch_name", branch.BranchName) - d.Set("build_spec", branch.BuildSpec) d.Set("custom_domains", aws.StringValueSlice(branch.CustomDomains)) d.Set("description", branch.Description) d.Set("destination_branch", branch.DestinationBranch) @@ -355,10 +345,6 @@ func resourceAwsAmplifyBranchUpdate(d *schema.ResourceData, meta interface{}) er input.BasicAuthCredentials = aws.String(d.Get("basic_auth_credentials").(string)) } - if d.HasChange("build_spec") { - input.BuildSpec = aws.String(d.Get("build_spec").(string)) - } - if d.HasChange("description") { input.Description = aws.String(d.Get("description").(string)) } diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index 7a39ead43f4e..98cdd23665ae 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -28,14 +28,13 @@ func testAccAWSAmplifyBranch_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSAmplifyBranchConfigName(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSAmplifyBranchExists(resourceName, &branch), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+/branches/.+`)), resource.TestCheckResourceAttr(resourceName, "associated_resources.#", "0"), resource.TestCheckResourceAttr(resourceName, "backend_environment_arn", ""), resource.TestCheckResourceAttr(resourceName, "basic_auth_credentials", ""), resource.TestCheckResourceAttr(resourceName, "branch_name", rName), - resource.TestCheckResourceAttr(resourceName, "build_spec", ""), resource.TestCheckResourceAttr(resourceName, "custom_domains.#", "0"), resource.TestCheckResourceAttr(resourceName, "description", ""), resource.TestCheckResourceAttr(resourceName, "destination_branch", ""), @@ -260,8 +259,8 @@ func testAccAWSAmplifyBranch_EnvironmentVariables(t *testing.T) { }) } -/* -func TestAccAWSAmplifyBranch_simple(t *testing.T) { +func testAccAWSAmplifyBranch_OptionalArguments(t *testing.T) { + var branch amplify.Branch rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_branch.test" @@ -272,13 +271,18 @@ func TestAccAWSAmplifyBranch_simple(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyBranchConfigSimple(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "description", "description"), - resource.TestCheckResourceAttr(resourceName, "display_name", "displayname"), + Config: testAccAWSAmplifyBranchConfigOptionalArguments(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttr(resourceName, "description", "testdescription1"), + resource.TestCheckResourceAttr(resourceName, "display_name", "testdisplayname1"), resource.TestCheckResourceAttr(resourceName, "enable_auto_build", "false"), - resource.TestCheckResourceAttr(resourceName, "framework", "WEB"), - resource.TestCheckResourceAttr(resourceName, "stage", "PRODUCTION"), + resource.TestCheckResourceAttr(resourceName, "enable_notification", "true"), + resource.TestCheckResourceAttr(resourceName, "enable_performance_mode", "true"), + resource.TestCheckResourceAttr(resourceName, "enable_pull_request_preview", "false"), + resource.TestCheckResourceAttr(resourceName, "framework", "React"), + resource.TestCheckResourceAttr(resourceName, "pull_request_environment_name", "testpr1"), + resource.TestCheckResourceAttr(resourceName, "stage", "DEVELOPMENT"), resource.TestCheckResourceAttr(resourceName, "ttl", "10"), ), }, @@ -287,174 +291,25 @@ func TestAccAWSAmplifyBranch_simple(t *testing.T) { ImportState: true, ImportStateVerify: true, }, - }, - }) -} - -func TestAccAWSAmplifyBranch_backendEnvironment(t *testing.T) { - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_amplify_branch.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, - ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyBranchConfigBackendEnvironment(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr(resourceName, "backend_environment_arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/backendenvironments/prod")), - ), - }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccAWSAmplifyBranch_pullRequestPreview(t *testing.T) { - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_amplify_branch.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, - ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyBranchConfigPullRequestPreview(rName), - Check: resource.ComposeTestCheckFunc( + Config: testAccAWSAmplifyBranchConfigOptionalArgumentsUpdated(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttr(resourceName, "description", "testdescription2"), + resource.TestCheckResourceAttr(resourceName, "display_name", "testdisplayname2"), + resource.TestCheckResourceAttr(resourceName, "enable_auto_build", "true"), + resource.TestCheckResourceAttr(resourceName, "enable_notification", "false"), + resource.TestCheckResourceAttr(resourceName, "enable_performance_mode", "true"), resource.TestCheckResourceAttr(resourceName, "enable_pull_request_preview", "true"), - resource.TestCheckResourceAttr(resourceName, "pull_request_environment_name", "prod"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccAWSAmplifyBranch_BasicAuthCredentials(t *testing.T) { - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_amplify_branch.test" - - username1 := "username1" - password1 := "password1" - username2 := "username2" - password2 := "password2" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, - ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyBranchConfigBasicAuthConfig(rName, username1, password1), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.enable_basic_auth", "true"), - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.username", username1), - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.password", password1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyBranchConfigBasicAuthConfig(rName, username2, password2), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "1"), - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.enable_basic_auth", "true"), - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.username", username2), - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.0.password", password2), - ), - }, - { - Config: testAccAWSAmplifyBranchConfig_Required(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "basic_auth_config.#", "0"), - ), - }, - }, - }) -} - -func TestAccAWSAmplifyBranch_notification(t *testing.T) { - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_amplify_branch.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, - ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyBranchConfigNotification(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "enable_notification", "true"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccAWSAmplifyBranch_environmentVariables(t *testing.T) { - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_amplify_branch.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, - ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyBranchConfigEnvironmentVariables1(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "1"), - resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyBranchConfigEnvironmentVariables2(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "2"), - resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR1", "2"), - resource.TestCheckResourceAttr(resourceName, "environment_variables.ENVVAR2", "2"), - ), - }, - { - Config: testAccAWSAmplifyBranchConfig_Required(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "environment_variables.%", "0"), + resource.TestCheckResourceAttr(resourceName, "framework", "Angular"), + resource.TestCheckResourceAttr(resourceName, "pull_request_environment_name", "testpr2"), + resource.TestCheckResourceAttr(resourceName, "stage", "EXPERIMENTAL"), + resource.TestCheckResourceAttr(resourceName, "ttl", "15"), ), }, }, }) } -*/ func testAccCheckAWSAmplifyBranchExists(resourceName string, v *amplify.Branch) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -641,146 +496,50 @@ resource "aws_amplify_branch" "test" { `, rName) } -/* -func testAccAWSAmplifyBranchConfig_Required(rName string) string { - return testAccAWSAmplifyBranchConfigBranch(rName, "master") -} - -func testAccAWSAmplifyBranchConfigBranch(rName string, branchName string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = "%s" -} - -resource "aws_amplify_branch" "test" { - app_id = aws_amplify_app.test.id - branch_name = "%s" -} -`, rName, branchName) -} - -func testAccAWSAmplifyBranchConfigSimple(rName string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = "%s" -} - -resource "aws_amplify_branch" "test" { - app_id = aws_amplify_app.test.id - branch_name = "master" - - description = "description" - display_name = "displayname" - enable_auto_build = false - framework = "WEB" - stage = "PRODUCTION" - ttl = "10" -} -`, rName) -} - -func testAccAWSAmplifyBranchConfigBackendEnvironment(rName string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = "%s" -} - -resource "aws_amplify_backend_environment" "test" { - app_id = aws_amplify_app.test.id - environment_name = "prod" -} - -resource "aws_amplify_branch" "test" { - app_id = aws_amplify_app.test.id - branch_name = "master" - - backend_environment_arn = aws_amplify_backend_environment.test.arn -} -`, rName) -} - -func testAccAWSAmplifyBranchConfigPullRequestPreview(rName string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = "%s" -} - -resource "aws_amplify_branch" "test" { - app_id = aws_amplify_app.test.id - branch_name = "master" - - enable_pull_request_preview = true - pull_request_environment_name = "prod" -} -`, rName) -} - -func testAccAWSAmplifyBranchConfigBasicAuthConfig(rName string, username, password string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = "%s" -} - -resource "aws_amplify_branch" "test" { - app_id = aws_amplify_app.test.id - branch_name = "master" - - basic_auth_config { - enable_basic_auth = true - username = "%s" - password = "%s" - } -} -`, rName, username, password) -} - -func testAccAWSAmplifyBranchConfigNotification(rName string) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = "%s" -} - -resource "aws_amplify_branch" "test" { - app_id = aws_amplify_app.test.id - branch_name = "master" - - enable_notification = true -} -`, rName) -} - -func testAccAWSAmplifyBranchConfigEnvironmentVariables1(rName string) string { +func testAccAWSAmplifyBranchConfigOptionalArguments(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q } resource "aws_amplify_branch" "test" { app_id = aws_amplify_app.test.id - branch_name = "master" + branch_name = %[1]q - environment_variables = { - ENVVAR1 = "1" - } + description = "testdescription1" + display_name = "testdisplayname1" + enable_auto_build = false + enable_notification = true + enable_performance_mode = true + enable_pull_request_preview = false + framework = "React" + pull_request_environment_name = "testpr1" + stage = "DEVELOPMENT" + ttl = "10" } `, rName) } -func testAccAWSAmplifyBranchConfigEnvironmentVariables2(rName string) string { +func testAccAWSAmplifyBranchConfigOptionalArgumentsUpdated(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q } resource "aws_amplify_branch" "test" { app_id = aws_amplify_app.test.id - branch_name = "master" + branch_name = %[1]q - environment_variables = { - ENVVAR1 = "2", - ENVVAR2 = "2" - } + description = "testdescription2" + display_name = "testdisplayname2" + enable_auto_build = true + enable_notification = false + enable_performance_mode = true + enable_pull_request_preview = true + framework = "Angular" + pull_request_environment_name = "testpr2" + stage = "EXPERIMENTAL" + ttl = "15" } `, rName) } -*/ diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index 40e0e19383c0..de678a4c9992 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -34,6 +34,7 @@ func TestAccAWSAmplify_serial(t *testing.T) { "BackendEnvironmentArn": testAccAWSAmplifyBranch_BackendEnvironmentArn, "BasicAuthCredentials": testAccAWSAmplifyBranch_BasicAuthCredentials, "EnvironmentVariables": testAccAWSAmplifyBranch_EnvironmentVariables, + "OptionalArguments": testAccAWSAmplifyBranch_OptionalArguments, }, } diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown index 5c29b7acf482..38a78617f553 100644 --- a/website/docs/r/amplify_branch.html.markdown +++ b/website/docs/r/amplify_branch.html.markdown @@ -158,7 +158,6 @@ The following arguments are supported: * `branch_name` - (Required) The name for the branch. * `backend_environment_arn` - (Optional) The Amazon Resource Name (ARN) for a backend environment that is part of an Amplify app. * `basic_auth_credentials` - (Optional) The basic authorization credentials for the branch. -* `build_spec` - (Optional) The build specification (build spec) for the branch. * `description` - (Optional) The description for the branch. * `display_name` - (Optional) The display name for a branch. This is used as the default domain prefix. * `enable_auto_build` - (Optional) Enables auto building for the branch. From 6ac806d430f9e66396732f793fc9a220242cc6af Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 14:12:33 -0400 Subject: [PATCH 0187/1208] r/aws_amplify_branch: Fold 'testAccAWSAmplifyBranch_BackendEnvironmentArn' into 'testAccAWSAmplifyBranch_OptionalArguments'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSAmplify_serial/Branch/OptionalArguments' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAmplify_serial/Branch/OptionalArguments -timeout 180m === RUN TestAccAWSAmplify_serial === RUN TestAccAWSAmplify_serial/Branch === RUN TestAccAWSAmplify_serial/Branch/OptionalArguments === PAUSE TestAccAWSAmplify_serial/Branch/OptionalArguments === CONT TestAccAWSAmplify_serial/Branch/OptionalArguments --- PASS: TestAccAWSAmplify_serial (29.75s) --- PASS: TestAccAWSAmplify_serial/Branch (0.00s) --- PASS: TestAccAWSAmplify_serial/Branch/OptionalArguments (29.75s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 32.968s --- aws/resource_aws_amplify_branch_test.go | 101 ++++++++---------------- aws/resource_aws_amplify_test.go | 13 ++- 2 files changed, 39 insertions(+), 75 deletions(-) diff --git a/aws/resource_aws_amplify_branch_test.go b/aws/resource_aws_amplify_branch_test.go index 98cdd23665ae..3ba7103ddfde 100644 --- a/aws/resource_aws_amplify_branch_test.go +++ b/aws/resource_aws_amplify_branch_test.go @@ -130,43 +130,6 @@ func testAccAWSAmplifyBranch_Tags(t *testing.T) { }) } -func testAccAWSAmplifyBranch_BackendEnvironmentArn(t *testing.T) { - var branch amplify.Branch - rName := acctest.RandomWithPrefix("tf-acc-test") - environmentName := acctest.RandStringFromCharSet(9, acctest.CharSetAlpha) - resourceName := "aws_amplify_branch.test" - backendEnvironment1ResourceName := "aws_amplify_backend_environment.test1" - backendEnvironment2ResourceName := "aws_amplify_backend_environment.test2" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, - ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName, 1), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyBranchExists(resourceName, &branch), - resource.TestCheckResourceAttrPair(resourceName, "backend_environment_arn", backendEnvironment1ResourceName, "arn"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName, 2), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAmplifyBranchExists(resourceName, &branch), - resource.TestCheckResourceAttrPair(resourceName, "backend_environment_arn", backendEnvironment2ResourceName, "arn"), - ), - }, - }, - }) -} - func testAccAWSAmplifyBranch_BasicAuthCredentials(t *testing.T) { var branch amplify.Branch rName := acctest.RandomWithPrefix("tf-acc-test") @@ -262,7 +225,10 @@ func testAccAWSAmplifyBranch_EnvironmentVariables(t *testing.T) { func testAccAWSAmplifyBranch_OptionalArguments(t *testing.T) { var branch amplify.Branch rName := acctest.RandomWithPrefix("tf-acc-test") + environmentName := acctest.RandStringFromCharSet(9, acctest.CharSetAlpha) resourceName := "aws_amplify_branch.test" + backendEnvironment1ResourceName := "aws_amplify_backend_environment.test1" + backendEnvironment2ResourceName := "aws_amplify_backend_environment.test2" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, @@ -271,9 +237,10 @@ func testAccAWSAmplifyBranch_OptionalArguments(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyBranchDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyBranchConfigOptionalArguments(rName), + Config: testAccAWSAmplifyBranchConfigOptionalArguments(rName, environmentName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttrPair(resourceName, "backend_environment_arn", backendEnvironment1ResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "description", "testdescription1"), resource.TestCheckResourceAttr(resourceName, "display_name", "testdisplayname1"), resource.TestCheckResourceAttr(resourceName, "enable_auto_build", "false"), @@ -292,9 +259,10 @@ func testAccAWSAmplifyBranch_OptionalArguments(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyBranchConfigOptionalArgumentsUpdated(rName), + Config: testAccAWSAmplifyBranchConfigOptionalArgumentsUpdated(rName, environmentName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSAmplifyBranchExists(resourceName, &branch), + resource.TestCheckResourceAttrPair(resourceName, "backend_environment_arn", backendEnvironment2ResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "description", "testdescription2"), resource.TestCheckResourceAttr(resourceName, "display_name", "testdisplayname2"), resource.TestCheckResourceAttr(resourceName, "enable_auto_build", "true"), @@ -420,31 +388,6 @@ resource "aws_amplify_branch" "test" { `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } -func testAccAWSAmplifyBranchConfigBackendEnvironmentARN(rName, environmentName string, index int) string { - return fmt.Sprintf(` -resource "aws_amplify_app" "test" { - name = %[1]q -} - -resource "aws_amplify_backend_environment" "test1" { - app_id = aws_amplify_app.test.id - environment_name = "%[2]sa" -} - -resource "aws_amplify_backend_environment" "test2" { - app_id = aws_amplify_app.test.id - environment_name = "%[2]sb" -} - -resource "aws_amplify_branch" "test" { - app_id = aws_amplify_app.test.id - branch_name = %[1]q - - backend_environment_arn = aws_amplify_backend_environment.test%[3]d.arn -} -`, rName, environmentName, index) -} - func testAccAWSAmplifyBranchConfigBasicAuthCredentials(rName, basicAuthCredentials string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { @@ -496,16 +439,27 @@ resource "aws_amplify_branch" "test" { `, rName) } -func testAccAWSAmplifyBranchConfigOptionalArguments(rName string) string { +func testAccAWSAmplifyBranchConfigOptionalArguments(rName, environmentName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { name = %[1]q } +resource "aws_amplify_backend_environment" "test1" { + app_id = aws_amplify_app.test.id + environment_name = "%[2]sa" +} + +resource "aws_amplify_backend_environment" "test2" { + app_id = aws_amplify_app.test.id + environment_name = "%[2]sb" +} + resource "aws_amplify_branch" "test" { app_id = aws_amplify_app.test.id branch_name = %[1]q + backend_environment_arn = aws_amplify_backend_environment.test1.arn description = "testdescription1" display_name = "testdisplayname1" enable_auto_build = false @@ -517,19 +471,30 @@ resource "aws_amplify_branch" "test" { stage = "DEVELOPMENT" ttl = "10" } -`, rName) +`, rName, environmentName) } -func testAccAWSAmplifyBranchConfigOptionalArgumentsUpdated(rName string) string { +func testAccAWSAmplifyBranchConfigOptionalArgumentsUpdated(rName, environmentName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { name = %[1]q } +resource "aws_amplify_backend_environment" "test1" { + app_id = aws_amplify_app.test.id + environment_name = "%[2]sa" +} + +resource "aws_amplify_backend_environment" "test2" { + app_id = aws_amplify_app.test.id + environment_name = "%[2]sb" +} + resource "aws_amplify_branch" "test" { app_id = aws_amplify_app.test.id branch_name = %[1]q + backend_environment_arn = aws_amplify_backend_environment.test2.arn description = "testdescription2" display_name = "testdisplayname2" enable_auto_build = true @@ -541,5 +506,5 @@ resource "aws_amplify_branch" "test" { stage = "EXPERIMENTAL" ttl = "15" } -`, rName) +`, rName, environmentName) } diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index de678a4c9992..03e39da1c05c 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -28,13 +28,12 @@ func TestAccAWSAmplify_serial(t *testing.T) { "DeploymentArtifacts_StackName": testAccAWSAmplifyBackendEnvironment_DeploymentArtifacts_StackName, }, "Branch": { - "basic": testAccAWSAmplifyBranch_basic, - "disappears": testAccAWSAmplifyBranch_disappears, - "Tags": testAccAWSAmplifyBranch_Tags, - "BackendEnvironmentArn": testAccAWSAmplifyBranch_BackendEnvironmentArn, - "BasicAuthCredentials": testAccAWSAmplifyBranch_BasicAuthCredentials, - "EnvironmentVariables": testAccAWSAmplifyBranch_EnvironmentVariables, - "OptionalArguments": testAccAWSAmplifyBranch_OptionalArguments, + "basic": testAccAWSAmplifyBranch_basic, + "disappears": testAccAWSAmplifyBranch_disappears, + "Tags": testAccAWSAmplifyBranch_Tags, + "BasicAuthCredentials": testAccAWSAmplifyBranch_BasicAuthCredentials, + "EnvironmentVariables": testAccAWSAmplifyBranch_EnvironmentVariables, + "OptionalArguments": testAccAWSAmplifyBranch_OptionalArguments, }, } From 723594fe434ae88992e4839f84289370d695409a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Jun 2021 18:19:30 +0000 Subject: [PATCH 0188/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.52 to 1.38.53. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.52...v1.38.53) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index cf9da5e68909..9ef40ef59bcf 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.52 + github.com/aws/aws-sdk-go v1.38.53 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 210cb5bdbce9..bbdc129029c8 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.52 h1:7NKcUyTG/CyDX835kq04DDNe8vXaJhbGW8ThemHb18A= -github.com/aws/aws-sdk-go v1.38.52/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.53 h1:Qj5OvKPrDGTiCnWj+kwQXAlBO6OaFBH/WaRzJPZPg3w= +github.com/aws/aws-sdk-go v1.38.53/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index fb58b46640af..7d0c72aea7b8 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.52" +const SDKVersion = "1.38.53" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 53f729f07fcc..a1510d3c78de 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.52 +# github.com/aws/aws-sdk-go v1.38.53 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From b1f6ce800e6b5d15323374d387a9cf89778812aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Jun 2021 18:19:34 +0000 Subject: [PATCH 0189/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.52 to 1.38.53 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.52 to 1.38.53. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.52...v1.38.53) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d7de330e30a0..dd113710b11e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.52 + github.com/aws/aws-sdk-go v1.38.53 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index 14d7c8704aa0..2afd4dc501a2 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.52 h1:7NKcUyTG/CyDX835kq04DDNe8vXaJhbGW8ThemHb18A= -github.com/aws/aws-sdk-go v1.38.52/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.53 h1:Qj5OvKPrDGTiCnWj+kwQXAlBO6OaFBH/WaRzJPZPg3w= +github.com/aws/aws-sdk-go v1.38.53/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From e397f8347b66ca395d81fc26771fbd51c8118087 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 14:23:34 -0400 Subject: [PATCH 0190/1208] r/aws_amplify_app: 'auto_branch_creation_config.enable_performance_mode' is 'ForceNew'. --- .changelog/11937.txt | 4 ++++ aws/resource_aws_amplify_app.go | 1 + 2 files changed, 5 insertions(+) diff --git a/.changelog/11937.txt b/.changelog/11937.txt index f520349bd25b..106a416f8af3 100644 --- a/.changelog/11937.txt +++ b/.changelog/11937.txt @@ -1,3 +1,7 @@ ```release-note:new-resource aws_amplify_branch +``` + +```release-note:bug +resource/aws_amplify_app: Mark the `enable_performance_mode` argumnet in the `auto_branch_creation_config` configuration block as `ForceNew` ``` \ No newline at end of file diff --git a/aws/resource_aws_amplify_app.go b/aws/resource_aws_amplify_app.go index 963fffb1269a..b28d2ba01202 100644 --- a/aws/resource_aws_amplify_app.go +++ b/aws/resource_aws_amplify_app.go @@ -94,6 +94,7 @@ func resourceAwsAmplifyApp() *schema.Resource { "enable_performance_mode": { Type: schema.TypeBool, Optional: true, + ForceNew: true, }, "enable_pull_request_preview": { From 3b39a064948fa526cba902259a763b273d6b1c0f Mon Sep 17 00:00:00 2001 From: Akshay Jain Date: Fri, 28 May 2021 14:29:13 -0700 Subject: [PATCH 0191/1208] Adding GP3 support for launch configurations --- aws/resource_aws_launch_configuration.go | 25 +++++++++ aws/resource_aws_launch_configuration_test.go | 55 +++++++++++++++++++ .../docs/r/launch_configuration.html.markdown | 6 +- 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_launch_configuration.go b/aws/resource_aws_launch_configuration.go index c4d7bc8c5251..d56a0ab1b59d 100644 --- a/aws/resource_aws_launch_configuration.go +++ b/aws/resource_aws_launch_configuration.go @@ -218,6 +218,13 @@ func resourceAwsLaunchConfiguration() *schema.Resource { Computed: true, ForceNew: true, }, + + "throughput": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + }, }, }, }, @@ -325,6 +332,13 @@ func resourceAwsLaunchConfiguration() *schema.Resource { Computed: true, ForceNew: true, }, + + "throughput": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + }, }, }, }, @@ -435,6 +449,10 @@ func resourceAwsLaunchConfigurationCreate(d *schema.ResourceData, meta interface ebs.Iops = aws.Int64(int64(v)) } + if v, ok := bd["throughput"].(int); ok && v > 0 { + ebs.Throughput = aws.Int64(int64(v)) + } + if bd["device_name"].(string) == aws.StringValue(rootDeviceName) { return fmt.Errorf("Root device (%s) declared as an 'ebs_block_device'. Use 'root_block_device' keyword.", *rootDeviceName) } @@ -482,6 +500,10 @@ func resourceAwsLaunchConfigurationCreate(d *schema.ResourceData, meta interface ebs.Iops = aws.Int64(int64(v)) } + if v, ok := bd["throughput"].(int); ok && v > 0 { + ebs.Throughput = aws.Int64(int64(v)) + } + if dn, err := fetchRootDeviceName(d.Get("image_id").(string), ec2conn); err == nil { if dn == nil { return fmt.Errorf( @@ -763,6 +785,9 @@ func readBlockDevicesFromLaunchConfiguration(d *schema.ResourceData, lc *autosca if bdm.Ebs != nil && bdm.Ebs.Iops != nil { bd["iops"] = *bdm.Ebs.Iops } + if bdm.Ebs != nil && bdm.Ebs.Throughput != nil { + bd["throughput"] = *bdm.Ebs.Throughput + } if bdm.Ebs != nil && bdm.Ebs.Encrypted != nil { bd["encrypted"] = *bdm.Ebs.Encrypted } diff --git a/aws/resource_aws_launch_configuration_test.go b/aws/resource_aws_launch_configuration_test.go index 6b7f79deb074..e7ff3eb4ac44 100644 --- a/aws/resource_aws_launch_configuration_test.go +++ b/aws/resource_aws_launch_configuration_test.go @@ -362,6 +362,38 @@ func TestAccAWSLaunchConfiguration_withEncryption(t *testing.T) { }) } +func TestAccAWSLaunchConfiguration_withGP3(t *testing.T) { + var conf autoscaling.LaunchConfiguration + resourceName := "aws_launch_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, autoscaling.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLaunchConfigurationWithGP3(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLaunchConfigurationExists("aws_launch_configuration.test", &conf), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "ebs_block_device.*", map[string]string{ + "volume_type": "gp3", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "ebs_block_device.*", map[string]string{ + "throughput": "150", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"associate_public_ip_address"}, + }, + }, + }) +} + func TestAccAWSLaunchConfiguration_updateEbsBlockDevices(t *testing.T) { var conf autoscaling.LaunchConfiguration resourceName := "aws_launch_configuration.test" @@ -835,6 +867,29 @@ resource "aws_launch_configuration" "test" { `) } +func testAccAWSLaunchConfigurationWithGP3() string { + return composeConfig(testAccLatestAmazonLinuxHvmEbsAmiConfig(), ` +resource "aws_launch_configuration" "test" { + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = "t2.micro" + associate_public_ip_address = false + + root_block_device { + volume_type = "gp3" + volume_size = 11 + } + + ebs_block_device { + volume_type = "gp3" + device_name = "/dev/sdb" + volume_size = 9 + encrypted = true + throughput = 150 + } +} +`) +} + func testAccAWSLaunchConfigurationWithEncryptionUpdated() string { return composeConfig(testAccLatestAmazonLinuxHvmEbsAmiConfig(), ` resource "aws_launch_configuration" "test" { diff --git a/website/docs/r/launch_configuration.html.markdown b/website/docs/r/launch_configuration.html.markdown index f99ce052dbaa..ac2fed58bfd7 100644 --- a/website/docs/r/launch_configuration.html.markdown +++ b/website/docs/r/launch_configuration.html.markdown @@ -176,12 +176,13 @@ to understand the implications of using these attributes. The `root_block_device` mapping supports the following: -* `volume_type` - (Optional) The type of volume. Can be `"standard"`, `"gp2"`, +* `volume_type` - (Optional) The type of volume. Can be `"standard"`, `"gp2"`, `"gp3"`, `"st1"`, `"sc1"` or `"io1"`. (Default: `"standard"`). * `volume_size` - (Optional) The size of the volume in gigabytes. * `iops` - (Optional) The amount of provisioned [IOPS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-io-characteristics.html). This must be set with a `volume_type` of `"io1"`. +* `throughput` - (Optional) The throughput (MiBps) to provision for a `gp3` volume. * `delete_on_termination` - (Optional) Whether the volume should be destroyed on instance termination (Default: `true`). * `encrypted` - (Optional) Whether the volume should be encrypted or not. (Default: `false`). @@ -193,12 +194,13 @@ Each `ebs_block_device` supports the following: * `device_name` - (Required) The name of the device to mount. * `snapshot_id` - (Optional) The Snapshot ID to mount. -* `volume_type` - (Optional) The type of volume. Can be `"standard"`, `"gp2"`, +* `volume_type` - (Optional) The type of volume. Can be `"standard"`, `"gp2"`, `"gp3"`, `"st1"`, `"sc1"` or `"io1"`. (Default: `"standard"`). * `volume_size` - (Optional) The size of the volume in gigabytes. * `iops` - (Optional) The amount of provisioned [IOPS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-io-characteristics.html). This must be set with a `volume_type` of `"io1"`. +* `throughput` - (Optional) The throughput (MiBps) to provision for a `gp3` volume. * `delete_on_termination` - (Optional) Whether the volume should be destroyed on instance termination (Default: `true`). * `encrypted` - (Optional) Whether the volume should be encrypted or not. Do not use this option if you are using `snapshot_id` as the encrypted flag will be determined by the snapshot. (Default: `false`). From 3d93e690d769bc1e94e5e88633d5c13463afb5c2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 14:32:00 -0400 Subject: [PATCH 0192/1208] Add CHANGELOG entry. --- .changelog/19632.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19632.txt diff --git a/.changelog/19632.txt b/.changelog/19632.txt new file mode 100644 index 000000000000..bcced0890342 --- /dev/null +++ b/.changelog/19632.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_launch_configuration: Add `throughput` argument to `ebs_block_device` and `root_block_device` configuration blocks to support GP3 volumes +``` \ No newline at end of file From 859b56536cc8160a305e5a8497429c29caa150dd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 15:04:00 -0400 Subject: [PATCH 0193/1208] d/aws_launch_configuration: Add 'throughput' attribute to 'ebs_block_device' and 'root_block_device' configuration blocks to support GP3 volumes. --- .changelog/19632.txt | 4 +++ aws/data_source_aws_launch_configuration.go | 22 ++++++++---- aws/resource_aws_launch_configuration.go | 34 +++++++++---------- .../docs/d/launch_configuration.html.markdown | 6 ++-- 4 files changed, 41 insertions(+), 25 deletions(-) diff --git a/.changelog/19632.txt b/.changelog/19632.txt index bcced0890342..12cd701def3b 100644 --- a/.changelog/19632.txt +++ b/.changelog/19632.txt @@ -1,3 +1,7 @@ ```release-note:enhancement resource/aws_launch_configuration: Add `throughput` argument to `ebs_block_device` and `root_block_device` configuration blocks to support GP3 volumes +``` + +```release-note:enhancement +data-source/aws_launch_configuration: Add `throughput` attribute to `ebs_block_device` and `root_block_device` configuration blocks to support GP3 volumes ``` \ No newline at end of file diff --git a/aws/data_source_aws_launch_configuration.go b/aws/data_source_aws_launch_configuration.go index 76b673b4eb57..88acbc0a0d31 100644 --- a/aws/data_source_aws_launch_configuration.go +++ b/aws/data_source_aws_launch_configuration.go @@ -105,7 +105,7 @@ func dataSourceAwsLaunchConfiguration() *schema.Resource { Computed: true, }, - "no_device": { + "encrypted": { Type: schema.TypeBool, Computed: true, }, @@ -115,11 +115,21 @@ func dataSourceAwsLaunchConfiguration() *schema.Resource { Computed: true, }, + "no_device": { + Type: schema.TypeBool, + Computed: true, + }, + "snapshot_id": { Type: schema.TypeString, Computed: true, }, + "throughput": { + Type: schema.TypeBool, + Computed: true, + }, + "volume_size": { Type: schema.TypeInt, Computed: true, @@ -129,11 +139,6 @@ func dataSourceAwsLaunchConfiguration() *schema.Resource { Type: schema.TypeString, Computed: true, }, - - "encrypted": { - Type: schema.TypeBool, - Computed: true, - }, }, }, }, @@ -197,6 +202,11 @@ func dataSourceAwsLaunchConfiguration() *schema.Resource { Computed: true, }, + "throughput": { + Type: schema.TypeBool, + Computed: true, + }, + "volume_size": { Type: schema.TypeInt, Computed: true, diff --git a/aws/resource_aws_launch_configuration.go b/aws/resource_aws_launch_configuration.go index d56a0ab1b59d..f111f6e76be2 100644 --- a/aws/resource_aws_launch_configuration.go +++ b/aws/resource_aws_launch_configuration.go @@ -178,9 +178,10 @@ func resourceAwsLaunchConfiguration() *schema.Resource { ForceNew: true, }, - "no_device": { + "encrypted": { Type: schema.TypeBool, Optional: true, + Computed: true, ForceNew: true, }, @@ -191,36 +192,35 @@ func resourceAwsLaunchConfiguration() *schema.Resource { ForceNew: true, }, - "snapshot_id": { - Type: schema.TypeString, + "no_device": { + Type: schema.TypeBool, Optional: true, - Computed: true, ForceNew: true, }, - "volume_size": { - Type: schema.TypeInt, + "snapshot_id": { + Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, - "volume_type": { - Type: schema.TypeString, + "throughput": { + Type: schema.TypeInt, Optional: true, Computed: true, ForceNew: true, }, - "encrypted": { - Type: schema.TypeBool, + "volume_size": { + Type: schema.TypeInt, Optional: true, Computed: true, ForceNew: true, }, - "throughput": { - Type: schema.TypeInt, + "volume_type": { + Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, @@ -319,22 +319,22 @@ func resourceAwsLaunchConfiguration() *schema.Resource { ForceNew: true, }, - "volume_size": { + "throughput": { Type: schema.TypeInt, Optional: true, Computed: true, ForceNew: true, }, - "volume_type": { - Type: schema.TypeString, + "volume_size": { + Type: schema.TypeInt, Optional: true, Computed: true, ForceNew: true, }, - "throughput": { - Type: schema.TypeInt, + "volume_type": { + Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, diff --git a/website/docs/d/launch_configuration.html.markdown b/website/docs/d/launch_configuration.html.markdown index 1fb1edfa3cf8..33c7ea4dd732 100644 --- a/website/docs/d/launch_configuration.html.markdown +++ b/website/docs/d/launch_configuration.html.markdown @@ -57,6 +57,7 @@ In addition to all arguments above, the following attributes are exported: * `delete_on_termination` - Whether the EBS Volume will be deleted on instance termination. * `encrypted` - Whether the volume is Encrypted. * `iops` - The provisioned IOPs of the volume. +* `throughput` - The Throughput of the volume. * `volume_size` - The Size of the volume. * `volume_type` - The Type of the volume. @@ -64,12 +65,13 @@ In addition to all arguments above, the following attributes are exported: * `delete_on_termination` - Whether the EBS Volume will be deleted on instance termination. * `device_name` - The Name of the device. -* `no_device` - Whether the device in the block device mapping of the AMI is suppressed. +* `encrypted` - Whether the volume is Encrypted. * `iops` - The provisioned IOPs of the volume. +* `no_device` - Whether the device in the block device mapping of the AMI is suppressed. * `snapshot_id` - The Snapshot ID of the mount. +* `throughput` - The Throughput of the volume. * `volume_size` - The Size of the volume. * `volume_type` - The Type of the volume. -* `encrypted` - Whether the volume is Encrypted. `ephemeral_block_device` is exported with the following attributes: From 779b16224978f49c9bd95605a99fa021f028183c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 15:04:58 -0400 Subject: [PATCH 0194/1208] Skip invalid volume type errors on GovCloud. --- aws/resource_aws_autoscaling_group_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/aws/resource_aws_autoscaling_group_test.go b/aws/resource_aws_autoscaling_group_test.go index 634dc59fcb23..b5208464a573 100644 --- a/aws/resource_aws_autoscaling_group_test.go +++ b/aws/resource_aws_autoscaling_group_test.go @@ -21,12 +21,20 @@ import ( ) func init() { + RegisterServiceErrorCheckFunc(autoscaling.EndpointsID, testAccErrorCheckSkipAutoScaling) + resource.AddTestSweepers("aws_autoscaling_group", &resource.Sweeper{ Name: "aws_autoscaling_group", F: testSweepAutoscalingGroups, }) } +func testAccErrorCheckSkipAutoScaling(t *testing.T) resource.ErrorCheckFunc { + return testAccErrorCheckSkipMessagesContaining(t, + "gp3 is invalid", + ) +} + func testSweepAutoscalingGroups(region string) error { client, err := sharedClientForRegion(region) if err != nil { From 55d75758cd1770025c25b5dc022086126089aac1 Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Fri, 7 Feb 2020 01:31:02 +0900 Subject: [PATCH 0195/1208] Add aws_amplify_webhook resource --- aws/provider.go | 1 + aws/resource_aws_amplify_webhook.go | 145 +++++++++++++++++++ aws/resource_aws_amplify_webhook_test.go | 135 +++++++++++++++++ website/docs/r/amplify_webhook.html.markdown | 53 +++++++ 4 files changed, 334 insertions(+) create mode 100644 aws/resource_aws_amplify_webhook.go create mode 100644 aws/resource_aws_amplify_webhook_test.go create mode 100644 website/docs/r/amplify_webhook.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 4fd4105c5633..74fd8c21cb99 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -456,6 +456,7 @@ func Provider() *schema.Provider { "aws_amplify_app": resourceAwsAmplifyApp(), "aws_amplify_backend_environment": resourceAwsAmplifyBackendEnvironment(), "aws_amplify_branch": resourceAwsAmplifyBranch(), + "aws_amplify_webhook": resourceAwsAmplifyWebhook(), "aws_api_gateway_account": resourceAwsApiGatewayAccount(), "aws_api_gateway_api_key": resourceAwsApiGatewayApiKey(), "aws_api_gateway_authorizer": resourceAwsApiGatewayAuthorizer(), diff --git a/aws/resource_aws_amplify_webhook.go b/aws/resource_aws_amplify_webhook.go new file mode 100644 index 000000000000..4707d8682e4e --- /dev/null +++ b/aws/resource_aws_amplify_webhook.go @@ -0,0 +1,145 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func resourceAwsAmplifyWebhook() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAmplifyWebhookCreate, + Read: resourceAwsAmplifyWebhookRead, + Update: resourceAwsAmplifyWebhookUpdate, + Delete: resourceAwsAmplifyWebhookDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "app_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "branch_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 255), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9/_.-]+$`), "should only contain letters, numbers, and the symbols /_.-"), + ), + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "url": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsAmplifyWebhookCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Print("[DEBUG] Creating Amplify Webhook") + + params := &lify.CreateWebhookInput{ + AppId: aws.String(d.Get("app_id").(string)), + BranchName: aws.String(d.Get("branch_name").(string)), + } + + if v, ok := d.GetOk("description"); ok { + params.Description = aws.String(v.(string)) + } + + resp, err := conn.CreateWebhook(params) + if err != nil { + return fmt.Errorf("Error creating Amplify Webhook: %s", err) + } + + d.SetId(*resp.Webhook.WebhookId) + + return resourceAwsAmplifyWebhookRead(d, meta) +} + +func resourceAwsAmplifyWebhookRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Reading Amplify Webhook: %s", d.Id()) + + resp, err := conn.GetWebhook(&lify.GetWebhookInput{ + WebhookId: aws.String(d.Id()), + }) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == amplify.ErrCodeNotFoundException { + log.Printf("[WARN] Amplify Webhook (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + return err + } + + s := strings.Split(aws.StringValue(resp.Webhook.WebhookArn), "/") + app_id := s[1] + + d.Set("app_id", app_id) + d.Set("branch_name", resp.Webhook.BranchName) + d.Set("description", resp.Webhook.Description) + d.Set("arn", resp.Webhook.WebhookArn) + d.Set("url", resp.Webhook.WebhookUrl) + + return nil +} + +func resourceAwsAmplifyWebhookUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Updating Amplify Webhook: %s", d.Id()) + + params := &lify.UpdateWebhookInput{ + WebhookId: aws.String(d.Id()), + } + + if d.HasChange("branch_name") { + params.BranchName = aws.String(d.Get("branch_name").(string)) + } + + if d.HasChange("description") { + params.Description = aws.String(d.Get("description").(string)) + } + + _, err := conn.UpdateWebhook(params) + if err != nil { + return fmt.Errorf("Error updating Amplify Webhook: %s", err) + } + + return resourceAwsAmplifyWebhookRead(d, meta) +} + +func resourceAwsAmplifyWebhookDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Deleting Amplify Webhook: %s", d.Id()) + + params := &lify.DeleteWebhookInput{ + WebhookId: aws.String(d.Id()), + } + + _, err := conn.DeleteWebhook(params) + if err != nil { + return fmt.Errorf("Error deleting Amplify Webhook: %s", err) + } + + return nil +} diff --git a/aws/resource_aws_amplify_webhook_test.go b/aws/resource_aws_amplify_webhook_test.go new file mode 100644 index 000000000000..08a9a8c1694e --- /dev/null +++ b/aws/resource_aws_amplify_webhook_test.go @@ -0,0 +1,135 @@ +package aws + +import ( + "fmt" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccAWSAmplifyWebhook_basic(t *testing.T) { + var webhook amplify.Webhook + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_webhook.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyWebhookDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyWebhookConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyWebhookExists(resourceName, &webhook), + resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/webhooks/[^/]+$")), + resource.TestMatchResourceAttr(resourceName, "url", regexp.MustCompile("^https://webhooks.amplify.")), + resource.TestCheckResourceAttr(resourceName, "branch_name", "master"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAmplifyWebhookConfigAll(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "description", "triggermaster"), + ), + }, + }, + }) +} + +func testAccCheckAWSAmplifyWebhookExists(resourceName string, v *amplify.Webhook) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + output, err := conn.GetWebhook(&lify.GetWebhookInput{ + WebhookId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + + if output == nil || output.Webhook == nil { + return fmt.Errorf("Amplify Webhook (%s) not found", rs.Primary.ID) + } + + *v = *output.Webhook + + return nil + } +} + +func testAccCheckAWSAmplifyWebhookDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_amplify_webhook" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + _, err := conn.GetWebhook(&lify.GetWebhookInput{ + WebhookId: aws.String(rs.Primary.ID), + }) + + if isAWSErr(err, amplify.ErrCodeNotFoundException, "") { + continue + } + + if err != nil { + return err + } + } + + return nil +} + +func testAccAWSAmplifyWebhookConfig_Required(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" +} + +resource "aws_amplify_webhook" "test" { + app_id = aws_amplify_app.test.id + branch_name = aws_amplify_branch.test.branch_name +} +`, rName) +} + +func testAccAWSAmplifyWebhookConfigAll(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" +} + +resource "aws_amplify_webhook" "test" { + app_id = aws_amplify_app.test.id + branch_name = aws_amplify_branch.test.branch_name + description = "triggermaster" +} +`, rName) +} diff --git a/website/docs/r/amplify_webhook.html.markdown b/website/docs/r/amplify_webhook.html.markdown new file mode 100644 index 000000000000..5c67836e90b4 --- /dev/null +++ b/website/docs/r/amplify_webhook.html.markdown @@ -0,0 +1,53 @@ +--- +subcategory: "Amplify" +layout: "aws" +page_title: "AWS: aws_amplify_webhook" +description: |- + Provides an Amplify webhook resource. +--- + +# Resource: aws_amplify_webhook + +Provides an Amplify webhook resource. + +## Example Usage + +```hcl +resource "aws_amplify_app" "app" { + name = "app" +} + +resource "aws_amplify_branch" "master" { + app_id = aws_amplify_app.app.id + branch_name = "master" +} + +resource "aws_amplify_webhook" "master" { + app_id = aws_amplify_app.app.id + branch_name = aws_amplify_branch.master.branch_name + description = "triggermaster" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `app_id` - (Required) Unique Id for an Amplify App. +* `branch_name` - (Required) Name for a branch. +* `description` - (Optional) Description for a webhook + +## Attribute Reference + +The following attributes are exported: + +* `arn` - ARN for the webhook. +* `url` - Url of the webhook. + +## Import + +Amplify webhook can be imported using a webhook ID (webhookId), e.g. + +``` +$ terraform import aws_amplify_webhook.master a26b22a0-748b-4b57-b9a0-ae7e601fe4b1 +``` From 29f5a374ad5ae918405fb4c4530ef907519f6a5d Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Sat, 15 Feb 2020 02:59:16 +0900 Subject: [PATCH 0196/1208] use "${}" in docs --- website/docs/r/amplify_webhook.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/amplify_webhook.html.markdown b/website/docs/r/amplify_webhook.html.markdown index 5c67836e90b4..e166b6cdcbcc 100644 --- a/website/docs/r/amplify_webhook.html.markdown +++ b/website/docs/r/amplify_webhook.html.markdown @@ -18,13 +18,13 @@ resource "aws_amplify_app" "app" { } resource "aws_amplify_branch" "master" { - app_id = aws_amplify_app.app.id + app_id = "${aws_amplify_app.app.id}" branch_name = "master" } resource "aws_amplify_webhook" "master" { - app_id = aws_amplify_app.app.id - branch_name = aws_amplify_branch.master.branch_name + app_id = "${aws_amplify_app.app.id}" + branch_name = "${aws_amplify_branch.master.branch_name}" description = "triggermaster" } ``` From 9786566b06241fec6906defefe3d70f4b04b1a1a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 15:30:52 -0400 Subject: [PATCH 0197/1208] r/aws_amplify_webhook: Building with Plugin SDK v2. --- aws/resource_aws_amplify_test.go | 3 ++ aws/resource_aws_amplify_webhook.go | 19 ++++++------ aws/resource_aws_amplify_webhook_test.go | 8 ++--- website/docs/r/amplify_webhook.html.markdown | 32 ++++++++++---------- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index 03e39da1c05c..a796ea1f63c1 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -35,6 +35,9 @@ func TestAccAWSAmplify_serial(t *testing.T) { "EnvironmentVariables": testAccAWSAmplifyBranch_EnvironmentVariables, "OptionalArguments": testAccAWSAmplifyBranch_OptionalArguments, }, + "Webhook": { + "basic": testAccAWSAmplifyWebhook_basic, + }, } for group, m := range testCases { diff --git a/aws/resource_aws_amplify_webhook.go b/aws/resource_aws_amplify_webhook.go index 4707d8682e4e..b8414fbded2f 100644 --- a/aws/resource_aws_amplify_webhook.go +++ b/aws/resource_aws_amplify_webhook.go @@ -9,8 +9,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/amplify" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func resourceAwsAmplifyWebhook() *schema.Resource { @@ -28,23 +28,24 @@ func resourceAwsAmplifyWebhook() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "app_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "branch_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 255), - validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9/_.-]+$`), "should only contain letters, numbers, and the symbols /_.-"), - ), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[0-9A-Za-z/_.-]{1,255}$`), "should be not be more than 255 letters, numbers, and the symbols /_.-"), }, + "description": { Type: schema.TypeString, Optional: true, }, + "url": { Type: schema.TypeString, Computed: true, @@ -55,7 +56,6 @@ func resourceAwsAmplifyWebhook() *schema.Resource { func resourceAwsAmplifyWebhookCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Print("[DEBUG] Creating Amplify Webhook") params := &lify.CreateWebhookInput{ AppId: aws.String(d.Get("app_id").(string)), @@ -78,7 +78,6 @@ func resourceAwsAmplifyWebhookCreate(d *schema.ResourceData, meta interface{}) e func resourceAwsAmplifyWebhookRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Reading Amplify Webhook: %s", d.Id()) resp, err := conn.GetWebhook(&lify.GetWebhookInput{ WebhookId: aws.String(d.Id()), diff --git a/aws/resource_aws_amplify_webhook_test.go b/aws/resource_aws_amplify_webhook_test.go index 08a9a8c1694e..ef4372f693b2 100644 --- a/aws/resource_aws_amplify_webhook_test.go +++ b/aws/resource_aws_amplify_webhook_test.go @@ -7,12 +7,12 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "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 TestAccAWSAmplifyWebhook_basic(t *testing.T) { +func testAccAWSAmplifyWebhook_basic(t *testing.T) { var webhook amplify.Webhook rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_webhook.test" diff --git a/website/docs/r/amplify_webhook.html.markdown b/website/docs/r/amplify_webhook.html.markdown index e166b6cdcbcc..2a0ea85bb965 100644 --- a/website/docs/r/amplify_webhook.html.markdown +++ b/website/docs/r/amplify_webhook.html.markdown @@ -1,30 +1,30 @@ --- -subcategory: "Amplify" +subcategory: "Amplify Console" layout: "aws" page_title: "AWS: aws_amplify_webhook" description: |- - Provides an Amplify webhook resource. + Provides an Amplify Webhook resource. --- # Resource: aws_amplify_webhook -Provides an Amplify webhook resource. +Provides an Amplify Webhook resource. ## Example Usage -```hcl -resource "aws_amplify_app" "app" { +```terraform +resource "aws_amplify_app" "example" { name = "app" } resource "aws_amplify_branch" "master" { - app_id = "${aws_amplify_app.app.id}" + app_id = aws_amplify_app.example.id branch_name = "master" } resource "aws_amplify_webhook" "master" { - app_id = "${aws_amplify_app.app.id}" - branch_name = "${aws_amplify_branch.master.branch_name}" + app_id = aws_amplify_app.example.id + branch_name = aws_amplify_branch.master.branch_name description = "triggermaster" } ``` @@ -33,20 +33,20 @@ resource "aws_amplify_webhook" "master" { The following arguments are supported: -* `app_id` - (Required) Unique Id for an Amplify App. -* `branch_name` - (Required) Name for a branch. -* `description` - (Optional) Description for a webhook +* `app_id` - (Required) The unique ID for an Amplify app. +* `branch_name` - (Required) The name for a branch that is part of the Amplify app. +* `description` - (Optional) The description for a webhook. -## Attribute Reference +## Attributes Reference -The following attributes are exported: +In addition to all arguments above, the following attributes are exported: -* `arn` - ARN for the webhook. -* `url` - Url of the webhook. +* `arn` - The Amazon Resource Name (ARN) for the webhook. +* `url` - The URL of the webhook. ## Import -Amplify webhook can be imported using a webhook ID (webhookId), e.g. +Amplify webhook can be imported using a webhook ID, e.g. ``` $ terraform import aws_amplify_webhook.master a26b22a0-748b-4b57-b9a0-ae7e601fe4b1 From f62d0f9c396bfef8daee47d12f81b90ecc38a4bf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 15:31:58 -0400 Subject: [PATCH 0198/1208] Add CHANGELOG entry. --- .changelog/11939.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/11939.txt diff --git a/.changelog/11939.txt b/.changelog/11939.txt new file mode 100644 index 000000000000..7555c387a8ce --- /dev/null +++ b/.changelog/11939.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_amplify_webhook +``` \ No newline at end of file From 46f9ca66461e9ca684f615a5a3273bcfbd2a9821 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 2 Jun 2021 19:36:13 +0000 Subject: [PATCH 0199/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09907417efe4..d3b62cfddd22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,19 +2,23 @@ FEATURES: +* **New Resource:** `aws_amplify_branch` ([#11937](https://github.com/hashicorp/terraform-provider-aws/issues/11937)) * **New Resource:** `aws_servicecatalog_principal_portfolio_association` ([#19470](https://github.com/hashicorp/terraform-provider-aws/issues/19470)) ENHANCEMENTS: +* data-source/aws_launch_configuration: Add `throughput` attribute to `ebs_block_device` and `root_block_device` configuration blocks to support GP3 volumes ([#19632](https://github.com/hashicorp/terraform-provider-aws/issues/19632)) * resource/aws_acmpca_certificate_authority: Add `s3_object_acl` argument to `revocation_configuration.crl_configuration` configuration block ([#19578](https://github.com/hashicorp/terraform-provider-aws/issues/19578)) * resource/aws_cloudwatch_log_metric_filter: Add `dimensions` argument to `metric_transformation` configuration block ([#19625](https://github.com/hashicorp/terraform-provider-aws/issues/19625)) * resource/aws_cloudwatch_metric_alarm: Add plan time validation to `metric_query.metric.stat`. ([#19571](https://github.com/hashicorp/terraform-provider-aws/issues/19571)) * resource/aws_devicefarm_project: Add `default_job_timeout_minutes` and `tags` argument ([#19574](https://github.com/hashicorp/terraform-provider-aws/issues/19574)) * resource/aws_devicefarm_project: Add plan time validation for `name` ([#19574](https://github.com/hashicorp/terraform-provider-aws/issues/19574)) * resource/aws_fsx_lustre_filesystem: Allow updating `storage_capacity`. ([#19568](https://github.com/hashicorp/terraform-provider-aws/issues/19568)) +* resource/aws_launch_configuration: Add `throughput` argument to `ebs_block_device` and `root_block_device` configuration blocks to support GP3 volumes ([#19632](https://github.com/hashicorp/terraform-provider-aws/issues/19632)) BUG FIXES: +* resource/aws_amplify_app: Mark the `enable_performance_mode` argumnet in the `auto_branch_creation_config` configuration block as `ForceNew` ([#11937](https://github.com/hashicorp/terraform-provider-aws/issues/11937)) * resource/aws_elasticache_cluster: Fix provider-level `default_tags` support for resource ([#19615](https://github.com/hashicorp/terraform-provider-aws/issues/19615)) * resource/aws_iam_access_key: Fix status not defaulting to Active ([#19606](https://github.com/hashicorp/terraform-provider-aws/issues/19606)) From 54084002aff5bdcc413ecaadf8037e6fd66b79d1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 16:11:46 -0400 Subject: [PATCH 0200/1208] Spelling correction. --- .changelog/11937.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/11937.txt b/.changelog/11937.txt index 106a416f8af3..9da502923d73 100644 --- a/.changelog/11937.txt +++ b/.changelog/11937.txt @@ -3,5 +3,5 @@ aws_amplify_branch ``` ```release-note:bug -resource/aws_amplify_app: Mark the `enable_performance_mode` argumnet in the `auto_branch_creation_config` configuration block as `ForceNew` +resource/aws_amplify_app: Mark the `enable_performance_mode` argument in the `auto_branch_creation_config` configuration block as `ForceNew` ``` \ No newline at end of file From 4882b127521d9534846bd6666286c04b9ec00a24 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 2 Jun 2021 17:03:22 -0400 Subject: [PATCH 0201/1208] r/aws_amplify_webhook: All tests passing. --- aws/internal/service/amplify/finder/finder.go | 28 ++++ aws/resource_aws_amplify_test.go | 4 +- aws/resource_aws_amplify_webhook.go | 84 ++++++---- aws/resource_aws_amplify_webhook_test.go | 149 ++++++++++++++---- 4 files changed, 199 insertions(+), 66 deletions(-) diff --git a/aws/internal/service/amplify/finder/finder.go b/aws/internal/service/amplify/finder/finder.go index 7074fabb4c26..ec468523b9f6 100644 --- a/aws/internal/service/amplify/finder/finder.go +++ b/aws/internal/service/amplify/finder/finder.go @@ -92,3 +92,31 @@ func BranchByAppIDAndBranchName(conn *amplify.Amplify, appID, branchName string) return output.Branch, nil } + +func WebhookByID(conn *amplify.Amplify, id string) (*amplify.Webhook, error) { + input := &lify.GetWebhookInput{ + WebhookId: aws.String(id), + } + + output, err := conn.GetWebhook(input) + + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Webhook == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.Webhook, nil +} diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index a796ea1f63c1..c238c783c873 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -36,7 +36,9 @@ func TestAccAWSAmplify_serial(t *testing.T) { "OptionalArguments": testAccAWSAmplifyBranch_OptionalArguments, }, "Webhook": { - "basic": testAccAWSAmplifyWebhook_basic, + "basic": testAccAWSAmplifyWebhook_basic, + "disappears": testAccAWSAmplifyWebhook_disappears, + "update": testAccAWSAmplifyWebhook_update, }, } diff --git a/aws/resource_aws_amplify_webhook.go b/aws/resource_aws_amplify_webhook.go index b8414fbded2f..fe66597b64d4 100644 --- a/aws/resource_aws_amplify_webhook.go +++ b/aws/resource_aws_amplify_webhook.go @@ -7,10 +7,13 @@ import ( "strings" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/amplify" + "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/service/amplify/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsAmplifyWebhook() *schema.Resource { @@ -57,21 +60,23 @@ func resourceAwsAmplifyWebhook() *schema.Resource { func resourceAwsAmplifyWebhookCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - params := &lify.CreateWebhookInput{ + input := &lify.CreateWebhookInput{ AppId: aws.String(d.Get("app_id").(string)), BranchName: aws.String(d.Get("branch_name").(string)), } if v, ok := d.GetOk("description"); ok { - params.Description = aws.String(v.(string)) + input.Description = aws.String(v.(string)) } - resp, err := conn.CreateWebhook(params) + log.Printf("[DEBUG] Creating Amplify Webhook: %s", input) + output, err := conn.CreateWebhook(input) + if err != nil { - return fmt.Errorf("Error creating Amplify Webhook: %s", err) + return fmt.Errorf("error creating Amplify Webhook: %w", err) } - d.SetId(*resp.Webhook.WebhookId) + d.SetId(aws.StringValue(output.Webhook.WebhookId)) return resourceAwsAmplifyWebhookRead(d, meta) } @@ -79,49 +84,61 @@ func resourceAwsAmplifyWebhookCreate(d *schema.ResourceData, meta interface{}) e func resourceAwsAmplifyWebhookRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - resp, err := conn.GetWebhook(&lify.GetWebhookInput{ - WebhookId: aws.String(d.Id()), - }) + webhook, err := finder.WebhookByID(conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Amplify Webhook (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == amplify.ErrCodeNotFoundException { - log.Printf("[WARN] Amplify Webhook (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - return err + return fmt.Errorf("error reading Amplify Webhook (%s): %w", d.Id(), err) } - s := strings.Split(aws.StringValue(resp.Webhook.WebhookArn), "/") - app_id := s[1] + webhookArn := aws.StringValue(webhook.WebhookArn) + arn, err := arn.Parse(webhookArn) + + if err != nil { + return fmt.Errorf("error parsing %q: %w", webhookArn, err) + } - d.Set("app_id", app_id) - d.Set("branch_name", resp.Webhook.BranchName) - d.Set("description", resp.Webhook.Description) - d.Set("arn", resp.Webhook.WebhookArn) - d.Set("url", resp.Webhook.WebhookUrl) + // arn:${Partition}:amplify:${Region}:${Account}:apps/${AppId}/webhooks/${WebhookId} + parts := strings.Split(arn.Resource, "/") + + if len(parts) != 4 { + return fmt.Errorf("unexpected format for ARN resource (%s)", arn.Resource) + } + + d.Set("app_id", parts[1]) + d.Set("arn", webhookArn) + d.Set("branch_name", webhook.BranchName) + d.Set("description", webhook.Description) + d.Set("url", webhook.WebhookUrl) return nil } func resourceAwsAmplifyWebhookUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Updating Amplify Webhook: %s", d.Id()) - params := &lify.UpdateWebhookInput{ + input := &lify.UpdateWebhookInput{ WebhookId: aws.String(d.Id()), } if d.HasChange("branch_name") { - params.BranchName = aws.String(d.Get("branch_name").(string)) + input.BranchName = aws.String(d.Get("branch_name").(string)) } if d.HasChange("description") { - params.Description = aws.String(d.Get("description").(string)) + input.Description = aws.String(d.Get("description").(string)) } - _, err := conn.UpdateWebhook(params) + log.Printf("[DEBUG] Updating Amplify Webhook: %s", input) + _, err := conn.UpdateWebhook(input) + if err != nil { - return fmt.Errorf("Error updating Amplify Webhook: %s", err) + return fmt.Errorf("error updating Amplify Webhook (%s): %w", d.Id(), err) } return resourceAwsAmplifyWebhookRead(d, meta) @@ -129,15 +146,18 @@ func resourceAwsAmplifyWebhookUpdate(d *schema.ResourceData, meta interface{}) e func resourceAwsAmplifyWebhookDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Deleting Amplify Webhook: %s", d.Id()) - params := &lify.DeleteWebhookInput{ + log.Printf("[DEBUG] Deleting Amplify Webhook: %s", d.Id()) + _, err := conn.DeleteWebhook(&lify.DeleteWebhookInput{ WebhookId: aws.String(d.Id()), + }) + + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeNotFoundException) { + return nil } - _, err := conn.DeleteWebhook(params) if err != nil { - return fmt.Errorf("Error deleting Amplify Webhook: %s", err) + return fmt.Errorf("error deleting Amplify Webhook (%s): %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_amplify_webhook_test.go b/aws/resource_aws_amplify_webhook_test.go index ef4372f693b2..18beddc6fb4a 100644 --- a/aws/resource_aws_amplify_webhook_test.go +++ b/aws/resource_aws_amplify_webhook_test.go @@ -5,11 +5,12 @@ import ( "regexp" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func testAccAWSAmplifyWebhook_basic(t *testing.T) { @@ -18,18 +19,70 @@ func testAccAWSAmplifyWebhook_basic(t *testing.T) { resourceName := "aws_amplify_webhook.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyWebhookDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyWebhookConfig_Required(rName), - Check: resource.ComposeTestCheckFunc( + Config: testAccAWSAmplifyWebhookConfig(rName), + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSAmplifyWebhookExists(resourceName, &webhook), - resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/webhooks/[^/]+$")), - resource.TestMatchResourceAttr(resourceName, "url", regexp.MustCompile("^https://webhooks.amplify.")), - resource.TestCheckResourceAttr(resourceName, "branch_name", "master"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+/webhooks/.+`)), + resource.TestCheckResourceAttr(resourceName, "branch_name", rName), resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestMatchResourceAttr(resourceName, "url", regexp.MustCompile(fmt.Sprintf(`^https://webhooks.amplify.%s.%s/.+$`, testAccGetRegion(), testAccGetPartitionDNSSuffix()))), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAWSAmplifyWebhook_disappears(t *testing.T) { + var webhook amplify.Webhook + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_webhook.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyWebhookDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyWebhookConfig(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSAmplifyWebhookExists(resourceName, &webhook), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAmplifyWebhook(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccAWSAmplifyWebhook_update(t *testing.T) { + var webhook amplify.Webhook + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_webhook.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyWebhookDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyWebhookConfigDescription(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSAmplifyWebhookExists(resourceName, &webhook), + resource.TestCheckResourceAttr(resourceName, "branch_name", fmt.Sprintf("%s-1", rName)), + resource.TestCheckResourceAttr(resourceName, "description", "testdescription1"), ), }, { @@ -38,9 +91,11 @@ func testAccAWSAmplifyWebhook_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSAmplifyWebhookConfigAll(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "description", "triggermaster"), + Config: testAccAWSAmplifyWebhookConfigDescriptionUpdated(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSAmplifyWebhookExists(resourceName, &webhook), + resource.TestCheckResourceAttr(resourceName, "branch_name", fmt.Sprintf("%s-2", rName)), + resource.TestCheckResourceAttr(resourceName, "description", "testdescription2"), ), }, }, @@ -54,58 +109,57 @@ func testAccCheckAWSAmplifyWebhookExists(resourceName string, v *amplify.Webhook return fmt.Errorf("Not found: %s", resourceName) } + if rs.Primary.ID == "" { + return fmt.Errorf("No Amplify Webhook ID is set") + } + conn := testAccProvider.Meta().(*AWSClient).amplifyconn - output, err := conn.GetWebhook(&lify.GetWebhookInput{ - WebhookId: aws.String(rs.Primary.ID), - }) + webhook, err := finder.WebhookByID(conn, rs.Primary.ID) + if err != nil { return err } - if output == nil || output.Webhook == nil { - return fmt.Errorf("Amplify Webhook (%s) not found", rs.Primary.ID) - } - - *v = *output.Webhook + *v = *webhook return nil } } func testAccCheckAWSAmplifyWebhookDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_amplify_webhook" { continue } - conn := testAccProvider.Meta().(*AWSClient).amplifyconn - - _, err := conn.GetWebhook(&lify.GetWebhookInput{ - WebhookId: aws.String(rs.Primary.ID), - }) + _, err := finder.WebhookByID(conn, rs.Primary.ID) - if isAWSErr(err, amplify.ErrCodeNotFoundException, "") { + if tfresource.NotFound(err) { continue } if err != nil { return err } + + return fmt.Errorf("Amplify Webhook %s still exists", rs.Primary.ID) } return nil } -func testAccAWSAmplifyWebhookConfig_Required(rName string) string { +func testAccAWSAmplifyWebhookConfig(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q } resource "aws_amplify_branch" "test" { app_id = aws_amplify_app.test.id - branch_name = "master" + branch_name = %[1]q } resource "aws_amplify_webhook" "test" { @@ -115,21 +169,50 @@ resource "aws_amplify_webhook" "test" { `, rName) } -func testAccAWSAmplifyWebhookConfigAll(rName string) string { +func testAccAWSAmplifyWebhookConfigDescription(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q } -resource "aws_amplify_branch" "test" { +resource "aws_amplify_branch" "test1" { + app_id = aws_amplify_app.test.id + branch_name = "%[1]s-1" +} + +resource "aws_amplify_branch" "test2" { app_id = aws_amplify_app.test.id - branch_name = "master" + branch_name = "%[1]s-2" } resource "aws_amplify_webhook" "test" { app_id = aws_amplify_app.test.id - branch_name = aws_amplify_branch.test.branch_name - description = "triggermaster" + branch_name = aws_amplify_branch.test1.branch_name + description = "testdescription1" +} +`, rName) +} + +func testAccAWSAmplifyWebhookConfigDescriptionUpdated(rName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q +} + +resource "aws_amplify_branch" "test1" { + app_id = aws_amplify_app.test.id + branch_name = "%[1]s-1" +} + +resource "aws_amplify_branch" "test2" { + app_id = aws_amplify_app.test.id + branch_name = "%[1]s-2" +} + +resource "aws_amplify_webhook" "test" { + app_id = aws_amplify_app.test.id + branch_name = aws_amplify_branch.test2.branch_name + description = "testdescription2" } `, rName) } From ed9044585dcf249ebf3586c054bb7cf263055bed Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Fri, 7 Feb 2020 01:25:47 +0900 Subject: [PATCH 0202/1208] Add aws_amplify_domain_association resource --- aws/provider.go | 1 + ...resource_aws_amplify_domain_association.go | 287 ++++++++++++++++++ ...rce_aws_amplify_domain_association_test.go | 132 ++++++++ .../amplify_domain_association.html.markdown | 77 +++++ 4 files changed, 497 insertions(+) create mode 100644 aws/resource_aws_amplify_domain_association.go create mode 100644 aws/resource_aws_amplify_domain_association_test.go create mode 100644 website/docs/r/amplify_domain_association.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 74fd8c21cb99..20a1170763a4 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -456,6 +456,7 @@ func Provider() *schema.Provider { "aws_amplify_app": resourceAwsAmplifyApp(), "aws_amplify_backend_environment": resourceAwsAmplifyBackendEnvironment(), "aws_amplify_branch": resourceAwsAmplifyBranch(), + "aws_amplify_domain_association": resourceAwsAmplifyDomainAssociation(), "aws_amplify_webhook": resourceAwsAmplifyWebhook(), "aws_api_gateway_account": resourceAwsApiGatewayAccount(), "aws_api_gateway_api_key": resourceAwsApiGatewayApiKey(), diff --git a/aws/resource_aws_amplify_domain_association.go b/aws/resource_aws_amplify_domain_association.go new file mode 100644 index 000000000000..51d675f05dfb --- /dev/null +++ b/aws/resource_aws_amplify_domain_association.go @@ -0,0 +1,287 @@ +package aws + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceAwsAmplifyDomainAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsAmplifyDomainAssociationCreate, + Read: resourceAwsAmplifyDomainAssociationRead, + Update: resourceAwsAmplifyDomainAssociationUpdate, + Delete: resourceAwsAmplifyDomainAssociationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "app_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "domain_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "enable_auto_sub_domain": { + Type: schema.TypeBool, + Optional: true, + }, + "sub_domain_settings": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "branch_name": { + Type: schema.TypeString, + Required: true, + }, + "prefix": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + // non-API + "wait_for_verification": { + Type: schema.TypeBool, + Optional: true, + Default: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return true + }, + }, + }, + } +} + +func resourceAwsAmplifyDomainAssociationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Print("[DEBUG] Creating Amplify DomainAssociation") + + params := &lify.CreateDomainAssociationInput{ + AppId: aws.String(d.Get("app_id").(string)), + DomainName: aws.String(d.Get("domain_name").(string)), + } + + if v, ok := d.GetOk("sub_domain_settings"); ok { + params.SubDomainSettings = expandAmplifySubDomainSettings(v.([]interface{})) + } + + if v, ok := d.GetOk("enable_auto_sub_domain"); ok { + params.EnableAutoSubDomain = aws.Bool(v.(bool)) + } + + resp, err := conn.CreateDomainAssociation(params) + if err != nil { + return fmt.Errorf("Error creating Amplify DomainAssociation: %s", err) + } + + arn := *resp.DomainAssociation.DomainAssociationArn + d.SetId(arn[strings.Index(arn, ":apps/")+len(":apps/"):]) + + if d.Get("wait_for_verification").(bool) { + log.Printf("[DEBUG] Waiting until Amplify DomainAssociation (%s) is deployed", d.Id()) + if err := resourceAwsAmplifyDomainAssociationWaitUntilVerified(d.Id(), meta); err != nil { + return fmt.Errorf("error waiting until Amplify DomainAssociation (%s) is deployed: %s", d.Id(), err) + } + } + + return resourceAwsAmplifyDomainAssociationRead(d, meta) +} + +func resourceAwsAmplifyDomainAssociationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Reading Amplify DomainAssociation: %s", d.Id()) + + s := strings.Split(d.Id(), "/") + app_id := s[0] + domain_name := s[2] + + resp, err := conn.GetDomainAssociation(&lify.GetDomainAssociationInput{ + AppId: aws.String(app_id), + DomainName: aws.String(domain_name), + }) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == amplify.ErrCodeNotFoundException { + log.Printf("[WARN] Amplify DomainAssociation (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + return err + } + + d.Set("app_id", app_id) + d.Set("arn", resp.DomainAssociation.DomainAssociationArn) + d.Set("domain_name", resp.DomainAssociation.DomainName) + if err := d.Set("sub_domain_settings", flattenAmplifySubDomainSettings(resp.DomainAssociation.SubDomains)); err != nil { + return fmt.Errorf("error setting sub_domain_settings: %s", err) + } + d.Set("enable_auto_sub_domain", resp.DomainAssociation.EnableAutoSubDomain) + + return nil +} + +func resourceAwsAmplifyDomainAssociationUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Updating Amplify DomainAssociation: %s", d.Id()) + + s := strings.Split(d.Id(), "/") + app_id := s[0] + domain_name := s[2] + + params := &lify.UpdateDomainAssociationInput{ + AppId: aws.String(app_id), + DomainName: aws.String(domain_name), + } + + if d.HasChange("sub_domain_settings") { + params.SubDomainSettings = expandAmplifySubDomainSettings(d.Get("sub_domain_settings").([]interface{})) + } + + if d.HasChange("enable_auto_sub_domain") { + params.EnableAutoSubDomain = aws.Bool(d.Get("enable_auto_sub_domain").(bool)) + } + + _, err := conn.UpdateDomainAssociation(params) + if err != nil { + return fmt.Errorf("Error updating Amplify DomainAssociation: %s", err) + } + + if d.Get("wait_for_verification").(bool) { + log.Printf("[DEBUG] Waiting until Amplify DomainAssociation (%s) is deployed", d.Id()) + if err := resourceAwsAmplifyDomainAssociationWaitUntilVerified(d.Id(), meta); err != nil { + return fmt.Errorf("error waiting until Amplify DomainAssociation (%s) is deployed: %s", d.Id(), err) + } + } + + return resourceAwsAmplifyDomainAssociationRead(d, meta) +} + +func resourceAwsAmplifyDomainAssociationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).amplifyconn + log.Printf("[DEBUG] Deleting Amplify DomainAssociation: %s", d.Id()) + + s := strings.Split(d.Id(), "/") + app_id := s[0] + domain_name := s[2] + + params := &lify.DeleteDomainAssociationInput{ + AppId: aws.String(app_id), + DomainName: aws.String(domain_name), + } + + _, err := conn.DeleteDomainAssociation(params) + if err != nil { + return fmt.Errorf("Error deleting Amplify DomainAssociation: %s", err) + } + + return nil +} + +func resourceAwsAmplifyDomainAssociationWaitUntilVerified(id string, meta interface{}) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + amplify.DomainStatusPendingVerification, + amplify.DomainStatusInProgress, + amplify.DomainStatusCreating, + amplify.DomainStatusRequestingCertificate, + amplify.DomainStatusUpdating, + }, + Target: []string{ + // It takes up to 30 minutes, so skip waiting for deployment. + amplify.DomainStatusPendingDeployment, + amplify.DomainStatusAvailable, + }, + Refresh: resourceAwsAmplifyDomainAssociationStateRefreshFunc(id, meta), + Timeout: 15 * time.Minute, + MinTimeout: 15 * time.Second, + Delay: 10 * time.Second, + } + + _, err := stateConf.WaitForState() + return err +} + +func resourceAwsAmplifyDomainAssociationStateRefreshFunc(id string, meta interface{}) resource.StateRefreshFunc { + s := strings.Split(id, "/") + app_id := s[0] + domain_name := s[2] + + return func() (interface{}, string, error) { + conn := meta.(*AWSClient).amplifyconn + + resp, err := conn.GetDomainAssociation(&lify.GetDomainAssociationInput{ + AppId: aws.String(app_id), + DomainName: aws.String(domain_name), + }) + if err != nil { + log.Printf("[WARN] Error retrieving Amplify DomainAssociation %q details: %s", id, err) + return nil, "", err + } + + if *resp.DomainAssociation.DomainStatus == amplify.DomainStatusFailed { + return nil, "", fmt.Errorf("%s", *resp.DomainAssociation.StatusReason) + } + + return resp.DomainAssociation, *resp.DomainAssociation.DomainStatus, nil + } +} + +func expandAmplifySubDomainSettings(values []interface{}) []*amplify.SubDomainSetting { + settings := make([]*amplify.SubDomainSetting, 0) + + for _, v := range values { + e := v.(map[string]interface{}) + + setting := &lify.SubDomainSetting{} + + if ev, ok := e["branch_name"].(string); ok && ev != "" { + setting.BranchName = aws.String(ev) + } + + if ev, ok := e["prefix"].(string); ok { + setting.Prefix = aws.String(ev) + } + + settings = append(settings, setting) + } + + return settings +} + +func flattenAmplifySubDomainSettings(sub_domains []*amplify.SubDomain) []map[string]interface{} { + values := make([]map[string]interface{}, 0) + + for _, v := range sub_domains { + kv := make(map[string]interface{}) + + if v.SubDomainSetting.BranchName != nil { + kv["branch_name"] = *v.SubDomainSetting.BranchName + } + + if v.SubDomainSetting.Prefix != nil { + kv["prefix"] = *v.SubDomainSetting.Prefix + } + + values = append(values, kv) + } + + return values +} diff --git a/aws/resource_aws_amplify_domain_association_test.go b/aws/resource_aws_amplify_domain_association_test.go new file mode 100644 index 000000000000..f655bba79505 --- /dev/null +++ b/aws/resource_aws_amplify_domain_association_test.go @@ -0,0 +1,132 @@ +package aws + +import ( + "fmt" + "regexp" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccAWSAmplifyDomainAssociation_basic(t *testing.T) { + var domain amplify.DomainAssociation + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_domain_association.test" + + domainName := "example.com" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyDomainAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyDomainAssociationConfig_Required(rName, domainName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), + resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/domains/[^/]+$")), + resource.TestCheckResourceAttr(resourceName, "domain_name", domainName), + resource.TestCheckResourceAttr(resourceName, "sub_domain_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "sub_domain_settings.0.branch_name", "master"), + resource.TestCheckResourceAttr(resourceName, "sub_domain_settings.0.prefix", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"wait_for_verification"}, + }, + }, + }) +} + +func testAccCheckAWSAmplifyDomainAssociationExists(resourceName string, v *amplify.DomainAssociation) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + id := strings.Split(rs.Primary.ID, "/") + app_id := id[0] + domain_name := id[2] + + output, err := conn.GetDomainAssociation(&lify.GetDomainAssociationInput{ + AppId: aws.String(app_id), + DomainName: aws.String(domain_name), + }) + if err != nil { + return err + } + + if output == nil || output.DomainAssociation == nil { + return fmt.Errorf("Amplify DomainAssociation (%s) not found", rs.Primary.ID) + } + + *v = *output.DomainAssociation + + return nil + } +} + +func testAccCheckAWSAmplifyDomainAssociationDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_amplify_domain_association" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + s := strings.Split(rs.Primary.ID, "/") + app_id := s[0] + domain_name := s[2] + + _, err := conn.GetDomainAssociation(&lify.GetDomainAssociationInput{ + AppId: aws.String(app_id), + DomainName: aws.String(domain_name), + }) + + if isAWSErr(err, amplify.ErrCodeNotFoundException, "") { + continue + } + + if err != nil { + return err + } + } + + return nil +} + +func testAccAWSAmplifyDomainAssociationConfig_Required(rName string, domainName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = "%s" +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = "master" +} + +resource "aws_amplify_domain_association" "test" { + app_id = aws_amplify_app.test.id + domain_name = "%s" + + sub_domain_settings { + branch_name = aws_amplify_branch.test.branch_name + prefix = "" + } + + wait_for_verification = false +} +`, rName, domainName) +} diff --git a/website/docs/r/amplify_domain_association.html.markdown b/website/docs/r/amplify_domain_association.html.markdown new file mode 100644 index 000000000000..67aec0bf3f14 --- /dev/null +++ b/website/docs/r/amplify_domain_association.html.markdown @@ -0,0 +1,77 @@ +--- +subcategory: "Amplify" +layout: "aws" +page_title: "AWS: aws_amplify_domain_association" +description: |- + Provides an Amplify domain association resource. +--- + +# Resource: aws_amplify_domain_association + +Provides an Amplify domain association resource. + +## Example Usage + +```hcl +resource "aws_amplify_app" "app" { + name = "app" + + // Setup redirect from https://example.com to https://www.example.com + custom_rules { + source = "https://example.com" + status = "302" + target = "https://www.example.com" + } +} + +resource "aws_amplify_branch" "master" { + app_id = aws_amplify_app.app.id + branch_name = "master" +} + +resource "aws_amplify_domain_association" "app" { + app_id = aws_amplify_app.app.id + domain_name = "example.com" + + // https://example.com + sub_domain_settings { + branch_name = aws_amplify_branch.master.branch_name + prefix = "" + } + + // https://www.example.com + sub_domain_settings { + branch_name = aws_amplify_branch.master.branch_name + prefix = "www" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `app_id` - (Required) Unique Id for an Amplify App. +* `domain_name` - (Required) Domain name for the Domain Association. +* `sub_domain_settings` - (Required) Setting structure for the Subdomain. A `sub_domain_settings` block is documented below. +* `enable_auto_sub_domain` - (Optional) Enables automated creation of Subdomains for branches. (Currently not supported) +* `wait_for_verification` - (Optional) If enabled, the resource will wait for the domain association status to change to PENDING_DEPLOYMENT or AVAILABLE. Setting this to false will skip the process. Default: true. + +A `sub_domain_settings` block supports the following arguments: + +* `branch_name` - (Required) Branch name setting for the Subdomain. +* `prefix` - (Required) Prefix setting for the Subdomain. + +## Attribute Reference + +The following attributes are exported: + +* `arn` - ARN for the Domain Association. + +## Import + +Amplify domain association can be imported using `app_id` and `domain_name`, e.g. + +``` +$ terraform import aws_amplify_domain_association.app d2ypk4k47z8u6/domains/example.com +``` From 49a5ea0fc460db86b20c8c72b18c510f55a87fb8 Mon Sep 17 00:00:00 2001 From: Keisuke Nishida Date: Sat, 15 Feb 2020 02:58:31 +0900 Subject: [PATCH 0203/1208] use "${}" in docs --- website/docs/r/amplify_domain_association.html.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/r/amplify_domain_association.html.markdown b/website/docs/r/amplify_domain_association.html.markdown index 67aec0bf3f14..123c2f6d669c 100644 --- a/website/docs/r/amplify_domain_association.html.markdown +++ b/website/docs/r/amplify_domain_association.html.markdown @@ -25,23 +25,23 @@ resource "aws_amplify_app" "app" { } resource "aws_amplify_branch" "master" { - app_id = aws_amplify_app.app.id + app_id = "${aws_amplify_app.app.id}" branch_name = "master" } resource "aws_amplify_domain_association" "app" { - app_id = aws_amplify_app.app.id + app_id = "${aws_amplify_app.app.id}" domain_name = "example.com" // https://example.com sub_domain_settings { - branch_name = aws_amplify_branch.master.branch_name + branch_name = "${aws_amplify_branch.master.branch_name}" prefix = "" } // https://www.example.com sub_domain_settings { - branch_name = aws_amplify_branch.master.branch_name + branch_name = "${aws_amplify_branch.master.branch_name}" prefix = "www" } } From c2d6be3bed3a27f9e24853d03b0825d4d78f377f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Jun 2021 09:20:00 -0400 Subject: [PATCH 0204/1208] r/aws_amplify_domain_association: Building with Plugin SDK v2. --- ...resource_aws_amplify_domain_association.go | 44 +++++++-------- ...rce_aws_amplify_domain_association_test.go | 14 ++--- .../amplify_domain_association.html.markdown | 53 +++++++++---------- 3 files changed, 51 insertions(+), 60 deletions(-) diff --git a/aws/resource_aws_amplify_domain_association.go b/aws/resource_aws_amplify_domain_association.go index 51d675f05dfb..8453aed28e65 100644 --- a/aws/resource_aws_amplify_domain_association.go +++ b/aws/resource_aws_amplify_domain_association.go @@ -9,8 +9,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/amplify" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceAwsAmplifyDomainAssociation() *schema.Resource { @@ -24,27 +24,27 @@ func resourceAwsAmplifyDomainAssociation() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "arn": { - Type: schema.TypeString, - Computed: true, - }, "app_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, + + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "domain_name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "enable_auto_sub_domain": { - Type: schema.TypeBool, - Optional: true, - }, - "sub_domain_settings": { - Type: schema.TypeList, + + "sub_domain_setting": { + Type: schema.TypeSet, Required: true, + MaxItems: 255, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "branch_name": { @@ -58,6 +58,7 @@ func resourceAwsAmplifyDomainAssociation() *schema.Resource { }, }, }, + // non-API "wait_for_verification": { Type: schema.TypeBool, @@ -80,14 +81,10 @@ func resourceAwsAmplifyDomainAssociationCreate(d *schema.ResourceData, meta inte DomainName: aws.String(d.Get("domain_name").(string)), } - if v, ok := d.GetOk("sub_domain_settings"); ok { + if v, ok := d.GetOk("sub_domain_setting"); ok { params.SubDomainSettings = expandAmplifySubDomainSettings(v.([]interface{})) } - if v, ok := d.GetOk("enable_auto_sub_domain"); ok { - params.EnableAutoSubDomain = aws.Bool(v.(bool)) - } - resp, err := conn.CreateDomainAssociation(params) if err != nil { return fmt.Errorf("Error creating Amplify DomainAssociation: %s", err) @@ -130,10 +127,9 @@ func resourceAwsAmplifyDomainAssociationRead(d *schema.ResourceData, meta interf d.Set("app_id", app_id) d.Set("arn", resp.DomainAssociation.DomainAssociationArn) d.Set("domain_name", resp.DomainAssociation.DomainName) - if err := d.Set("sub_domain_settings", flattenAmplifySubDomainSettings(resp.DomainAssociation.SubDomains)); err != nil { - return fmt.Errorf("error setting sub_domain_settings: %s", err) + if err := d.Set("sub_domain_setting", flattenAmplifySubDomainSettings(resp.DomainAssociation.SubDomains)); err != nil { + return fmt.Errorf("error setting sub_domain_setting: %s", err) } - d.Set("enable_auto_sub_domain", resp.DomainAssociation.EnableAutoSubDomain) return nil } @@ -151,12 +147,8 @@ func resourceAwsAmplifyDomainAssociationUpdate(d *schema.ResourceData, meta inte DomainName: aws.String(domain_name), } - if d.HasChange("sub_domain_settings") { - params.SubDomainSettings = expandAmplifySubDomainSettings(d.Get("sub_domain_settings").([]interface{})) - } - - if d.HasChange("enable_auto_sub_domain") { - params.EnableAutoSubDomain = aws.Bool(d.Get("enable_auto_sub_domain").(bool)) + if d.HasChange("sub_domain_setting") { + params.SubDomainSettings = expandAmplifySubDomainSettings(d.Get("sub_domain_setting").([]interface{})) } _, err := conn.UpdateDomainAssociation(params) diff --git a/aws/resource_aws_amplify_domain_association_test.go b/aws/resource_aws_amplify_domain_association_test.go index f655bba79505..b1d1f6b43dff 100644 --- a/aws/resource_aws_amplify_domain_association_test.go +++ b/aws/resource_aws_amplify_domain_association_test.go @@ -8,9 +8,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "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 TestAccAWSAmplifyDomainAssociation_basic(t *testing.T) { @@ -31,9 +31,9 @@ func TestAccAWSAmplifyDomainAssociation_basic(t *testing.T) { testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/domains/[^/]+$")), resource.TestCheckResourceAttr(resourceName, "domain_name", domainName), - resource.TestCheckResourceAttr(resourceName, "sub_domain_settings.#", "1"), - resource.TestCheckResourceAttr(resourceName, "sub_domain_settings.0.branch_name", "master"), - resource.TestCheckResourceAttr(resourceName, "sub_domain_settings.0.prefix", ""), + resource.TestCheckResourceAttr(resourceName, "sub_domain_setting.#", "1"), + resource.TestCheckResourceAttr(resourceName, "sub_domain_setting.0.branch_name", "master"), + resource.TestCheckResourceAttr(resourceName, "sub_domain_setting.0.prefix", ""), ), }, { @@ -121,7 +121,7 @@ resource "aws_amplify_domain_association" "test" { app_id = aws_amplify_app.test.id domain_name = "%s" - sub_domain_settings { + sub_domain_setting { branch_name = aws_amplify_branch.test.branch_name prefix = "" } diff --git a/website/docs/r/amplify_domain_association.html.markdown b/website/docs/r/amplify_domain_association.html.markdown index 123c2f6d669c..9134f6112b8e 100644 --- a/website/docs/r/amplify_domain_association.html.markdown +++ b/website/docs/r/amplify_domain_association.html.markdown @@ -1,23 +1,23 @@ --- -subcategory: "Amplify" +subcategory: "Amplify Console" layout: "aws" page_title: "AWS: aws_amplify_domain_association" description: |- - Provides an Amplify domain association resource. + Provides an Amplify Domain Association resource. --- # Resource: aws_amplify_domain_association -Provides an Amplify domain association resource. +Provides an Amplify Domain Association resource. ## Example Usage -```hcl -resource "aws_amplify_app" "app" { +```terraform +resource "aws_amplify_app" "example" { name = "app" - // Setup redirect from https://example.com to https://www.example.com - custom_rules { + # Setup redirect from https://example.com to https://www.example.com + custom_rule { source = "https://example.com" status = "302" target = "https://www.example.com" @@ -25,23 +25,23 @@ resource "aws_amplify_app" "app" { } resource "aws_amplify_branch" "master" { - app_id = "${aws_amplify_app.app.id}" + app_id = aws_amplify_app.example.id branch_name = "master" } -resource "aws_amplify_domain_association" "app" { - app_id = "${aws_amplify_app.app.id}" +resource "aws_amplify_domain_association" "example" { + app_id = aws_amplify_app.example.id domain_name = "example.com" - // https://example.com - sub_domain_settings { - branch_name = "${aws_amplify_branch.master.branch_name}" + # https://example.com + sub_domain_setting { + branch_name = aws_amplify_branch.master.branch_name prefix = "" } - // https://www.example.com - sub_domain_settings { - branch_name = "${aws_amplify_branch.master.branch_name}" + # https://www.example.com + sub_domain_setting { + branch_name = aws_amplify_branch.master.branch_name prefix = "www" } } @@ -51,27 +51,26 @@ resource "aws_amplify_domain_association" "app" { The following arguments are supported: -* `app_id` - (Required) Unique Id for an Amplify App. -* `domain_name` - (Required) Domain name for the Domain Association. -* `sub_domain_settings` - (Required) Setting structure for the Subdomain. A `sub_domain_settings` block is documented below. -* `enable_auto_sub_domain` - (Optional) Enables automated creation of Subdomains for branches. (Currently not supported) +* `app_id` - (Required) The unique ID for an Amplify app. +* `domain_name` - (Required) The domain name for the domain association. +* `sub_domain_setting` - (Required) The setting for the subdomain. Documented below. * `wait_for_verification` - (Optional) If enabled, the resource will wait for the domain association status to change to PENDING_DEPLOYMENT or AVAILABLE. Setting this to false will skip the process. Default: true. -A `sub_domain_settings` block supports the following arguments: +The `sub_domain_setting` configuration block supports the following arguments: -* `branch_name` - (Required) Branch name setting for the Subdomain. -* `prefix` - (Required) Prefix setting for the Subdomain. +* `branch_name` - (Required) The branch name setting for the subdomain. +* `prefix` - (Required) The prefix setting for the subdomain. -## Attribute Reference +## Attributes Reference -The following attributes are exported: +In addition to all arguments above, the following attributes are exported: -* `arn` - ARN for the Domain Association. +* `arn` - The Amazon Resource Name (ARN) for the domain association. ## Import Amplify domain association can be imported using `app_id` and `domain_name`, e.g. ``` -$ terraform import aws_amplify_domain_association.app d2ypk4k47z8u6/domains/example.com +$ terraform import aws_amplify_domain_association.app d2ypk4k47z8u6/example.com ``` From 2a5989680089307d32d730529a68dc0eb985a125 Mon Sep 17 00:00:00 2001 From: Pocket7878 Date: Thu, 3 Jun 2021 19:15:12 +0900 Subject: [PATCH 0205/1208] feature: Add Amazon Location Service client. --- .github/labeler-issue-triage.yml | 2 ++ .github/labeler-pr-triage.yml | 4 ++++ aws/config.go | 3 +++ aws/provider.go | 1 + infrastructure/repository/labels-service.tf | 1 + website/allowed-subcategories.txt | 1 + website/docs/guides/custom-service-endpoints.html.md | 1 + 7 files changed, 13 insertions(+) diff --git a/.github/labeler-issue-triage.yml b/.github/labeler-issue-triage.yml index 03760b4ff8f1..5aa0a23b7fbd 100644 --- a/.github/labeler-issue-triage.yml +++ b/.github/labeler-issue-triage.yml @@ -224,6 +224,8 @@ service/licensemanager: - '((\*|-) ?`?|(data|resource) "?)aws_licensemanager_' service/lightsail: - '((\*|-) ?`?|(data|resource) "?)aws_lightsail_' +service/location: + - '((\*|-) ?`?|(data|resource) "?)aws_location_' service/machinelearning: - '((\*|-) ?`?|(data|resource) "?)aws_machinelearning_' service/macie: diff --git a/.github/labeler-pr-triage.yml b/.github/labeler-pr-triage.yml index a70cf67696a3..7c03fe24038b 100644 --- a/.github/labeler-pr-triage.yml +++ b/.github/labeler-pr-triage.yml @@ -516,6 +516,10 @@ service/lightsail: - 'aws/internal/service/lightsail/**/*' - '**/*_lightsail_*' - '**/lightsail_*' +service/location: + - 'aws/internal/service/location/**/*' + - '**/*_location_*' + - '**/location_*' service/machinelearning: - 'aws/internal/service/machinelearning/**/*' - '**/*_machinelearning_*' diff --git a/aws/config.go b/aws/config.go index 8eef7bed53ce..f436c240284f 100644 --- a/aws/config.go +++ b/aws/config.go @@ -104,6 +104,7 @@ import ( "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" "github.com/aws/aws-sdk-go/service/licensemanager" "github.com/aws/aws-sdk-go/service/lightsail" + "github.com/aws/aws-sdk-go/service/locationservice" "github.com/aws/aws-sdk-go/service/macie" "github.com/aws/aws-sdk-go/service/macie2" "github.com/aws/aws-sdk-go/service/managedblockchain" @@ -313,6 +314,7 @@ type AWSClient struct { lexmodelconn *lexmodelbuildingservice.LexModelBuildingService licensemanagerconn *licensemanager.LicenseManager lightsailconn *lightsail.Lightsail + locationconn *locationservice.LocationService macieconn *macie.Macie macie2conn *macie2.Macie2 managedblockchainconn *managedblockchain.ManagedBlockchain @@ -562,6 +564,7 @@ func (c *Config) Client() (interface{}, error) { lexmodelconn: lexmodelbuildingservice.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["lexmodels"])})), licensemanagerconn: licensemanager.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["licensemanager"])})), lightsailconn: lightsail.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["lightsail"])})), + locationconn: locationservice.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["location"])})), macieconn: macie.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["macie"])})), macie2conn: macie2.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["macie2"])})), managedblockchainconn: managedblockchain.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["managedblockchain"])})), diff --git a/aws/provider.go b/aws/provider.go index 74fd8c21cb99..f3af9ac1651b 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1359,6 +1359,7 @@ func init() { "lexmodels", "licensemanager", "lightsail", + "location", "macie", "macie2", "managedblockchain", diff --git a/infrastructure/repository/labels-service.tf b/infrastructure/repository/labels-service.tf index 4f27b2b8ff12..b63fdee1ee28 100644 --- a/infrastructure/repository/labels-service.tf +++ b/infrastructure/repository/labels-service.tf @@ -125,6 +125,7 @@ variable "service_labels" { "lexmodelbuildingservice", "licensemanager", "lightsail", + "location", "machinelearning", "macie", "macie2", diff --git a/website/allowed-subcategories.txt b/website/allowed-subcategories.txt index 79d5df82be0e..1a9b72329402 100644 --- a/website/allowed-subcategories.txt +++ b/website/allowed-subcategories.txt @@ -86,6 +86,7 @@ Lambda Lex License Manager Lightsail +Location Service MQ Macie Macie Classic diff --git a/website/docs/guides/custom-service-endpoints.html.md b/website/docs/guides/custom-service-endpoints.html.md index edad3b4262e1..36c491480494 100644 --- a/website/docs/guides/custom-service-endpoints.html.md +++ b/website/docs/guides/custom-service-endpoints.html.md @@ -148,6 +148,7 @@ The Terraform AWS Provider allows the following endpoints to be customized:
  • lexmodels
  • licensemanager
  • lightsail
  • +
  • location
  • macie
  • macie2
  • managedblockchain
  • From 8ba927abf3acd0c57926a5cd7daf07d29bc6dd0a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Jun 2021 12:08:00 -0400 Subject: [PATCH 0206/1208] r/aws_amplify_domain_association: Add and use internal waiter package. --- aws/internal/service/amplify/finder/finder.go | 29 ++ aws/internal/service/amplify/id.go | 19 ++ aws/internal/service/amplify/waiter/status.go | 25 ++ aws/internal/service/amplify/waiter/waiter.go | 42 +++ aws/internal/tfresource/errors.go | 12 + ...resource_aws_amplify_domain_association.go | 277 ++++++++++-------- ...rce_aws_amplify_domain_association_test.go | 51 ++-- .../amplify_domain_association.html.markdown | 16 +- 8 files changed, 315 insertions(+), 156 deletions(-) create mode 100644 aws/internal/service/amplify/waiter/status.go create mode 100644 aws/internal/service/amplify/waiter/waiter.go diff --git a/aws/internal/service/amplify/finder/finder.go b/aws/internal/service/amplify/finder/finder.go index ec468523b9f6..9440c53a1f0d 100644 --- a/aws/internal/service/amplify/finder/finder.go +++ b/aws/internal/service/amplify/finder/finder.go @@ -93,6 +93,35 @@ func BranchByAppIDAndBranchName(conn *amplify.Amplify, appID, branchName string) return output.Branch, nil } +func DomainAssociationByAppIDAndDomainName(conn *amplify.Amplify, appID, domainName string) (*amplify.DomainAssociation, error) { + input := &lify.GetDomainAssociationInput{ + AppId: aws.String(appID), + DomainName: aws.String(domainName), + } + + output, err := conn.GetDomainAssociation(input) + + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.DomainAssociation == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.DomainAssociation, nil +} + func WebhookByID(conn *amplify.Amplify, id string) (*amplify.Webhook, error) { input := &lify.GetWebhookInput{ WebhookId: aws.String(id), diff --git a/aws/internal/service/amplify/id.go b/aws/internal/service/amplify/id.go index 0306a36111d1..20bb749cbb04 100644 --- a/aws/internal/service/amplify/id.go +++ b/aws/internal/service/amplify/id.go @@ -42,3 +42,22 @@ func BranchParseResourceID(id string) (string, string, error) { return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected APPID%[2]sBRANCHNAME", id, branchResourceIDSeparator) } + +const domainAssociationResourceIDSeparator = "/" + +func DomainAssociationCreateResourceID(appID, domainName string) string { + parts := []string{appID, domainName} + id := strings.Join(parts, domainAssociationResourceIDSeparator) + + return id +} + +func DomainAssociationParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, domainAssociationResourceIDSeparator) + + if len(parts) == 2 && parts[0] != "" && parts[1] != "" { + return parts[0], parts[1], nil + } + + return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected APPID%[2]sDOMAINNAME", id, domainAssociationResourceIDSeparator) +} diff --git a/aws/internal/service/amplify/waiter/status.go b/aws/internal/service/amplify/waiter/status.go new file mode 100644 index 000000000000..49be5ec89c8f --- /dev/null +++ b/aws/internal/service/amplify/waiter/status.go @@ -0,0 +1,25 @@ +package waiter + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func DomainAssociationStatus(conn *amplify.Amplify, appID, domainName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + domainAssociation, err := finder.DomainAssociationByAppIDAndDomainName(conn, appID, domainName) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return domainAssociation, aws.StringValue(domainAssociation.DomainStatus), nil + } +} diff --git a/aws/internal/service/amplify/waiter/waiter.go b/aws/internal/service/amplify/waiter/waiter.go new file mode 100644 index 000000000000..d9b007c84503 --- /dev/null +++ b/aws/internal/service/amplify/waiter/waiter.go @@ -0,0 +1,42 @@ +package waiter + +import ( + "errors" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +const ( + DomainAssociationVerifiedTimeout = 15 * time.Minute +) + +func DomainAssociationVerified(conn *amplify.Amplify, appID, domainName string) (*amplify.DomainAssociation, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + amplify.DomainStatusPendingVerification, + amplify.DomainStatusInProgress, + amplify.DomainStatusCreating, + amplify.DomainStatusRequestingCertificate, + amplify.DomainStatusUpdating, + }, + Target: []string{amplify.DomainStatusPendingDeployment, amplify.DomainStatusAvailable}, + Refresh: DomainAssociationStatus(conn, appID, domainName), + Timeout: DomainAssociationVerifiedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*amplify.DomainAssociation); ok { + if v != nil && aws.StringValue(v.DomainStatus) == amplify.DomainStatusFailed { + tfresource.SetLastError(err, errors.New(aws.StringValue(v.StatusReason))) + } + + return v, err + } + + return nil, err +} diff --git a/aws/internal/tfresource/errors.go b/aws/internal/tfresource/errors.go index baa733d20a5b..703eb55aa7d1 100644 --- a/aws/internal/tfresource/errors.go +++ b/aws/internal/tfresource/errors.go @@ -23,3 +23,15 @@ func TimedOut(err error) bool { timeoutErr, ok := err.(*resource.TimeoutError) // nolint:errorlint return ok && timeoutErr.LastError == nil } + +// SetLastError sets the LastError field on the error if supported. +func SetLastError(err, lastErr error) { + var te *resource.TimeoutError + var use *resource.UnexpectedStateError + + if ok := errors.As(err, &te); ok && te.LastError == nil { + te.LastError = lastErr + } else if ok := errors.As(err, &use); ok && use.LastError == nil { + use.LastError = lastErr + } +} diff --git a/aws/resource_aws_amplify_domain_association.go b/aws/resource_aws_amplify_domain_association.go index 8453aed28e65..4e36c21ac402 100644 --- a/aws/resource_aws_amplify_domain_association.go +++ b/aws/resource_aws_amplify_domain_association.go @@ -1,16 +1,18 @@ package aws import ( + "context" "fmt" "log" - "strings" - "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/amplify" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + tfamplify "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsAmplifyDomainAssociation() *schema.Resource { @@ -20,7 +22,11 @@ func resourceAwsAmplifyDomainAssociation() *schema.Resource { Update: resourceAwsAmplifyDomainAssociationUpdate, Delete: resourceAwsAmplifyDomainAssociationDelete, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + d.Set("wait_for_verification", true) + + return []*schema.ResourceData{d}, nil + }, }, Schema: map[string]*schema.Schema{ @@ -35,13 +41,18 @@ func resourceAwsAmplifyDomainAssociation() *schema.Resource { Computed: true, }, + "certificate_verification_dns_record": { + Type: schema.TypeString, + Computed: true, + }, + "domain_name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "sub_domain_setting": { + "sub_domain": { Type: schema.TypeSet, Required: true, MaxItems: 255, @@ -51,22 +62,26 @@ func resourceAwsAmplifyDomainAssociation() *schema.Resource { Type: schema.TypeString, Required: true, }, + "dns_record": { + Type: schema.TypeString, + Computed: true, + }, "prefix": { Type: schema.TypeString, Required: true, }, + "verified": { + Type: schema.TypeBool, + Computed: true, + }, }, }, }, - // non-API "wait_for_verification": { Type: schema.TypeBool, Optional: true, Default: true, - DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - return true - }, }, }, } @@ -74,29 +89,29 @@ func resourceAwsAmplifyDomainAssociation() *schema.Resource { func resourceAwsAmplifyDomainAssociationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Print("[DEBUG] Creating Amplify DomainAssociation") - params := &lify.CreateDomainAssociationInput{ - AppId: aws.String(d.Get("app_id").(string)), - DomainName: aws.String(d.Get("domain_name").(string)), - } + appID := d.Get("app_id").(string) + domainName := d.Get("domain_name").(string) + id := tfamplify.DomainAssociationCreateResourceID(appID, domainName) - if v, ok := d.GetOk("sub_domain_setting"); ok { - params.SubDomainSettings = expandAmplifySubDomainSettings(v.([]interface{})) + input := &lify.CreateDomainAssociationInput{ + AppId: aws.String(appID), + DomainName: aws.String(domainName), + SubDomainSettings: expandAmplifySubDomainSettings(d.Get("sub_domain").(*schema.Set).List()), } - resp, err := conn.CreateDomainAssociation(params) + log.Printf("[DEBUG] Creating Amplify Domain Association: %s", input) + _, err := conn.CreateDomainAssociation(input) + if err != nil { - return fmt.Errorf("Error creating Amplify DomainAssociation: %s", err) + return fmt.Errorf("error creating Amplify Domain Association (%s): %w", id, err) } - arn := *resp.DomainAssociation.DomainAssociationArn - d.SetId(arn[strings.Index(arn, ":apps/")+len(":apps/"):]) + d.SetId(id) if d.Get("wait_for_verification").(bool) { - log.Printf("[DEBUG] Waiting until Amplify DomainAssociation (%s) is deployed", d.Id()) - if err := resourceAwsAmplifyDomainAssociationWaitUntilVerified(d.Id(), meta); err != nil { - return fmt.Errorf("error waiting until Amplify DomainAssociation (%s) is deployed: %s", d.Id(), err) + if _, err := waiter.DomainAssociationVerified(conn, appID, domainName); err != nil { + return fmt.Errorf("error waiting for Amplify Domain Association (%s) to verify: %w", d.Id(), err) } } @@ -105,30 +120,31 @@ func resourceAwsAmplifyDomainAssociationCreate(d *schema.ResourceData, meta inte func resourceAwsAmplifyDomainAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Reading Amplify DomainAssociation: %s", d.Id()) - s := strings.Split(d.Id(), "/") - app_id := s[0] - domain_name := s[2] + appID, domainName, err := tfamplify.DomainAssociationParseResourceID(d.Id()) - resp, err := conn.GetDomainAssociation(&lify.GetDomainAssociationInput{ - AppId: aws.String(app_id), - DomainName: aws.String(domain_name), - }) if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == amplify.ErrCodeNotFoundException { - log.Printf("[WARN] Amplify DomainAssociation (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - return err + return fmt.Errorf("error parsing Amplify Domain Association ID: %w", err) + } + + domainAssociation, err := finder.DomainAssociationByAppIDAndDomainName(conn, appID, domainName) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Amplify Domain Association (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading Amplify Domain Association (%s): %w", d.Id(), err) } - d.Set("app_id", app_id) - d.Set("arn", resp.DomainAssociation.DomainAssociationArn) - d.Set("domain_name", resp.DomainAssociation.DomainName) - if err := d.Set("sub_domain_setting", flattenAmplifySubDomainSettings(resp.DomainAssociation.SubDomains)); err != nil { - return fmt.Errorf("error setting sub_domain_setting: %s", err) + d.Set("app_id", appID) + d.Set("arn", domainAssociation.DomainAssociationArn) + d.Set("certificate_verification_dns_record", domainAssociation.CertificateVerificationDNSRecord) + d.Set("domain_name", domainAssociation.DomainName) + if err := d.Set("sub_domain", flattenAmplifySubDomains(domainAssociation.SubDomains)); err != nil { + return fmt.Errorf("error setting sub_domain: %w", err) } return nil @@ -136,30 +152,31 @@ func resourceAwsAmplifyDomainAssociationRead(d *schema.ResourceData, meta interf func resourceAwsAmplifyDomainAssociationUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Updating Amplify DomainAssociation: %s", d.Id()) - s := strings.Split(d.Id(), "/") - app_id := s[0] - domain_name := s[2] + appID, domainName, err := tfamplify.DomainAssociationParseResourceID(d.Id()) - params := &lify.UpdateDomainAssociationInput{ - AppId: aws.String(app_id), - DomainName: aws.String(domain_name), + if err != nil { + return fmt.Errorf("error parsing Amplify Domain Association ID: %w", err) } - if d.HasChange("sub_domain_setting") { - params.SubDomainSettings = expandAmplifySubDomainSettings(d.Get("sub_domain_setting").([]interface{})) - } + if d.HasChange("sub_domain") { + input := &lify.UpdateDomainAssociationInput{ + AppId: aws.String(appID), + DomainName: aws.String(domainName), + SubDomainSettings: expandAmplifySubDomainSettings(d.Get("sub_domain").(*schema.Set).List()), + } - _, err := conn.UpdateDomainAssociation(params) - if err != nil { - return fmt.Errorf("Error updating Amplify DomainAssociation: %s", err) + log.Printf("[DEBUG] Creating Amplify Domain Association: %s", input) + _, err := conn.UpdateDomainAssociation(input) + + if err != nil { + return fmt.Errorf("error updating Amplify Domain Association (%s): %w", d.Id(), err) + } } if d.Get("wait_for_verification").(bool) { - log.Printf("[DEBUG] Waiting until Amplify DomainAssociation (%s) is deployed", d.Id()) - if err := resourceAwsAmplifyDomainAssociationWaitUntilVerified(d.Id(), meta); err != nil { - return fmt.Errorf("error waiting until Amplify DomainAssociation (%s) is deployed: %s", d.Id(), err) + if _, err := waiter.DomainAssociationVerified(conn, appID, domainName); err != nil { + return fmt.Errorf("error waiting for Amplify Domain Association (%s) to verify: %w", d.Id(), err) } } @@ -168,112 +185,118 @@ func resourceAwsAmplifyDomainAssociationUpdate(d *schema.ResourceData, meta inte func resourceAwsAmplifyDomainAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).amplifyconn - log.Printf("[DEBUG] Deleting Amplify DomainAssociation: %s", d.Id()) - s := strings.Split(d.Id(), "/") - app_id := s[0] - domain_name := s[2] + appID, domainName, err := tfamplify.DomainAssociationParseResourceID(d.Id()) - params := &lify.DeleteDomainAssociationInput{ - AppId: aws.String(app_id), - DomainName: aws.String(domain_name), + if err != nil { + return fmt.Errorf("error parsing Amplify Domain Association ID: %w", err) + } + + log.Printf("[DEBUG] Deleting Amplify Domain Association: %s", d.Id()) + _, err = conn.DeleteDomainAssociation(&lify.DeleteDomainAssociationInput{ + AppId: aws.String(appID), + DomainName: aws.String(domainName), + }) + + if tfawserr.ErrCodeEquals(err, amplify.ErrCodeNotFoundException) { + return nil } - _, err := conn.DeleteDomainAssociation(params) if err != nil { - return fmt.Errorf("Error deleting Amplify DomainAssociation: %s", err) + return fmt.Errorf("error deleting Amplify Domain Association (%s): %w", d.Id(), err) } return nil } -func resourceAwsAmplifyDomainAssociationWaitUntilVerified(id string, meta interface{}) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{ - amplify.DomainStatusPendingVerification, - amplify.DomainStatusInProgress, - amplify.DomainStatusCreating, - amplify.DomainStatusRequestingCertificate, - amplify.DomainStatusUpdating, - }, - Target: []string{ - // It takes up to 30 minutes, so skip waiting for deployment. - amplify.DomainStatusPendingDeployment, - amplify.DomainStatusAvailable, - }, - Refresh: resourceAwsAmplifyDomainAssociationStateRefreshFunc(id, meta), - Timeout: 15 * time.Minute, - MinTimeout: 15 * time.Second, - Delay: 10 * time.Second, +func expandAmplifySubDomainSetting(tfMap map[string]interface{}) *amplify.SubDomainSetting { + if tfMap == nil { + return nil + } + + apiObject := &lify.SubDomainSetting{} + + if v, ok := tfMap["branch_name"].(string); ok && v != "" { + apiObject.BranchName = aws.String(v) + } + + if v, ok := tfMap["prefix"].(string); ok && v != "" { + apiObject.Prefix = aws.String(v) } - _, err := stateConf.WaitForState() - return err + return apiObject } -func resourceAwsAmplifyDomainAssociationStateRefreshFunc(id string, meta interface{}) resource.StateRefreshFunc { - s := strings.Split(id, "/") - app_id := s[0] - domain_name := s[2] +func expandAmplifySubDomainSettings(tfList []interface{}) []*amplify.SubDomainSetting { + if len(tfList) == 0 { + return nil + } - return func() (interface{}, string, error) { - conn := meta.(*AWSClient).amplifyconn + var apiObjects []*amplify.SubDomainSetting - resp, err := conn.GetDomainAssociation(&lify.GetDomainAssociationInput{ - AppId: aws.String(app_id), - DomainName: aws.String(domain_name), - }) - if err != nil { - log.Printf("[WARN] Error retrieving Amplify DomainAssociation %q details: %s", id, err) - return nil, "", err + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + + if !ok { + continue } - if *resp.DomainAssociation.DomainStatus == amplify.DomainStatusFailed { - return nil, "", fmt.Errorf("%s", *resp.DomainAssociation.StatusReason) + apiObject := expandAmplifySubDomainSetting(tfMap) + + if apiObject == nil { + continue } - return resp.DomainAssociation, *resp.DomainAssociation.DomainStatus, nil + apiObjects = append(apiObjects, apiObject) } + + return apiObjects } -func expandAmplifySubDomainSettings(values []interface{}) []*amplify.SubDomainSetting { - settings := make([]*amplify.SubDomainSetting, 0) +func flattenAmplifySubDomain(apiObject *amplify.SubDomain) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} - for _, v := range values { - e := v.(map[string]interface{}) + if v := apiObject.DnsRecord; v != nil { + tfMap["dns_record"] = aws.StringValue(v) + } - setting := &lify.SubDomainSetting{} + if v := apiObject.SubDomainSetting; v != nil { + apiObject := v - if ev, ok := e["branch_name"].(string); ok && ev != "" { - setting.BranchName = aws.String(ev) + if v := apiObject.BranchName; v != nil { + tfMap["branch_name"] = aws.StringValue(v) } - if ev, ok := e["prefix"].(string); ok { - setting.Prefix = aws.String(ev) + if v := apiObject.Prefix; v != nil { + tfMap["prefix"] = aws.StringValue(v) } + } - settings = append(settings, setting) + if v := apiObject.Verified; v != nil { + tfMap["verified"] = aws.BoolValue(v) } - return settings + return tfMap } -func flattenAmplifySubDomainSettings(sub_domains []*amplify.SubDomain) []map[string]interface{} { - values := make([]map[string]interface{}, 0) - - for _, v := range sub_domains { - kv := make(map[string]interface{}) +func flattenAmplifySubDomains(apiObjects []*amplify.SubDomain) []interface{} { + if len(apiObjects) == 0 { + return nil + } - if v.SubDomainSetting.BranchName != nil { - kv["branch_name"] = *v.SubDomainSetting.BranchName - } + var tfList []interface{} - if v.SubDomainSetting.Prefix != nil { - kv["prefix"] = *v.SubDomainSetting.Prefix + for _, apiObject := range apiObjects { + if apiObject == nil { + continue } - values = append(values, kv) + tfList = append(tfList, flattenAmplifySubDomain(apiObject)) } - return values + return tfList } diff --git a/aws/resource_aws_amplify_domain_association_test.go b/aws/resource_aws_amplify_domain_association_test.go index b1d1f6b43dff..44d9af61d569 100644 --- a/aws/resource_aws_amplify_domain_association_test.go +++ b/aws/resource_aws_amplify_domain_association_test.go @@ -3,14 +3,15 @@ package aws import ( "fmt" "regexp" - "strings" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/amplify" "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" + tfamplify "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestAccAWSAmplifyDomainAssociation_basic(t *testing.T) { @@ -21,7 +22,8 @@ func TestAccAWSAmplifyDomainAssociation_basic(t *testing.T) { domainName := "example.com" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSAmplifyDomainAssociationDestroy, Steps: []resource.TestStep{ @@ -53,54 +55,55 @@ func testAccCheckAWSAmplifyDomainAssociationExists(resourceName string, v *ampli return fmt.Errorf("Not found: %s", resourceName) } - conn := testAccProvider.Meta().(*AWSClient).amplifyconn + if rs.Primary.ID == "" { + return fmt.Errorf("No Amplify Domain Association ID is set") + } - id := strings.Split(rs.Primary.ID, "/") - app_id := id[0] - domain_name := id[2] + appID, domainName, err := tfamplify.DomainAssociationParseResourceID(rs.Primary.ID) - output, err := conn.GetDomainAssociation(&lify.GetDomainAssociationInput{ - AppId: aws.String(app_id), - DomainName: aws.String(domain_name), - }) if err != nil { return err } - if output == nil || output.DomainAssociation == nil { - return fmt.Errorf("Amplify DomainAssociation (%s) not found", rs.Primary.ID) + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + + domainAssociation, err := finder.DomainAssociationByAppIDAndDomainName(conn, appID, domainName) + + if err != nil { + return err } - *v = *output.DomainAssociation + *v = *domainAssociation return nil } } func testAccCheckAWSAmplifyDomainAssociationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).amplifyconn + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_amplify_domain_association" { continue } - conn := testAccProvider.Meta().(*AWSClient).amplifyconn + appID, domainName, err := tfamplify.DomainAssociationParseResourceID(rs.Primary.ID) - s := strings.Split(rs.Primary.ID, "/") - app_id := s[0] - domain_name := s[2] + if err != nil { + return err + } - _, err := conn.GetDomainAssociation(&lify.GetDomainAssociationInput{ - AppId: aws.String(app_id), - DomainName: aws.String(domain_name), - }) + _, err = finder.DomainAssociationByAppIDAndDomainName(conn, appID, domainName) - if isAWSErr(err, amplify.ErrCodeNotFoundException, "") { + if tfresource.NotFound(err) { continue } if err != nil { return err } + + return fmt.Errorf("Amplify Domain Association %s still exists", rs.Primary.ID) } return nil @@ -121,7 +124,7 @@ resource "aws_amplify_domain_association" "test" { app_id = aws_amplify_app.test.id domain_name = "%s" - sub_domain_setting { + sub_domain { branch_name = aws_amplify_branch.test.branch_name prefix = "" } diff --git a/website/docs/r/amplify_domain_association.html.markdown b/website/docs/r/amplify_domain_association.html.markdown index 9134f6112b8e..51c5d3cd8fb0 100644 --- a/website/docs/r/amplify_domain_association.html.markdown +++ b/website/docs/r/amplify_domain_association.html.markdown @@ -34,13 +34,13 @@ resource "aws_amplify_domain_association" "example" { domain_name = "example.com" # https://example.com - sub_domain_setting { + sub_domain { branch_name = aws_amplify_branch.master.branch_name prefix = "" } # https://www.example.com - sub_domain_setting { + sub_domain { branch_name = aws_amplify_branch.master.branch_name prefix = "www" } @@ -53,10 +53,10 @@ The following arguments are supported: * `app_id` - (Required) The unique ID for an Amplify app. * `domain_name` - (Required) The domain name for the domain association. -* `sub_domain_setting` - (Required) The setting for the subdomain. Documented below. -* `wait_for_verification` - (Optional) If enabled, the resource will wait for the domain association status to change to PENDING_DEPLOYMENT or AVAILABLE. Setting this to false will skip the process. Default: true. +* `sub_domain` - (Required) The setting for the subdomain. Documented below. +* `wait_for_verification` - (Optional) If enabled, the resource will wait for the domain association status to change to `PENDING_DEPLOYMENT` or `AVAILABLE`. Setting this to `false` will skip the process. Default: `true`. -The `sub_domain_setting` configuration block supports the following arguments: +The `sub_domain` configuration block supports the following arguments: * `branch_name` - (Required) The branch name setting for the subdomain. * `prefix` - (Required) The prefix setting for the subdomain. @@ -66,6 +66,12 @@ The `sub_domain_setting` configuration block supports the following arguments: In addition to all arguments above, the following attributes are exported: * `arn` - The Amazon Resource Name (ARN) for the domain association. +* `certificate_verification_dns_record` - The DNS record for certificate verification. + +The `sub_domain` configuration block exports the following attributes: + +* `dns_record` - The DNS record for the subdomain. +* `verified` - The verified status of the subdomain. ## Import From b453af02a42eaf86561f64ae3fbbfe0e9ab784a2 Mon Sep 17 00:00:00 2001 From: Deepak Kumar <21131061+kumadee@users.noreply.github.com> Date: Thu, 3 Jun 2021 18:13:25 +0200 Subject: [PATCH 0207/1208] Add data globalaccelerator accelerator * d/aws_globalaccelerator_accelerator: Add new datasource and add documentation --- ...ource_aws_globalaccelerator_accelerator.go | 153 ++++++++++++++++++ ..._aws_globalaccelerator_accelerator_test.go | 79 +++++++++ aws/provider.go | 1 + .../d/globalaccelerator_accelerator.markdown | 44 +++++ 4 files changed, 277 insertions(+) create mode 100644 aws/data_source_aws_globalaccelerator_accelerator.go create mode 100644 aws/data_source_aws_globalaccelerator_accelerator_test.go create mode 100644 website/docs/d/globalaccelerator_accelerator.markdown diff --git a/aws/data_source_aws_globalaccelerator_accelerator.go b/aws/data_source_aws_globalaccelerator_accelerator.go new file mode 100644 index 000000000000..3353d9e1adab --- /dev/null +++ b/aws/data_source_aws_globalaccelerator_accelerator.go @@ -0,0 +1,153 @@ +package aws + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/globalaccelerator" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/globalaccelerator/finder" +) + +func dataSourceAwsGlobalAcceleratorAccelerator() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsGlobalAcceleratorAcceleratorRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "ip_address_type": { + Type: schema.TypeString, + Computed: true, + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "dns_name": { + Type: schema.TypeString, + Computed: true, + }, + "hosted_zone_id": { + Type: schema.TypeString, + Computed: true, + }, + "ip_sets": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip_addresses": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "ip_family": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "attributes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "flow_logs_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "flow_logs_s3_bucket": { + Type: schema.TypeString, + Computed: true, + }, + "flow_logs_s3_prefix": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "tags": tagsSchemaComputed(), + }, + } +} + +func dataSourceAwsGlobalAcceleratorAcceleratorRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).globalacceleratorconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + var results []*globalaccelerator.Accelerator + + err := conn.ListAcceleratorsPages(&globalaccelerator.ListAcceleratorsInput{}, func(page *globalaccelerator.ListAcceleratorsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, l := range page.Accelerators { + if l == nil { + continue + } + + if v, ok := d.GetOk("arn"); ok && v.(string) != aws.StringValue(l.AcceleratorArn) { + continue + } + + if v, ok := d.GetOk("name"); ok && v.(string) != aws.StringValue(l.Name) { + continue + } + + results = append(results, l) + } + + return !lastPage + }) + + if err != nil { + return fmt.Errorf("error reading AWS Global Accelerator: %w", err) + } + + if len(results) != 1 { + return fmt.Errorf("Search returned %d results, please revise so only one is returned", len(results)) + } + + accelerator := results[0] + d.SetId(aws.StringValue(accelerator.AcceleratorArn)) + d.Set("arn", accelerator.AcceleratorArn) + d.Set("enabled", accelerator.Enabled) + d.Set("dns_name", accelerator.DnsName) + d.Set("hosted_zone_id", globalAcceleratorRoute53ZoneID) + d.Set("name", accelerator.Name) + d.Set("ip_address_type", accelerator.IpAddressType) + d.Set("ip_sets", flattenGlobalAcceleratorIpSets(accelerator.IpSets)) + + acceleratorAttributes, err := finder.AcceleratorAttributesByARN(conn, d.Id()) + if err != nil { + return fmt.Errorf("error reading Global Accelerator Accelerator (%s) attributes: %w", d.Id(), err) + } + + if err := d.Set("attributes", []interface{}{flattenGlobalAcceleratorAcceleratorAttributes(acceleratorAttributes)}); err != nil { + return fmt.Errorf("error setting attributes: %w", err) + } + + tags, err := keyvaluetags.GlobalacceleratorListTags(conn, d.Id()) + if err != nil { + return fmt.Errorf("error listing tags for Global Accelerator Accelerator (%s): %w", d.Id(), err) + } + + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + return nil +} diff --git a/aws/data_source_aws_globalaccelerator_accelerator_test.go b/aws/data_source_aws_globalaccelerator_accelerator_test.go new file mode 100644 index 000000000000..bdc947d4fcaa --- /dev/null +++ b/aws/data_source_aws_globalaccelerator_accelerator_test.go @@ -0,0 +1,79 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/globalaccelerator" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSDataGlobalAcceleratorAccelerator_basic(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_globalaccelerator_accelerator.test" + dataSourceName := "data.aws_globalaccelerator_accelerator.test_by_arn" + dataSourceName2 := "data.aws_globalaccelerator_accelerator.test_by_name" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, globalaccelerator.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSGlobalAcceleratorAcceleratorConfigWithDataSource(rName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "attributes.#", resourceName, "attributes.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "attributes.0.flow_logs_enabled", resourceName, "attributes.0.flow_logs_enabled"), + resource.TestCheckResourceAttrPair(dataSourceName, "attributes.0.flow_logs_s3_bucket", resourceName, "attributes.0.flow_logs_s3_bucket"), + resource.TestCheckResourceAttrPair(dataSourceName, "attributes.0.flow_logs_s3_prefix", resourceName, "attributes.0.flow_logs_s3_prefix"), + resource.TestCheckResourceAttrPair(dataSourceName, "dns_name", resourceName, "dns_name"), + resource.TestCheckResourceAttrPair(dataSourceName, "enabled", resourceName, "enabled"), + resource.TestCheckResourceAttrPair(dataSourceName, "hosted_zone_id", resourceName, "hosted_zone_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "ip_address_type", resourceName, "ip_address_type"), + resource.TestCheckResourceAttrPair(dataSourceName, "ip_sets.#", resourceName, "ip_sets.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "ip_sets.0.ip_addresses.#", resourceName, "ip_sets.0.ip_addresses.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "ip_sets.0.ip_addresses.0", resourceName, "ip_sets.0.ip_addresses.0"), + resource.TestCheckResourceAttrPair(dataSourceName, "ip_sets.0.ip_addresses.1", resourceName, "ip_sets.0.ip_addresses.1"), + resource.TestCheckResourceAttrPair(dataSourceName, "ip_sets.0.ip_family", resourceName, "ip_sets.0.ip_family"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName2, "attributes.#", resourceName, "attributes.#"), + resource.TestCheckResourceAttrPair(dataSourceName2, "attributes.0.flow_logs_enabled", resourceName, "attributes.0.flow_logs_enabled"), + resource.TestCheckResourceAttrPair(dataSourceName2, "attributes.0.flow_logs_s3_bucket", resourceName, "attributes.0.flow_logs_s3_bucket"), + resource.TestCheckResourceAttrPair(dataSourceName2, "attributes.0.flow_logs_s3_prefix", resourceName, "attributes.0.flow_logs_s3_prefix"), + resource.TestCheckResourceAttrPair(dataSourceName2, "dns_name", resourceName, "dns_name"), + resource.TestCheckResourceAttrPair(dataSourceName2, "enabled", resourceName, "enabled"), + resource.TestCheckResourceAttrPair(dataSourceName2, "hosted_zone_id", resourceName, "hosted_zone_id"), + resource.TestCheckResourceAttrPair(dataSourceName2, "ip_address_type", resourceName, "ip_address_type"), + resource.TestCheckResourceAttrPair(dataSourceName2, "ip_sets.#", resourceName, "ip_sets.#"), + resource.TestCheckResourceAttrPair(dataSourceName2, "ip_sets.0.ip_addresses.#", resourceName, "ip_sets.0.ip_addresses.#"), + resource.TestCheckResourceAttrPair(dataSourceName2, "ip_sets.0.ip_addresses.0", resourceName, "ip_sets.0.ip_addresses.0"), + resource.TestCheckResourceAttrPair(dataSourceName2, "ip_sets.0.ip_addresses.1", resourceName, "ip_sets.0.ip_addresses.1"), + resource.TestCheckResourceAttrPair(dataSourceName2, "ip_sets.0.ip_family", resourceName, "ip_sets.0.ip_family"), + resource.TestCheckResourceAttrPair(dataSourceName2, "name", resourceName, "name"), + ), + }, + }, + }) +} + +func testAccAWSGlobalAcceleratorAcceleratorConfigWithDataSource(rName string) string { + return fmt.Sprintf(` +resource "aws_globalaccelerator_accelerator" "test" { + name = %[1]q + attributes { + flow_logs_enabled = false + flow_logs_s3_bucket = "" + flow_logs_s3_prefix = "flow-logs/globalaccelerator/" + } +} + +data "aws_globalaccelerator_accelerator" "test_by_arn" { + arn = aws_globalaccelerator_accelerator.test.id +} + +data "aws_globalaccelerator_accelerator" "test_by_name" { + name = aws_globalaccelerator_accelerator.test.name +} +`, rName) +} diff --git a/aws/provider.go b/aws/provider.go index 8cdb9f540662..855eeb158936 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -290,6 +290,7 @@ func Provider() *schema.Provider { "aws_elasticache_replication_group": dataSourceAwsElasticacheReplicationGroup(), "aws_elb_hosted_zone_id": dataSourceAwsElbHostedZoneId(), "aws_elb_service_account": dataSourceAwsElbServiceAccount(), + "aws_globalaccelerator_accelerator": dataSourceAwsGlobalAcceleratorAccelerator(), "aws_glue_connection": dataSourceAwsGlueConnection(), "aws_glue_data_catalog_encryption_settings": dataSourceAwsGlueDataCatalogEncryptionSettings(), "aws_glue_script": dataSourceAwsGlueScript(), diff --git a/website/docs/d/globalaccelerator_accelerator.markdown b/website/docs/d/globalaccelerator_accelerator.markdown new file mode 100644 index 000000000000..42f670388144 --- /dev/null +++ b/website/docs/d/globalaccelerator_accelerator.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "Global Accelerator" +layout: "aws" +page_title: "AWS: aws_globalaccelerator_accelerator" +description: |- + Provides a Global Accelerator accelerator data source. +--- + +# Data Source: aws_globalaccelerator_accelerator + +Provides information about a Global Accelerator accelerator. + +## Example Usage + +```terraform +variable "accelerator_arn" { + type = string + default = "" +} + +variable "accelerator_name" { + type = string + default = "" +} + +data "aws_globalaccelerator_accelerator" "example" { + arn = var.accelerator_arn + name = var.accelerator_name +} +``` + +## Argument Reference + +The following arguments are supported: + +* `arn` - (Optional) The full ARN of the Global Accelerator. +* `name` - (Optional) The unique name of the Global Accelerator. + +~> **NOTE**: When both `arn` and `name` are specified, `arn` takes precedence. + +## Attributes Reference + +See the [Globalaccelerator Accelerator Resource](/docs/providers/aws/r/globalaccelerator_accelerator.html) for details on the +returned attributes - they are identical. From b7e381ab8f51cbde9daad67a806dd16f15e341d5 Mon Sep 17 00:00:00 2001 From: kumadee Date: Thu, 3 Jun 2021 16:46:17 +0000 Subject: [PATCH 0208/1208] added changelog pr file --- .changelog/19647.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19647.txt diff --git a/.changelog/19647.txt b/.changelog/19647.txt new file mode 100644 index 000000000000..e063263e54a5 --- /dev/null +++ b/.changelog/19647.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_globalaccelerator_accelerator +``` \ No newline at end of file From c1af8f866337ab39122b84a71317db98e3b23fda Mon Sep 17 00:00:00 2001 From: kumadee Date: Thu, 3 Jun 2021 16:49:23 +0000 Subject: [PATCH 0209/1208] fixed formatting --- website/docs/d/globalaccelerator_accelerator.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/d/globalaccelerator_accelerator.markdown b/website/docs/d/globalaccelerator_accelerator.markdown index 42f670388144..9e94f02e78cd 100644 --- a/website/docs/d/globalaccelerator_accelerator.markdown +++ b/website/docs/d/globalaccelerator_accelerator.markdown @@ -24,8 +24,8 @@ variable "accelerator_name" { } data "aws_globalaccelerator_accelerator" "example" { - arn = var.accelerator_arn - name = var.accelerator_name + arn = var.accelerator_arn + name = var.accelerator_name } ``` From 3d9d57b5448bb20efafe1099f015666041707fdb Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Jun 2021 13:57:16 -0400 Subject: [PATCH 0210/1208] r/aws_amplify_domain_association: First test running. --- ...resource_aws_amplify_domain_association.go | 22 ++++++----- ...rce_aws_amplify_domain_association_test.go | 38 +++++++++---------- aws/resource_aws_amplify_test.go | 3 ++ 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/aws/resource_aws_amplify_domain_association.go b/aws/resource_aws_amplify_domain_association.go index 4e36c21ac402..64e4334e3409 100644 --- a/aws/resource_aws_amplify_domain_association.go +++ b/aws/resource_aws_amplify_domain_association.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/service/amplify" "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" tfamplify "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/amplify/waiter" @@ -47,28 +48,30 @@ func resourceAwsAmplifyDomainAssociation() *schema.Resource { }, "domain_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, "sub_domain": { Type: schema.TypeSet, Required: true, - MaxItems: 255, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "branch_name": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, "dns_record": { Type: schema.TypeString, Computed: true, }, "prefix": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(0, 255), }, "verified": { Type: schema.TypeBool, @@ -220,7 +223,8 @@ func expandAmplifySubDomainSetting(tfMap map[string]interface{}) *amplify.SubDom apiObject.BranchName = aws.String(v) } - if v, ok := tfMap["prefix"].(string); ok && v != "" { + // Empty prefix is allowed. + if v, ok := tfMap["prefix"].(string); ok { apiObject.Prefix = aws.String(v) } diff --git a/aws/resource_aws_amplify_domain_association_test.go b/aws/resource_aws_amplify_domain_association_test.go index 44d9af61d569..c93738604835 100644 --- a/aws/resource_aws_amplify_domain_association_test.go +++ b/aws/resource_aws_amplify_domain_association_test.go @@ -14,13 +14,11 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -func TestAccAWSAmplifyDomainAssociation_basic(t *testing.T) { +func testAccAWSAmplifyDomainAssociation_basic(t *testing.T) { var domain amplify.DomainAssociation rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_domain_association.test" - domainName := "example.com" - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), @@ -28,21 +26,23 @@ func TestAccAWSAmplifyDomainAssociation_basic(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyDomainAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyDomainAssociationConfig_Required(rName, domainName), + Config: testAccAWSAmplifyDomainAssociationConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), - resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile("^arn:[^:]+:amplify:[^:]+:[^:]+:apps/[^/]+/domains/[^/]+$")), - resource.TestCheckResourceAttr(resourceName, "domain_name", domainName), - resource.TestCheckResourceAttr(resourceName, "sub_domain_setting.#", "1"), - resource.TestCheckResourceAttr(resourceName, "sub_domain_setting.0.branch_name", "master"), - resource.TestCheckResourceAttr(resourceName, "sub_domain_setting.0.prefix", ""), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+/domains/.+`)), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), + resource.TestCheckResourceAttr(resourceName, "sub_domain.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "sub_domain.*", map[string]string{ + "branch_name": rName, + "prefix": "www", + }), + resource.TestCheckResourceAttr(resourceName, "wait_for_verification", "false"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"wait_for_verification"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -109,27 +109,27 @@ func testAccCheckAWSAmplifyDomainAssociationDestroy(s *terraform.State) error { return nil } -func testAccAWSAmplifyDomainAssociationConfig_Required(rName string, domainName string) string { +func testAccAWSAmplifyDomainAssociationConfig(rName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { - name = "%s" + name = %[1]q } resource "aws_amplify_branch" "test" { app_id = aws_amplify_app.test.id - branch_name = "master" + branch_name = %[1]q } resource "aws_amplify_domain_association" "test" { app_id = aws_amplify_app.test.id - domain_name = "%s" + domain_name = "example.com" sub_domain { branch_name = aws_amplify_branch.test.branch_name - prefix = "" + prefix = "www" } wait_for_verification = false } -`, rName, domainName) +`, rName) } diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index c238c783c873..a4a397bca94b 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -35,6 +35,9 @@ func TestAccAWSAmplify_serial(t *testing.T) { "EnvironmentVariables": testAccAWSAmplifyBranch_EnvironmentVariables, "OptionalArguments": testAccAWSAmplifyBranch_OptionalArguments, }, + "DomainAssociation": { + "basic": testAccAWSAmplifyDomainAssociation_basic, + }, "Webhook": { "basic": testAccAWSAmplifyWebhook_basic, "disappears": testAccAWSAmplifyWebhook_disappears, From 1f0ad57e5dba22686d0fe5bf64aa61aaea3d1320 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Jun 2021 13:58:45 -0400 Subject: [PATCH 0211/1208] Add CHANGELOG entry. --- .changelog/11938.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/11938.txt diff --git a/.changelog/11938.txt b/.changelog/11938.txt new file mode 100644 index 000000000000..297305946891 --- /dev/null +++ b/.changelog/11938.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_amplify_domain_association +``` \ No newline at end of file From 7f6adbf84e0623bcd24500df2043d0c6853d35b1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Jun 2021 14:51:56 -0400 Subject: [PATCH 0212/1208] r/aws_amplify_domain_association: Correct waiters. --- aws/internal/service/amplify/waiter/waiter.go | 30 +++- ...resource_aws_amplify_domain_association.go | 11 +- ...rce_aws_amplify_domain_association_test.go | 151 ++++++++++++++++-- aws/resource_aws_amplify_test.go | 4 +- docs/MAINTAINING.md | 1 + 5 files changed, 173 insertions(+), 24 deletions(-) diff --git a/aws/internal/service/amplify/waiter/waiter.go b/aws/internal/service/amplify/waiter/waiter.go index d9b007c84503..08abc2675acb 100644 --- a/aws/internal/service/amplify/waiter/waiter.go +++ b/aws/internal/service/amplify/waiter/waiter.go @@ -11,18 +11,34 @@ import ( ) const ( + DomainAssociationCreatedTimeout = 5 * time.Minute DomainAssociationVerifiedTimeout = 15 * time.Minute ) +func DomainAssociationCreated(conn *amplify.Amplify, appID, domainName string) (*amplify.DomainAssociation, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{amplify.DomainStatusCreating, amplify.DomainStatusInProgress, amplify.DomainStatusRequestingCertificate}, + Target: []string{amplify.DomainStatusPendingVerification, amplify.DomainStatusPendingDeployment, amplify.DomainStatusAvailable}, + Refresh: DomainAssociationStatus(conn, appID, domainName), + Timeout: DomainAssociationCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*amplify.DomainAssociation); ok { + if v != nil && aws.StringValue(v.DomainStatus) == amplify.DomainStatusFailed { + tfresource.SetLastError(err, errors.New(aws.StringValue(v.StatusReason))) + } + + return v, err + } + + return nil, err +} + func DomainAssociationVerified(conn *amplify.Amplify, appID, domainName string) (*amplify.DomainAssociation, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{ - amplify.DomainStatusPendingVerification, - amplify.DomainStatusInProgress, - amplify.DomainStatusCreating, - amplify.DomainStatusRequestingCertificate, - amplify.DomainStatusUpdating, - }, + Pending: []string{amplify.DomainStatusUpdating, amplify.DomainStatusInProgress, amplify.DomainStatusPendingVerification}, Target: []string{amplify.DomainStatusPendingDeployment, amplify.DomainStatusAvailable}, Refresh: DomainAssociationStatus(conn, appID, domainName), Timeout: DomainAssociationVerifiedTimeout, diff --git a/aws/resource_aws_amplify_domain_association.go b/aws/resource_aws_amplify_domain_association.go index 64e4334e3409..f1d7f2a86c65 100644 --- a/aws/resource_aws_amplify_domain_association.go +++ b/aws/resource_aws_amplify_domain_association.go @@ -1,7 +1,6 @@ package aws import ( - "context" "fmt" "log" @@ -23,11 +22,7 @@ func resourceAwsAmplifyDomainAssociation() *schema.Resource { Update: resourceAwsAmplifyDomainAssociationUpdate, Delete: resourceAwsAmplifyDomainAssociationDelete, Importer: &schema.ResourceImporter{ - StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - d.Set("wait_for_verification", true) - - return []*schema.ResourceData{d}, nil - }, + State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ @@ -112,6 +107,10 @@ func resourceAwsAmplifyDomainAssociationCreate(d *schema.ResourceData, meta inte d.SetId(id) + if _, err := waiter.DomainAssociationCreated(conn, appID, domainName); err != nil { + return fmt.Errorf("error waiting for Amplify Domain Association (%s) to create: %w", d.Id(), err) + } + if d.Get("wait_for_verification").(bool) { if _, err := waiter.DomainAssociationVerified(conn, appID, domainName); err != nil { return fmt.Errorf("error waiting for Amplify Domain Association (%s) to verify: %w", d.Id(), err) diff --git a/aws/resource_aws_amplify_domain_association_test.go b/aws/resource_aws_amplify_domain_association_test.go index c93738604835..701e197546b9 100644 --- a/aws/resource_aws_amplify_domain_association_test.go +++ b/aws/resource_aws_amplify_domain_association_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "os" "regexp" "testing" @@ -15,6 +16,12 @@ import ( ) func testAccAWSAmplifyDomainAssociation_basic(t *testing.T) { + key := "AMPLIFY_DOMAIN_NAME" + domainName := os.Getenv(key) + if domainName == "" { + t.Skipf("Environment variable %s is not set", key) + } + var domain amplify.DomainAssociation rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_amplify_domain_association.test" @@ -26,23 +33,112 @@ func testAccAWSAmplifyDomainAssociation_basic(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyDomainAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyDomainAssociationConfig(rName), + Config: testAccAWSAmplifyDomainAssociationConfig(rName, domainName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+/domains/.+`)), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), + resource.TestCheckResourceAttr(resourceName, "domain_name", domainName), resource.TestCheckResourceAttr(resourceName, "sub_domain.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "sub_domain.*", map[string]string{ "branch_name": rName, - "prefix": "www", + "prefix": "", + }), + resource.TestCheckResourceAttr(resourceName, "wait_for_verification", "false"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"wait_for_verification"}, + }, + }, + }) +} + +func testAccAWSAmplifyDomainAssociation_disappears(t *testing.T) { + key := "AMPLIFY_DOMAIN_NAME" + domainName := os.Getenv(key) + if domainName == "" { + t.Skipf("Environment variable %s is not set", key) + } + + var domain amplify.DomainAssociation + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_domain_association.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyDomainAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyDomainAssociationConfig(rName, domainName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAmplifyDomainAssociation(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccAWSAmplifyDomainAssociation_update(t *testing.T) { + key := "AMPLIFY_DOMAIN_NAME" + domainName := os.Getenv(key) + if domainName == "" { + t.Skipf("Environment variable %s is not set", key) + } + + var domain amplify.DomainAssociation + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_amplify_domain_association.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSAmplify(t) }, + ErrorCheck: testAccErrorCheck(t, amplify.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAmplifyDomainAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAmplifyDomainAssociationConfig(rName, domainName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+/domains/.+`)), + resource.TestCheckResourceAttr(resourceName, "domain_name", domainName), + resource.TestCheckResourceAttr(resourceName, "sub_domain.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "sub_domain.*", map[string]string{ + "branch_name": rName, + "prefix": "", }), resource.TestCheckResourceAttr(resourceName, "wait_for_verification", "false"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"wait_for_verification"}, + }, + { + Config: testAccAWSAmplifyDomainAssociationConfigUpdated(rName, domainName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+/domains/.+`)), + resource.TestCheckResourceAttr(resourceName, "domain_name", domainName), + resource.TestCheckResourceAttr(resourceName, "sub_domain.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "sub_domain.*", map[string]string{ + "branch_name": rName, + "prefix": "", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "sub_domain.*", map[string]string{ + "branch_name": fmt.Sprintf("%s-2", rName), + "prefix": "www", + }), + resource.TestCheckResourceAttr(resourceName, "wait_for_verification", "true"), + ), }, }, }) @@ -109,7 +205,7 @@ func testAccCheckAWSAmplifyDomainAssociationDestroy(s *terraform.State) error { return nil } -func testAccAWSAmplifyDomainAssociationConfig(rName string) string { +func testAccAWSAmplifyDomainAssociationConfig(rName, domainName string) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { name = %[1]q @@ -122,14 +218,49 @@ resource "aws_amplify_branch" "test" { resource "aws_amplify_domain_association" "test" { app_id = aws_amplify_app.test.id - domain_name = "example.com" + domain_name = %[2]q sub_domain { branch_name = aws_amplify_branch.test.branch_name - prefix = "www" + prefix = "" } wait_for_verification = false } -`, rName) +`, rName, domainName) +} + +func testAccAWSAmplifyDomainAssociationConfigUpdated(rName, domainName string) string { + return fmt.Sprintf(` +resource "aws_amplify_app" "test" { + name = %[1]q +} + +resource "aws_amplify_branch" "test" { + app_id = aws_amplify_app.test.id + branch_name = %[1]q +} + +resource "aws_amplify_branch" "test2" { + app_id = aws_amplify_app.test.id + branch_name = "%[1]s-2" + } + +resource "aws_amplify_domain_association" "test" { + app_id = aws_amplify_app.test.id + domain_name = %[2]q + + sub_domain { + branch_name = aws_amplify_branch.test.branch_name + prefix = "" + } + + sub_domain { + branch_name = aws_amplify_branch.test2.branch_name + prefix = "www" + } + + wait_for_verification = true +} +`, rName, domainName) } diff --git a/aws/resource_aws_amplify_test.go b/aws/resource_aws_amplify_test.go index a4a397bca94b..d4b48560d042 100644 --- a/aws/resource_aws_amplify_test.go +++ b/aws/resource_aws_amplify_test.go @@ -36,7 +36,9 @@ func TestAccAWSAmplify_serial(t *testing.T) { "OptionalArguments": testAccAWSAmplifyBranch_OptionalArguments, }, "DomainAssociation": { - "basic": testAccAWSAmplifyDomainAssociation_basic, + "basic": testAccAWSAmplifyDomainAssociation_basic, + "disappears": testAccAWSAmplifyDomainAssociation_disappears, + "update": testAccAWSAmplifyDomainAssociation_update, }, "Webhook": { "basic": testAccAWSAmplifyWebhook_basic, diff --git a/docs/MAINTAINING.md b/docs/MAINTAINING.md index 2a8d9b3c4743..bb36731efe7f 100644 --- a/docs/MAINTAINING.md +++ b/docs/MAINTAINING.md @@ -342,6 +342,7 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi | `ACM_CERTIFICATE_SINGLE_ISSUED_DOMAIN` | Domain name of ACM Certificate with a single issued certificate. **DEPRECATED:** Should be replaced with `aws_acm_certficate` resource usage in tests. | | `ACM_CERTIFICATE_SINGLE_ISSUED_MOST_RECENT_ARN` | Amazon Resource Name of most recent ACM Certificate with a single issued certificate. **DEPRECATED:** Should be replaced with `aws_acm_certficate` resource usage in tests. | | `ADM_CLIENT_ID` | Identifier for Amazon Device Manager Client in Pinpoint testing. | +| `AMPLIFY_DOMAIN_NAME` | Domain name to use for Amplify domain association testing. | | `AMPLIFY_GITHUB_ACCESS_TOKEN` | GitHub access token used for AWS Amplify testing. | | `AMPLIFY_GITHUB_REPOSITORY` | GitHub repository used for AWS Amplify testing. | | `ADM_CLIENT_SECRET` | Secret for Amazon Device Manager Client in Pinpoint testing. | From 6dccac660d47e0113f0be80071d73ba22a38b7f3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Jun 2021 15:01:12 -0400 Subject: [PATCH 0213/1208] Fix terrafmt error. --- aws/resource_aws_amplify_domain_association_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_amplify_domain_association_test.go b/aws/resource_aws_amplify_domain_association_test.go index 701e197546b9..6e3a8f4095a4 100644 --- a/aws/resource_aws_amplify_domain_association_test.go +++ b/aws/resource_aws_amplify_domain_association_test.go @@ -242,9 +242,9 @@ resource "aws_amplify_branch" "test" { } resource "aws_amplify_branch" "test2" { - app_id = aws_amplify_app.test.id - branch_name = "%[1]s-2" - } + app_id = aws_amplify_app.test.id + branch_name = "%[1]s-2" +} resource "aws_amplify_domain_association" "test" { app_id = aws_amplify_app.test.id From 459b930e3c1010d2a4e81b309abd8b415c688c62 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Jun 2021 15:16:33 -0400 Subject: [PATCH 0214/1208] r/aws_amplify_domain_association: Avoid 'BadRequestException: Cannot update domain while the domain is in PENDING_VERIFICATION status.'. --- ...rce_aws_amplify_domain_association_test.go | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/aws/resource_aws_amplify_domain_association_test.go b/aws/resource_aws_amplify_domain_association_test.go index 6e3a8f4095a4..2ffe7d1d0a23 100644 --- a/aws/resource_aws_amplify_domain_association_test.go +++ b/aws/resource_aws_amplify_domain_association_test.go @@ -33,7 +33,7 @@ func testAccAWSAmplifyDomainAssociation_basic(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyDomainAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyDomainAssociationConfig(rName, domainName), + Config: testAccAWSAmplifyDomainAssociationConfig(rName, domainName, false), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+/domains/.+`)), @@ -74,7 +74,7 @@ func testAccAWSAmplifyDomainAssociation_disappears(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyDomainAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyDomainAssociationConfig(rName, domainName), + Config: testAccAWSAmplifyDomainAssociationConfig(rName, domainName, false), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), testAccCheckResourceDisappears(testAccProvider, resourceAwsAmplifyDomainAssociation(), resourceName), @@ -103,7 +103,7 @@ func testAccAWSAmplifyDomainAssociation_update(t *testing.T) { CheckDestroy: testAccCheckAWSAmplifyDomainAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAmplifyDomainAssociationConfig(rName, domainName), + Config: testAccAWSAmplifyDomainAssociationConfig(rName, domainName, true), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+/domains/.+`)), @@ -113,7 +113,7 @@ func testAccAWSAmplifyDomainAssociation_update(t *testing.T) { "branch_name": rName, "prefix": "", }), - resource.TestCheckResourceAttr(resourceName, "wait_for_verification", "false"), + resource.TestCheckResourceAttr(resourceName, "wait_for_verification", "true"), ), }, { @@ -123,7 +123,7 @@ func testAccAWSAmplifyDomainAssociation_update(t *testing.T) { ImportStateVerifyIgnore: []string{"wait_for_verification"}, }, { - Config: testAccAWSAmplifyDomainAssociationConfigUpdated(rName, domainName), + Config: testAccAWSAmplifyDomainAssociationConfigUpdated(rName, domainName, true), Check: resource.ComposeTestCheckFunc( testAccCheckAWSAmplifyDomainAssociationExists(resourceName, &domain), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "amplify", regexp.MustCompile(`apps/.+/domains/.+`)), @@ -205,7 +205,7 @@ func testAccCheckAWSAmplifyDomainAssociationDestroy(s *terraform.State) error { return nil } -func testAccAWSAmplifyDomainAssociationConfig(rName, domainName string) string { +func testAccAWSAmplifyDomainAssociationConfig(rName, domainName string, waitForVerification bool) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { name = %[1]q @@ -225,12 +225,12 @@ resource "aws_amplify_domain_association" "test" { prefix = "" } - wait_for_verification = false + wait_for_verification = %[3]t } -`, rName, domainName) +`, rName, domainName, waitForVerification) } -func testAccAWSAmplifyDomainAssociationConfigUpdated(rName, domainName string) string { +func testAccAWSAmplifyDomainAssociationConfigUpdated(rName, domainName string, waitForVerification bool) string { return fmt.Sprintf(` resource "aws_amplify_app" "test" { name = %[1]q @@ -260,7 +260,7 @@ resource "aws_amplify_domain_association" "test" { prefix = "www" } - wait_for_verification = true + wait_for_verification = %[3]t } -`, rName, domainName) +`, rName, domainName, waitForVerification) } From 04b13770792b4d59d9b874c4ab5e913ca62f8792 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 3 Jun 2021 19:55:59 +0000 Subject: [PATCH 0215/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3b62cfddd22..324acdc5b620 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ FEATURES: * **New Resource:** `aws_amplify_branch` ([#11937](https://github.com/hashicorp/terraform-provider-aws/issues/11937)) +* **New Resource:** `aws_amplify_domain_association` ([#11938](https://github.com/hashicorp/terraform-provider-aws/issues/11938)) +* **New Resource:** `aws_amplify_webhook` ([#11939](https://github.com/hashicorp/terraform-provider-aws/issues/11939)) * **New Resource:** `aws_servicecatalog_principal_portfolio_association` ([#19470](https://github.com/hashicorp/terraform-provider-aws/issues/19470)) ENHANCEMENTS: @@ -18,7 +20,7 @@ ENHANCEMENTS: BUG FIXES: -* resource/aws_amplify_app: Mark the `enable_performance_mode` argumnet in the `auto_branch_creation_config` configuration block as `ForceNew` ([#11937](https://github.com/hashicorp/terraform-provider-aws/issues/11937)) +* resource/aws_amplify_app: Mark the `enable_performance_mode` argument in the `auto_branch_creation_config` configuration block as `ForceNew` ([#11937](https://github.com/hashicorp/terraform-provider-aws/issues/11937)) * resource/aws_elasticache_cluster: Fix provider-level `default_tags` support for resource ([#19615](https://github.com/hashicorp/terraform-provider-aws/issues/19615)) * resource/aws_iam_access_key: Fix status not defaulting to Active ([#19606](https://github.com/hashicorp/terraform-provider-aws/issues/19606)) From 629605281787cf1fa396938aa908cf63bd6a8e57 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Jun 2021 16:42:07 -0400 Subject: [PATCH 0216/1208] r/aws_cloudwatch_event_api_destination: Fix crash on update. --- aws/resource_aws_cloudwatch_event_api_destination.go | 2 +- ...ource_aws_cloudwatch_event_api_destination_test.go | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_api_destination.go b/aws/resource_aws_cloudwatch_event_api_destination.go index 0a645db0a8db..749becf9958c 100644 --- a/aws/resource_aws_cloudwatch_event_api_destination.go +++ b/aws/resource_aws_cloudwatch_event_api_destination.go @@ -148,7 +148,7 @@ func resourceAwsCloudWatchEventApiDestinationUpdate(d *schema.ResourceData, meta input.InvocationEndpoint = aws.String(invocationEndpoint.(string)) } if invocationRateLimitPerSecond, ok := d.GetOk("invocation_rate_limit_per_second"); ok { - input.InvocationRateLimitPerSecond = aws.Int64(invocationRateLimitPerSecond.(int64)) + input.InvocationRateLimitPerSecond = aws.Int64(int64(invocationRateLimitPerSecond.(int))) } if httpMethod, ok := d.GetOk("http_method"); ok { input.HttpMethod = aws.String(httpMethod.(string)) diff --git a/aws/resource_aws_cloudwatch_event_api_destination_test.go b/aws/resource_aws_cloudwatch_event_api_destination_test.go index 6ee21570cbd4..2f0b4045e50b 100644 --- a/aws/resource_aws_cloudwatch_event_api_destination_test.go +++ b/aws/resource_aws_cloudwatch_event_api_destination_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatchevents" events "github.com/aws/aws-sdk-go/service/cloudwatchevents" "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -84,7 +83,7 @@ func TestAccAWSCloudWatchEventApiDestination_basic(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCloudWatchEventApiDestinationDestroy, Steps: []resource.TestStep{ @@ -157,7 +156,7 @@ func TestAccAWSCloudWatchEventApiDestination_optional(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCloudWatchEventApiDestinationDestroy, Steps: []resource.TestStep{ @@ -207,7 +206,7 @@ func TestAccAWSCloudWatchEventApiDestination_optional(t *testing.T) { invocationEndpointModified, httpMethodModified, descriptionModified, - int64(invocationRateLimitPerSecondModified), + int64(invocationRateLimitPerSecond), ), Check: resource.ComposeTestCheckFunc( testAccCheckCloudWatchEventApiDestinationExists(resourceName, &v3), @@ -216,7 +215,7 @@ func TestAccAWSCloudWatchEventApiDestination_optional(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "http_method", httpMethodModified), resource.TestCheckResourceAttr(resourceName, "invocation_endpoint", invocationEndpointModified), resource.TestCheckResourceAttr(resourceName, "description", descriptionModified), - resource.TestCheckResourceAttr(resourceName, "invocation_rate_limit_per_second", fmt.Sprint(invocationRateLimitPerSecondModified)), + resource.TestCheckResourceAttr(resourceName, "invocation_rate_limit_per_second", fmt.Sprint(invocationRateLimitPerSecond)), ), }, }, @@ -233,7 +232,7 @@ func TestAccAWSCloudWatchEventApiDestination_disappears(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, cloudwatchevents.EndpointsID), + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCloudWatchEventApiDestinationDestroy, Steps: []resource.TestStep{ From 550aac9b869c91e8968d4c787b0d389580454609 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 3 Jun 2021 16:46:45 -0400 Subject: [PATCH 0217/1208] Add CHANGELOG entry. --- .changelog/19654.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19654.txt diff --git a/.changelog/19654.txt b/.changelog/19654.txt new file mode 100644 index 000000000000..3e8303887fbc --- /dev/null +++ b/.changelog/19654.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_cloudwatch_event_api_destination: Fix crash on resource update +``` \ No newline at end of file From 15ef1028b6bd9934379084d8aeb55fdcf86962e8 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 3 Jun 2021 21:02:24 +0000 Subject: [PATCH 0218/1208] Update CHANGELOG.md for #19654 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 324acdc5b620..2e7f0034b4dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ ENHANCEMENTS: BUG FIXES: * resource/aws_amplify_app: Mark the `enable_performance_mode` argument in the `auto_branch_creation_config` configuration block as `ForceNew` ([#11937](https://github.com/hashicorp/terraform-provider-aws/issues/11937)) +* resource/aws_cloudwatch_event_api_destination: Fix crash on resource update ([#19654](https://github.com/hashicorp/terraform-provider-aws/issues/19654)) * resource/aws_elasticache_cluster: Fix provider-level `default_tags` support for resource ([#19615](https://github.com/hashicorp/terraform-provider-aws/issues/19615)) * resource/aws_iam_access_key: Fix status not defaulting to Active ([#19606](https://github.com/hashicorp/terraform-provider-aws/issues/19606)) From eb33a76aec833459a32c901222494c103a43b21d Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 00:25:01 +0300 Subject: [PATCH 0219/1208] owner_id arg --- aws/resource_aws_default_vpc_dhcp_options.go | 53 ++++++++++++------- ...ource_aws_default_vpc_dhcp_options_test.go | 42 ++++++++++++++- .../r/default_vpc_dhcp_options.html.markdown | 2 +- 3 files changed, 76 insertions(+), 21 deletions(-) diff --git a/aws/resource_aws_default_vpc_dhcp_options.go b/aws/resource_aws_default_vpc_dhcp_options.go index 49f967b2922f..f5a4fab69910 100644 --- a/aws/resource_aws_default_vpc_dhcp_options.go +++ b/aws/resource_aws_default_vpc_dhcp_options.go @@ -33,31 +33,48 @@ func resourceAwsDefaultVpcDhcpOptions() *schema.Resource { Computed: true, } + dvpc.Schema["owner_id"] = &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + } + return dvpc } func resourceAwsDefaultVpcDhcpOptionsCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - req := &ec2.DescribeDhcpOptionsInput{ - Filters: []*ec2.Filter{ - { - Name: aws.String("key"), - Values: aws.StringSlice([]string{"domain-name"}), - }, - { - Name: aws.String("value"), - Values: aws.StringSlice([]string{resourceAwsEc2RegionalPrivateDnsSuffix(meta.(*AWSClient).region)}), - }, - { - Name: aws.String("key"), - Values: aws.StringSlice([]string{"domain-name-servers"}), - }, - { - Name: aws.String("value"), - Values: aws.StringSlice([]string{"AmazonProvidedDNS"}), - }, + filters := []*ec2.Filter{ + { + Name: aws.String("key"), + Values: aws.StringSlice([]string{"domain-name"}), + }, + { + Name: aws.String("value"), + Values: aws.StringSlice([]string{resourceAwsEc2RegionalPrivateDnsSuffix(meta.(*AWSClient).region)}), + }, + { + Name: aws.String("key"), + Values: aws.StringSlice([]string{"domain-name-servers"}), }, + { + Name: aws.String("value"), + Values: aws.StringSlice([]string{"AmazonProvidedDNS"}), + }, + } + + if v, ok := d.GetOk("owner_id"); ok { + filter := &ec2.Filter{ + Name: aws.String("owner-id"), + Values: aws.StringSlice([]string{v.(string)}), + } + + filters = append(filters, filter) + } + + req := &ec2.DescribeDhcpOptionsInput{ + Filters: filters, } var dhcpOptions []*ec2.DhcpOptions diff --git a/aws/resource_aws_default_vpc_dhcp_options_test.go b/aws/resource_aws_default_vpc_dhcp_options_test.go index 51cf6c6c971c..6326be7317dc 100644 --- a/aws/resource_aws_default_vpc_dhcp_options_test.go +++ b/aws/resource_aws_default_vpc_dhcp_options_test.go @@ -11,7 +11,7 @@ import ( func TestAccAWSDefaultVpcDhcpOptions_basic(t *testing.T) { var d ec2.DhcpOptions - resourceName := "aws_default_vpc_dhcp_options.foo" + resourceName := "aws_default_vpc_dhcp_options.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -35,13 +35,51 @@ func TestAccAWSDefaultVpcDhcpOptions_basic(t *testing.T) { }) } +func TestAccAWSDefaultVpcDhcpOptions_owner(t *testing.T) { + var d ec2.DhcpOptions + resourceName := "aws_default_vpc_dhcp_options.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDefaultVpcDhcpOptionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDefaultVpcDhcpOptionsConfigOwner, + Check: resource.ComposeTestCheckFunc( + testAccCheckDHCPOptionsExists(resourceName, &d), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`dhcp-options/dopt-.+`)), + resource.TestCheckResourceAttr(resourceName, "domain_name", resourceAwsEc2RegionalPrivateDnsSuffix(testAccGetRegion())), + resource.TestCheckResourceAttr(resourceName, "domain_name_servers", "AmazonProvidedDNS"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", "Default DHCP Option Set"), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + ), + }, + }, + }) +} + func testAccCheckAWSDefaultVpcDhcpOptionsDestroy(s *terraform.State) error { // We expect DHCP Options Set to still exist return nil } const testAccAWSDefaultVpcDhcpOptionsConfigBasic = ` -resource "aws_default_vpc_dhcp_options" "foo" { +resource "aws_default_vpc_dhcp_options" "test" { + tags = { + Name = "Default DHCP Option Set" + } +} +` + +const testAccAWSDefaultVpcDhcpOptionsConfigOwner = ` +data "aws_caller_identity" "current" {} + +resource "aws_default_vpc_dhcp_options" "test" { + owner_id = data.aws_caller_identity.current.account_id + tags = { Name = "Default DHCP Option Set" } diff --git a/website/docs/r/default_vpc_dhcp_options.html.markdown b/website/docs/r/default_vpc_dhcp_options.html.markdown index 9c46ffe3ef4c..f4a852e724e3 100644 --- a/website/docs/r/default_vpc_dhcp_options.html.markdown +++ b/website/docs/r/default_vpc_dhcp_options.html.markdown @@ -39,6 +39,7 @@ The following arguments are still supported: * `netbios_name_servers` - (Optional) List of NETBIOS name servers. * `netbios_node_type` - (Optional) The NetBIOS node type (1, 2, 4, or 8). AWS recommends to specify 2 since broadcast and multicast are not supported in their network. For more information about these node types, see [RFC 2132](http://www.ietf.org/rfc/rfc2132.txt). +* `owner_id` - The ID of the AWS account that owns the DHCP options set. * `tags` - (Optional) A map of tags to assign to the resource. ### Removing `aws_default_vpc_dhcp_options` from your configuration @@ -54,7 +55,6 @@ In addition to all arguments above, the following attributes are exported: * `id` - The ID of the DHCP Options Set. * `arn` - The ARN of the DHCP Options Set. -* `owner_id` - The ID of the AWS account that owns the DHCP options set. ## Import From 11679e5b84a243cb22074293a0be737d610cd099 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 00:27:29 +0300 Subject: [PATCH 0220/1208] changelog --- .changelog/19656.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19656.txt diff --git a/.changelog/19656.txt b/.changelog/19656.txt new file mode 100644 index 000000000000..32399c4fe364 --- /dev/null +++ b/.changelog/19656.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_default_vpc_dhcp_options: Add `owner_id` argument. +``` \ No newline at end of file From 0059bf207fddfdbd1242786f59ccf368f10c642c Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 00:37:03 +0300 Subject: [PATCH 0221/1208] fmt --- aws/resource_aws_default_vpc_dhcp_options_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_default_vpc_dhcp_options_test.go b/aws/resource_aws_default_vpc_dhcp_options_test.go index 6326be7317dc..ab6cc56ee660 100644 --- a/aws/resource_aws_default_vpc_dhcp_options_test.go +++ b/aws/resource_aws_default_vpc_dhcp_options_test.go @@ -79,7 +79,7 @@ data "aws_caller_identity" "current" {} resource "aws_default_vpc_dhcp_options" "test" { owner_id = data.aws_caller_identity.current.account_id - + tags = { Name = "Default DHCP Option Set" } From c16ad68fc0b64ca6c4ae2a4eea981e38eca0dbf9 Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Thu, 3 Jun 2021 22:06:58 +0000 Subject: [PATCH 0222/1208] v3.44.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e7f0034b4dd..5cebc142d93a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 3.44.0 (Unreleased) +## 3.44.0 (June 03, 2021) FEATURES: From 0df25c7bc8eb3e52e8a95c8583964eb0496f6d83 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 3 Jun 2021 22:26:35 +0000 Subject: [PATCH 0223/1208] Update CHANGELOG.md after v3.44.0 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cebc142d93a..a6a7ff3a80aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## 3.45.0 (Unreleased) ## 3.44.0 (June 03, 2021) FEATURES: From d9f6cf2b2f48483dead42804498ba19dd0613dd8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Jun 2021 06:22:20 +0000 Subject: [PATCH 0224/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.53 to 1.38.54. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.53...v1.38.54) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- .../github.com/aws/aws-sdk-go/service/s3/api.go | 16 +++++++++++----- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 9ef40ef59bcf..6d654639ae40 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.53 + github.com/aws/aws-sdk-go v1.38.54 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index bbdc129029c8..b83998d7df43 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.53 h1:Qj5OvKPrDGTiCnWj+kwQXAlBO6OaFBH/WaRzJPZPg3w= -github.com/aws/aws-sdk-go v1.38.53/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.54 h1:fsiNnyso3kIWmUdCSYZt/4oodinY6O6biM1CJMsdYpc= +github.com/aws/aws-sdk-go v1.38.54/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index 7d0c72aea7b8..572b480d25e6 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.53" +const SDKVersion = "1.38.54" diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/s3/api.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/s3/api.go index ebdd5f616e9a..e23d94b1a0d3 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/s3/api.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/s3/api.go @@ -8815,11 +8815,12 @@ func (c *S3) PutBucketTaggingRequest(input *PutBucketTaggingInput) (req *request // according to resources with the same tag key values. For example, you can // tag several resources with a specific application name, and then organize // your billing information to see the total cost of that application across -// several services. For more information, see Cost Allocation and Tagging (https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html). +// several services. For more information, see Cost Allocation and Tagging (https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html) +// and Using Cost Allocation in Amazon S3 Bucket Tags (https://docs.aws.amazon.com/AmazonS3/latest/dev/CostAllocTagging.html). // -// Within a bucket, if you add a tag that has the same key as an existing tag, -// the new value overwrites the old value. For more information, see Using Cost -// Allocation in Amazon S3 Bucket Tags (https://docs.aws.amazon.com/AmazonS3/latest/dev/CostAllocTagging.html). +// When this operation sets the tags for a bucket, it will overwrite any current +// tags the bucket already has. You cannot use this operation to add tags to +// an existing list of tags. // // To use this operation, you must have permissions to perform the s3:PutBucketTagging // action. The bucket owner has this permission by default and can grant this @@ -30056,7 +30057,8 @@ type PutObjectInput struct { // The Object Lock mode that you want to apply to this object. ObjectLockMode *string `location:"header" locationName:"x-amz-object-lock-mode" type:"string" enum:"ObjectLockMode"` - // The date and time when you want this object's Object Lock to expire. + // The date and time when you want this object's Object Lock to expire. Must + // be formatted as a timestamp parameter. ObjectLockRetainUntilDate *time.Time `location:"header" locationName:"x-amz-object-lock-retain-until-date" type:"timestamp" timestampFormat:"iso8601"` // Confirms that the requester knows that they will be charged for the request. @@ -36036,6 +36038,9 @@ const ( // InventoryOptionalFieldIntelligentTieringAccessTier is a InventoryOptionalField enum value InventoryOptionalFieldIntelligentTieringAccessTier = "IntelligentTieringAccessTier" + + // InventoryOptionalFieldBucketKeyStatus is a InventoryOptionalField enum value + InventoryOptionalFieldBucketKeyStatus = "BucketKeyStatus" ) // InventoryOptionalField_Values returns all elements of the InventoryOptionalField enum @@ -36052,6 +36057,7 @@ func InventoryOptionalField_Values() []string { InventoryOptionalFieldObjectLockMode, InventoryOptionalFieldObjectLockLegalHoldStatus, InventoryOptionalFieldIntelligentTieringAccessTier, + InventoryOptionalFieldBucketKeyStatus, } } diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index a1510d3c78de..cd642952109e 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.53 +# github.com/aws/aws-sdk-go v1.38.54 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From f13916a615c88d362ea6d5e1f95478b9a9dd92b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Jun 2021 06:23:07 +0000 Subject: [PATCH 0225/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.53 to 1.38.54 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.53 to 1.38.54. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.53...v1.38.54) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index dd113710b11e..467802da399e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.53 + github.com/aws/aws-sdk-go v1.38.54 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index 2afd4dc501a2..db173458b47c 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.53 h1:Qj5OvKPrDGTiCnWj+kwQXAlBO6OaFBH/WaRzJPZPg3w= -github.com/aws/aws-sdk-go v1.38.53/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.54 h1:fsiNnyso3kIWmUdCSYZt/4oodinY6O6biM1CJMsdYpc= +github.com/aws/aws-sdk-go v1.38.54/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 5fa1c633deef03777d0a716090867eda8330415b Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 11:23:54 +0300 Subject: [PATCH 0226/1208] add compression type --- aws/resource_aws_fsx_lustre_file_system.go | 71 +++++++++++-------- ...esource_aws_fsx_lustre_file_system_test.go | 53 ++++++++++++++ 2 files changed, 93 insertions(+), 31 deletions(-) diff --git a/aws/resource_aws_fsx_lustre_file_system.go b/aws/resource_aws_fsx_lustre_file_system.go index 3704bb313ee5..d5460f88ac36 100644 --- a/aws/resource_aws_fsx_lustre_file_system.go +++ b/aws/resource_aws_fsx_lustre_file_system.go @@ -182,6 +182,12 @@ func resourceAwsFsxLustreFileSystem() *schema.Resource { ForceNew: true, Default: false, }, + "data_compression_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(fsx.DataCompressionType_Values(), false), + Default: fsx.DataCompressionTypeNone, + }, }, CustomizeDiff: customdiff.Sequence( @@ -274,6 +280,10 @@ func resourceAwsFsxLustreFileSystemCreate(d *schema.ResourceData, meta interface input.LustreConfiguration.CopyTagsToBackups = aws.Bool(v.(bool)) } + if v, ok := d.GetOk("data_compression_type"); ok { + input.LustreConfiguration.DataCompressionType = aws.String(v.(string)) + } + result, err := conn.CreateFileSystem(input) if err != nil { return fmt.Errorf("Error creating FSx Lustre filesystem: %w", err) @@ -301,39 +311,37 @@ func resourceAwsFsxLustreFileSystemUpdate(d *schema.ResourceData, meta interface } } - requestUpdate := false - input := &fsx.UpdateFileSystemInput{ - ClientRequestToken: aws.String(resource.UniqueId()), - FileSystemId: aws.String(d.Id()), - LustreConfiguration: &fsx.UpdateFileSystemLustreConfiguration{}, - } + if d.HasChangesExcept("tags_all", "tags") { + input := &fsx.UpdateFileSystemInput{ + ClientRequestToken: aws.String(resource.UniqueId()), + FileSystemId: aws.String(d.Id()), + LustreConfiguration: &fsx.UpdateFileSystemLustreConfiguration{}, + } - if d.HasChange("weekly_maintenance_start_time") { - input.LustreConfiguration.WeeklyMaintenanceStartTime = aws.String(d.Get("weekly_maintenance_start_time").(string)) - requestUpdate = true - } + if d.HasChange("weekly_maintenance_start_time") { + input.LustreConfiguration.WeeklyMaintenanceStartTime = aws.String(d.Get("weekly_maintenance_start_time").(string)) + } - if d.HasChange("automatic_backup_retention_days") { - input.LustreConfiguration.AutomaticBackupRetentionDays = aws.Int64(int64(d.Get("automatic_backup_retention_days").(int))) - requestUpdate = true - } + if d.HasChange("automatic_backup_retention_days") { + input.LustreConfiguration.AutomaticBackupRetentionDays = aws.Int64(int64(d.Get("automatic_backup_retention_days").(int))) + } - if d.HasChange("daily_automatic_backup_start_time") { - input.LustreConfiguration.DailyAutomaticBackupStartTime = aws.String(d.Get("daily_automatic_backup_start_time").(string)) - requestUpdate = true - } + if d.HasChange("daily_automatic_backup_start_time") { + input.LustreConfiguration.DailyAutomaticBackupStartTime = aws.String(d.Get("daily_automatic_backup_start_time").(string)) + } - if d.HasChange("auto_import_policy") { - input.LustreConfiguration.AutoImportPolicy = aws.String(d.Get("auto_import_policy").(string)) - requestUpdate = true - } + if d.HasChange("auto_import_policy") { + input.LustreConfiguration.AutoImportPolicy = aws.String(d.Get("auto_import_policy").(string)) + } - if d.HasChange("storage_capacity") { - input.StorageCapacity = aws.Int64(int64(d.Get("storage_capacity").(int))) - requestUpdate = true - } + if d.HasChange("storage_capacity") { + input.StorageCapacity = aws.Int64(int64(d.Get("storage_capacity").(int))) + } + + if v, ok := d.GetOk("data_compression_type"); ok { + input.LustreConfiguration.DataCompressionType = aws.String(v.(string)) + } - if requestUpdate { _, err := conn.UpdateFileSystem(input) if err != nil { return fmt.Errorf("error updating FSX Lustre File System (%s): %w", d.Id(), err) @@ -397,10 +405,10 @@ func resourceAwsFsxLustreFileSystemRead(d *schema.ResourceData, meta interface{} if lustreConfig.PerUnitStorageThroughput != nil { d.Set("per_unit_storage_throughput", lustreConfig.PerUnitStorageThroughput) } - d.Set("mount_name", filesystem.LustreConfiguration.MountName) + d.Set("mount_name", lustreConfig.MountName) d.Set("storage_type", filesystem.StorageType) - if filesystem.LustreConfiguration.DriveCacheType != nil { - d.Set("drive_cache_type", filesystem.LustreConfiguration.DriveCacheType) + if lustreConfig.DriveCacheType != nil { + d.Set("drive_cache_type", lustreConfig.DriveCacheType) } if filesystem.KmsKeyId != nil { @@ -433,7 +441,8 @@ func resourceAwsFsxLustreFileSystemRead(d *schema.ResourceData, meta interface{} d.Set("weekly_maintenance_start_time", lustreConfig.WeeklyMaintenanceStartTime) d.Set("automatic_backup_retention_days", lustreConfig.AutomaticBackupRetentionDays) d.Set("daily_automatic_backup_start_time", lustreConfig.DailyAutomaticBackupStartTime) - d.Set("copy_tags_to_backups", filesystem.LustreConfiguration.CopyTagsToBackups) + d.Set("copy_tags_to_backups", lustreConfig.CopyTagsToBackups) + d.Set("data_compression_type", lustreConfig.DataCompressionType) return nil } diff --git a/aws/resource_aws_fsx_lustre_file_system_test.go b/aws/resource_aws_fsx_lustre_file_system_test.go index 119ff6a9af1d..7e6d42c56a8a 100644 --- a/aws/resource_aws_fsx_lustre_file_system_test.go +++ b/aws/resource_aws_fsx_lustre_file_system_test.go @@ -107,6 +107,7 @@ func TestAccAWSFsxLustreFileSystem_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "automatic_backup_retention_days", "0"), resource.TestCheckResourceAttr(resourceName, "storage_type", fsx.StorageTypeSsd), resource.TestCheckResourceAttr(resourceName, "copy_tags_to_backups", "false"), + resource.TestCheckResourceAttr(resourceName, "data_compression_type", fsx.DataCompressionTypeNone), ), }, { @@ -141,6 +142,47 @@ func TestAccAWSFsxLustreFileSystem_disappears(t *testing.T) { }) } +func TestAccAWSFsxLustreFileSystem_dataCompression(t *testing.T) { + var filesystem fsx.FileSystem + resourceName := "aws_fsx_lustre_file_system.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(fsx.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, fsx.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckFsxLustreFileSystemDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsFsxLustreFileSystemConfigCompression(), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem), + resource.TestCheckResourceAttr(resourceName, "data_compression_type", fsx.DataCompressionTypeLz4), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"security_group_ids"}, + }, + { + Config: testAccAwsFsxLustreFileSystemConfigSubnetIds1(), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem), + resource.TestCheckResourceAttr(resourceName, "data_compression_type", fsx.DataCompressionTypeNone), + ), + }, + { + Config: testAccAwsFsxLustreFileSystemConfigCompression(), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxLustreFileSystemExists(resourceName, &filesystem), + resource.TestCheckResourceAttr(resourceName, "data_compression_type", fsx.DataCompressionTypeLz4), + ), + }, + }, + }) +} + func TestAccAWSFsxLustreFileSystem_ExportPath(t *testing.T) { var filesystem1, filesystem2 fsx.FileSystem resourceName := "aws_fsx_lustre_file_system.test" @@ -1151,3 +1193,14 @@ resource "aws_fsx_lustre_file_system" "test" { } `) } + +func testAccAwsFsxLustreFileSystemConfigCompression() string { + return composeConfig(testAccAwsFsxLustreFileSystemConfigBase(), ` +resource "aws_fsx_lustre_file_system" "test" { + storage_capacity = 1200 + subnet_ids = [aws_subnet.test1.id] + deployment_type = data.aws_partition.current.partition == "aws-us-gov" ? "SCRATCH_2" : null # GovCloud does not support SCRATCH_1 + data_compression_type = "LZ4" +} +`) +} From f7938e57494616c412a8df654ff89ee0a13da8f5 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 11:26:52 +0300 Subject: [PATCH 0227/1208] docs --- website/docs/r/fsx_lustre_file_system.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/fsx_lustre_file_system.html.markdown b/website/docs/r/fsx_lustre_file_system.html.markdown index ae3e53478d1b..af4962dda2fd 100644 --- a/website/docs/r/fsx_lustre_file_system.html.markdown +++ b/website/docs/r/fsx_lustre_file_system.html.markdown @@ -41,6 +41,7 @@ The following arguments are supported: * `daily_automatic_backup_start_time` - (Optional) A recurring daily time, in the format HH:MM. HH is the zero-padded hour of the day (0-23), and MM is the zero-padded minute of the hour. For example, 05:00 specifies 5 AM daily. only valid for `PERSISTENT_1` deployment_type. Requires `automatic_backup_retention_days` to be set. * `auto_import_policy` - (Optional) How Amazon FSx keeps your file and directory listings up to date as you add or modify objects in your linked S3 bucket. see [Auto Import Data Repo](https://docs.aws.amazon.com/fsx/latest/LustreGuide/autoimport-data-repo.html) for more details. * `copy_tags_to_backups` - (Optional) A boolean flag indicating whether tags for the file system should be copied to backups. Applicable for `PERSISTENT_1` deployment_type. The default value is false. +* `data_compression_type` - (Optional) Sets the data compression configuration for the file system. Valid values are `LZ4` and `NONE`. Default value is `NONE`. Unsetting this value reverts the compression type back to `NONE`. ## Attributes Reference From 5fd1c948c4cfcd3894d95ed92ac6d1fc16df6540 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 11:31:16 +0300 Subject: [PATCH 0228/1208] changelog --- .changelog/19664.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19664.txt diff --git a/.changelog/19664.txt b/.changelog/19664.txt new file mode 100644 index 000000000000..96a024a5014b --- /dev/null +++ b/.changelog/19664.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_fsx_lustre_filesystem: Add `data_compression_type` argument. +``` \ No newline at end of file From e3f7067a6fbea10520c98fc40a1ec887e63801af Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 4 Jun 2021 09:40:59 -0400 Subject: [PATCH 0229/1208] r/aws_batch_job_definition: Match equivalency of 'null' and '[]' for 'linuxParameters.devices' and 'linuxParameters.tmpfs'. --- .../batch/equivalency/container_properties.go | 26 ++++++ .../equivalency/container_properties_test.go | 83 +++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/aws/internal/service/batch/equivalency/container_properties.go b/aws/internal/service/batch/equivalency/container_properties.go index 4954b75aaf0d..272cf3ee0343 100644 --- a/aws/internal/service/batch/equivalency/container_properties.go +++ b/aws/internal/service/batch/equivalency/container_properties.go @@ -36,8 +36,34 @@ func (cp *containerProperties) Reduce() error { } } + if cp.LinuxParameters != nil { + if len(cp.LinuxParameters.Devices) == 0 { + cp.LinuxParameters.Devices = nil + } + + for _, device := range cp.LinuxParameters.Devices { + if len(device.Permissions) == 0 { + device.Permissions = nil + } + } + + if len(cp.LinuxParameters.Tmpfs) == 0 { + cp.LinuxParameters.Tmpfs = nil + } + + for _, tmpfs := range cp.LinuxParameters.Tmpfs { + if len(tmpfs.MountOptions) == 0 { + tmpfs.MountOptions = nil + } + } + } + // Prevent difference of API response that adds an empty array when not configured during the request if cp.LogConfiguration != nil { + if len(cp.LogConfiguration.Options) == 0 { + cp.LogConfiguration.Options = nil + } + if len(cp.LogConfiguration.SecretOptions) == 0 { cp.LogConfiguration.SecretOptions = nil } diff --git a/aws/internal/service/batch/equivalency/container_properties_test.go b/aws/internal/service/batch/equivalency/container_properties_test.go index 48956f6d4cee..7baca6f05f0b 100644 --- a/aws/internal/service/batch/equivalency/container_properties_test.go +++ b/aws/internal/service/batch/equivalency/container_properties_test.go @@ -282,6 +282,89 @@ func TestEquivalentBatchContainerPropertiesJSON(t *testing.T) { } ] } +`, + ExpectEquivalent: true, + }, + { + Name: "empty linuxParameters.devices, linuxParameters.tmpfs, logConfiguration.options", + ApiJson: ` +{ + "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", + "vcpus": 1, + "memory": 4096, + "jobRoleArn": "arn:aws:iam::123:role/role-test", + "environment": [{"name":"ENVIRONMENT","value":"test"}], + "linuxParameters": { + "devices": [], + "initProcessEnabled": true, + "tmpfs": [] + }, + "logConfiguration": { + "logDriver": "awslogs", + "options": {} + } +} +`, + ConfigurationJson: ` +{ + "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", + "vcpus": 1, + "memory": 4096, + "jobRoleArn": "arn:aws:iam::123:role/role-test", + "environment": [{"name":"ENVIRONMENT","value":"test"}], + "linuxParameters": { + "initProcessEnabled": true + }, + "logConfiguration": { + "logDriver": "awslogs" + } +} +`, + ExpectEquivalent: true, + }, + { + Name: "empty linuxParameters.devices.permissions, linuxParameters.tmpfs.mountOptions", + ApiJson: ` +{ + "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", + "vcpus": 1, + "memory": 4096, + "jobRoleArn": "arn:aws:iam::123:role/role-test", + "environment": [{"name":"ENVIRONMENT","value":"test"}], + "linuxParameters": { + "devices": [{ + "containerPath": "/test", + "hostPath": "/tmp", + "permissions": [] + }], + "initProcessEnabled": true, + "tmpfs": [{ + "containerPath": "/tmp", + "mountOptions": [], + "size": 4096 + }] + } +} +`, + ConfigurationJson: ` +{ + "image": "123.dkr.ecr.us-east-1.amazonaws.com/my-app", + "vcpus": 1, + "memory": 4096, + "jobRoleArn": "arn:aws:iam::123:role/role-test", + "environment": [{"name":"ENVIRONMENT","value":"test"}], + "linuxParameters": { + "devices": [{ + "containerPath": "/test", + "hostPath": "/tmp" + }], + "initProcessEnabled": true, + "tmpfs": [{ + "containerPath": "/tmp", + "size": 4096 + }] + } +} `, ExpectEquivalent: true, }, From 2db27cf71c73da95912219c26178f647bf35a04a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 4 Jun 2021 10:12:02 -0400 Subject: [PATCH 0230/1208] r/aws_cloudwatch_metric_alarm: Allow extended statistics in 'metric.stat'. --- aws/resource_aws_cloudwatch_metric_alarm.go | 9 ++++++--- aws/resource_aws_cloudwatch_metric_alarm_test.go | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_cloudwatch_metric_alarm.go b/aws/resource_aws_cloudwatch_metric_alarm.go index c3ac1c24fed9..42ba993726ab 100644 --- a/aws/resource_aws_cloudwatch_metric_alarm.go +++ b/aws/resource_aws_cloudwatch_metric_alarm.go @@ -99,9 +99,12 @@ func resourceAwsCloudWatchMetricAlarm() *schema.Resource { Required: true, }, "stat": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(cloudwatch.Statistic_Values(), false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.Any( + validation.StringInSlice(cloudwatch.Statistic_Values(), false), + validation.StringMatch(regexp.MustCompile(`p(\d{1,2}(\.\d{0,2})?|100)`), "must specify a value between p0.0 and p100"), + ), }, "unit": { Type: schema.TypeString, diff --git a/aws/resource_aws_cloudwatch_metric_alarm_test.go b/aws/resource_aws_cloudwatch_metric_alarm_test.go index e6c15d1f84a6..f666bb1b0384 100644 --- a/aws/resource_aws_cloudwatch_metric_alarm_test.go +++ b/aws/resource_aws_cloudwatch_metric_alarm_test.go @@ -716,7 +716,7 @@ resource "aws_cloudwatch_metric_alarm" "test" { metric_name = "CPUUtilization" namespace = "AWS/EC2" period = "120" - stat = "Average" + stat = "p95.45" unit = "Count" dimensions = { From d1ce0c793a918ddafd8b3775b1a9f087f84b293d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 4 Jun 2021 10:15:24 -0400 Subject: [PATCH 0231/1208] Add CHANGELOG entry. --- .changelog/19668.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19668.txt diff --git a/.changelog/19668.txt b/.changelog/19668.txt new file mode 100644 index 000000000000..f1c4e66da493 --- /dev/null +++ b/.changelog/19668.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_cloudwatch_metric_alarm: Allow extended statistics in the `stat` argument of the `metric` configuration block +``` \ No newline at end of file From cb49ce07b400c4e35f46120e8f5a01c1a76782e4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 4 Jun 2021 10:23:18 -0400 Subject: [PATCH 0232/1208] Add CHANGELOG entry. --- .changelog/19666.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19666.txt diff --git a/.changelog/19666.txt b/.changelog/19666.txt new file mode 100644 index 000000000000..c22c8c477975 --- /dev/null +++ b/.changelog/19666.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_batch_job_definition: Suppress differences for empty `linuxParameters.devices` and `linuxParameters.tmpfs` arrays in the `container_properties` argument +``` \ No newline at end of file From d8623c8634be3bc81dc924354f6b0d1f009cf8e2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 16 Apr 2021 16:03:55 -0400 Subject: [PATCH 0233/1208] r/aws_sqs_queue(_policy): Simplify acceptance tests for GovCloud. --- aws/internal/service/sqs/consts.go | 8 + aws/internal/service/sqs/waiter/waiter.go | 14 ++ aws/resource_aws_sqs_queue.go | 20 +-- aws/resource_aws_sqs_queue_policy.go | 1 + aws/resource_aws_sqs_queue_policy_test.go | 19 +-- aws/resource_aws_sqs_queue_test.go | 196 ++++++++++++---------- 6 files changed, 152 insertions(+), 106 deletions(-) create mode 100644 aws/internal/service/sqs/waiter/waiter.go diff --git a/aws/internal/service/sqs/consts.go b/aws/internal/service/sqs/consts.go index c3c2ad484441..61adf57fb417 100644 --- a/aws/internal/service/sqs/consts.go +++ b/aws/internal/service/sqs/consts.go @@ -3,3 +3,11 @@ package sqs const ( FifoQueueNameSuffix = ".fifo" ) + +const ( + DefaultQueueDelaySeconds = 0 + DefaultQueueMaximumMessageSize = 262144 + DefaultQueueMessageRetentionPeriod = 345600 + DefaultQueueReceiveMessageWaitTimeSeconds = 0 + DefaultQueueVisibilityTimeout = 30 +) diff --git a/aws/internal/service/sqs/waiter/waiter.go b/aws/internal/service/sqs/waiter/waiter.go new file mode 100644 index 000000000000..86a2c078cd3d --- /dev/null +++ b/aws/internal/service/sqs/waiter/waiter.go @@ -0,0 +1,14 @@ +package waiter + +import ( + "time" +) + +const ( + // Maximum amount of time to wait for SQS queue attribute changes to propagate + // This timeout should not be increased without strong consideration + // as this will negatively impact user experience when configurations + // have incorrect references or permissions. + // Reference: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SetQueueAttributes.html + QueueAttributePropagationTimeout = 1 * time.Minute +) diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index 534cd0a041e4..44026dc5192a 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -74,27 +74,27 @@ func resourceAwsSqsQueue() *schema.Resource { "delay_seconds": { Type: schema.TypeInt, Optional: true, - Default: 0, + Default: tfsqs.DefaultQueueDelaySeconds, }, "max_message_size": { Type: schema.TypeInt, Optional: true, - Default: 262144, + Default: tfsqs.DefaultQueueMaximumMessageSize, }, "message_retention_seconds": { Type: schema.TypeInt, Optional: true, - Default: 345600, + Default: tfsqs.DefaultQueueMessageRetentionPeriod, }, "receive_wait_time_seconds": { Type: schema.TypeInt, Optional: true, - Default: 0, + Default: tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds, }, "visibility_timeout_seconds": { Type: schema.TypeInt, Optional: true, - Default: 30, + Default: tfsqs.DefaultQueueVisibilityTimeout, }, "policy": { Type: schema.TypeString, @@ -297,15 +297,15 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { // Always set attribute defaults d.Set("arn", "") d.Set("content_based_deduplication", false) - d.Set("delay_seconds", 0) + d.Set("delay_seconds", tfsqs.DefaultQueueDelaySeconds) d.Set("kms_data_key_reuse_period_seconds", 300) d.Set("kms_master_key_id", "") - d.Set("max_message_size", 262144) - d.Set("message_retention_seconds", 345600) + d.Set("max_message_size", tfsqs.DefaultQueueMaximumMessageSize) + d.Set("message_retention_seconds", tfsqs.DefaultQueueMessageRetentionPeriod) d.Set("policy", "") - d.Set("receive_wait_time_seconds", 0) + d.Set("receive_wait_time_seconds", tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds) d.Set("redrive_policy", "") - d.Set("visibility_timeout_seconds", 30) + d.Set("visibility_timeout_seconds", tfsqs.DefaultQueueVisibilityTimeout) if attributeOutput != nil { queueAttributes := aws.StringValueMap(attributeOutput.Attributes) diff --git a/aws/resource_aws_sqs_queue_policy.go b/aws/resource_aws_sqs_queue_policy.go index cd3e2b0d8a25..5c8442122864 100644 --- a/aws/resource_aws_sqs_queue_policy.go +++ b/aws/resource_aws_sqs_queue_policy.go @@ -81,6 +81,7 @@ func resourceAwsSqsQueuePolicyUpsert(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] SQS attribute %s not found - retrying", sqs.QueueAttributeNamePolicy) return resource.RetryableError(notUpdatedError) } + equivalent, err := awspolicy.PoliciesAreEquivalent(aws.StringValue(queuePolicy), policy) if err != nil { return resource.NonRetryableError(err) diff --git a/aws/resource_aws_sqs_queue_policy_test.go b/aws/resource_aws_sqs_queue_policy_test.go index a75bb561994c..11b8f863c4a7 100644 --- a/aws/resource_aws_sqs_queue_policy_test.go +++ b/aws/resource_aws_sqs_queue_policy_test.go @@ -13,6 +13,7 @@ import ( func TestAccAWSSQSQueuePolicy_basic(t *testing.T) { var queueAttributes map[string]*string resourceName := "aws_sqs_queue_policy.test" + queueResourceName := "aws_sqs_queue.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -24,9 +25,8 @@ func TestAccAWSSQSQueuePolicy_basic(t *testing.T) { { Config: testAccAWSSQSPolicyConfigBasic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSQSQueueExists("aws_sqs_queue.test", &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), - resource.TestMatchResourceAttr("aws_sqs_queue_policy.test", "policy", + testAccCheckAWSSQSQueueExists(queueResourceName, &queueAttributes), + resource.TestMatchResourceAttr(resourceName, "policy", regexp.MustCompile("^{\"Version\":\"2012-10-17\".+")), ), }, @@ -39,7 +39,7 @@ func TestAccAWSSQSQueuePolicy_basic(t *testing.T) { Config: testAccAWSSQSPolicyConfigBasic(rName), PlanOnly: true, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrPair(resourceName, "policy", "aws_sqs_queue.test", "policy"), + resource.TestCheckResourceAttrPair(resourceName, "policy", queueResourceName, "policy"), ), }, }, @@ -48,7 +48,7 @@ func TestAccAWSSQSQueuePolicy_basic(t *testing.T) { func TestAccAWSSQSQueuePolicy_disappears_queue(t *testing.T) { var queueAttributes map[string]*string - resourceName := "aws_sqs_queue_policy.test" + queueResourceName := "aws_sqs_queue.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -60,9 +60,8 @@ func TestAccAWSSQSQueuePolicy_disappears_queue(t *testing.T) { { Config: testAccAWSSQSPolicyConfigBasic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSQSQueueExists("aws_sqs_queue.test", &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), - testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueue(), resourceName), + testAccCheckAWSSQSQueueExists(queueResourceName, &queueAttributes), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueue(), queueResourceName), ), ExpectNonEmptyPlan: true, }, @@ -73,6 +72,7 @@ func TestAccAWSSQSQueuePolicy_disappears_queue(t *testing.T) { func TestAccAWSSQSQueuePolicy_disappears(t *testing.T) { var queueAttributes map[string]*string resourceName := "aws_sqs_queue_policy.test" + queueResourceName := "aws_sqs_queue.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -84,8 +84,7 @@ func TestAccAWSSQSQueuePolicy_disappears(t *testing.T) { { Config: testAccAWSSQSPolicyConfigBasic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSQSQueueExists("aws_sqs_queue.test", &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), + testAccCheckAWSSQSQueueExists(queueResourceName, &queueAttributes), testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueuePolicy(), resourceName), ), ExpectNonEmptyPlan: true, diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index 826f150b476a..bdc118db8573 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "strconv" "testing" "time" @@ -76,9 +77,9 @@ func testSweepSqsQueues(region string) error { func TestAccAWSSQSQueue_basic(t *testing.T) { var queueAttributes map[string]*string - resourceName := "aws_sqs_queue.queue" queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), @@ -89,7 +90,11 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { Config: testAccAWSSQSConfigWithDefaults(queueName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { @@ -101,25 +106,56 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { Config: testAccAWSSQSConfigWithOverrides(queueName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueueOverrideAttributes(&queueAttributes), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", "90"), + resource.TestCheckResourceAttr(resourceName, "max_message_size", "2048"), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", "86400"), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", "10"), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", "60"), ), }, { Config: testAccAWSSQSConfigWithDefaults(queueName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, }, }) } -func TestAccAWSSQSQueue_tags(t *testing.T) { +func TestAccAWSSQSQueue_disappears(t *testing.T) { var queueAttributes map[string]*string + resourceName := "aws_sqs_queue.queue" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSQSQueueDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSQSConfigWithDefaults(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueue(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} +func TestAccAWSSQSQueue_tags(t *testing.T) { + var queueAttributes map[string]*string resourceName := "aws_sqs_queue.queue" queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), @@ -130,7 +166,11 @@ func TestAccAWSSQSQueue_tags(t *testing.T) { Config: testAccAWSSQSConfigWithTags(queueName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.Usage", "original"), ), @@ -144,7 +184,11 @@ func TestAccAWSSQSQueue_tags(t *testing.T) { Config: testAccAWSSQSConfigWithTagsChanged(queueName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.Usage", "changed"), ), @@ -153,7 +197,11 @@ func TestAccAWSSQSQueue_tags(t *testing.T) { Config: testAccAWSSQSConfigWithDefaults(queueName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), resource.TestCheckNoResourceAttr(resourceName, "tags"), ), }, @@ -178,6 +226,11 @@ func TestAccAWSSQSQueue_Name_Generated(t *testing.T) { naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { @@ -206,6 +259,11 @@ func TestAccAWSSQSQueue_Name_Generated_FIFOQueue(t *testing.T) { naming.TestCheckResourceAttrNameWithSuffixGenerated(resourceName, "name", tfsqs.FifoQueueNameSuffix), resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { @@ -232,10 +290,14 @@ func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { Config: testAccAWSSQSQueueConfigNamePrefix(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "name_prefix", rName), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { @@ -262,10 +324,14 @@ func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { Config: testAccAWSSQSQueueConfigNamePrefixFIFOQueue(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), naming.TestCheckResourceAttrNameWithSuffixFromPrefix(resourceName, "name", rName, tfsqs.FifoQueueNameSuffix), resource.TestCheckResourceAttr(resourceName, "name_prefix", rName), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { @@ -279,7 +345,7 @@ func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { func TestAccAWSSQSQueue_policy(t *testing.T) { var queueAttributes map[string]*string - + resourceName := "aws_sqs_queue.test-email-events" queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) topicName := fmt.Sprintf("sns-topic-%s", acctest.RandString(10)) @@ -292,12 +358,12 @@ func TestAccAWSSQSQueue_policy(t *testing.T) { { Config: testAccAWSSQSConfig_PolicyFormat(topicName, queueName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSQSQueueExists("aws_sqs_queue.test-email-events", &queueAttributes), + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), testAccCheckAWSSQSQueuePolicyAttribute(&queueAttributes, topicName, queueName), ), }, { - ResourceName: "aws_sqs_queue.test-email-events", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -307,9 +373,9 @@ func TestAccAWSSQSQueue_policy(t *testing.T) { func TestAccAWSSQSQueue_queueDeletedRecently(t *testing.T) { var queueAttributes map[string]*string - resourceName := "aws_sqs_queue.queue" queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), @@ -320,14 +386,22 @@ func TestAccAWSSQSQueue_queueDeletedRecently(t *testing.T) { Config: testAccAWSSQSConfigWithDefaults(queueName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { Config: testAccAWSSQSConfigWithDefaults(queueName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), Taint: []string{resourceName}, }, @@ -337,6 +411,7 @@ func TestAccAWSSQSQueue_queueDeletedRecently(t *testing.T) { func TestAccAWSSQSQueue_redrivePolicy(t *testing.T) { var queueAttributes map[string]*string + resourceName := "aws_sqs_queue.my_dead_letter_queue" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -347,12 +422,16 @@ func TestAccAWSSQSQueue_redrivePolicy(t *testing.T) { { Config: testAccAWSSQSConfigWithRedrive(acctest.RandString(10)), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSQSQueueExists("aws_sqs_queue.my_dead_letter_queue", &queueAttributes), - testAccCheckAWSSQSQueueDefaultAttributes(&queueAttributes), + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { - ResourceName: "aws_sqs_queue.my_dead_letter_queue", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -363,9 +442,10 @@ func TestAccAWSSQSQueue_redrivePolicy(t *testing.T) { // Tests formatting and compacting of Policy, Redrive json func TestAccAWSSQSQueue_Policybasic(t *testing.T) { var queueAttributes map[string]*string - + resourceName := "aws_sqs_queue.test-email-events" queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) topicName := fmt.Sprintf("sns-topic-%s", acctest.RandString(10)) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), @@ -375,12 +455,16 @@ func TestAccAWSSQSQueue_Policybasic(t *testing.T) { { Config: testAccAWSSQSConfig_PolicyFormat(topicName, queueName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSQSQueueExists("aws_sqs_queue.test-email-events", &queueAttributes), - testAccCheckAWSSQSQueueOverrideAttributes(&queueAttributes), + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", "90"), + resource.TestCheckResourceAttr(resourceName, "max_message_size", "2048"), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", "86400"), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", "10"), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", "60"), ), }, { - ResourceName: "aws_sqs_queue.test-email-events", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -390,8 +474,8 @@ func TestAccAWSSQSQueue_Policybasic(t *testing.T) { func TestAccAWSSQSQueue_FIFO(t *testing.T) { var queueAttributes map[string]*string - resourceName := "aws_sqs_queue.queue" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), @@ -431,8 +515,8 @@ func TestAccAWSSQSQueue_FIFOExpectNameError(t *testing.T) { func TestAccAWSSQSQueue_FIFOWithContentBasedDeduplication(t *testing.T) { var queueAttributes map[string]*string - resourceName := "aws_sqs_queue.queue" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), @@ -473,8 +557,8 @@ func TestAccAWSSQSQueue_ExpectContentBasedDeduplicationError(t *testing.T) { func TestAccAWSSQSQueue_Encryption(t *testing.T) { var queueAttributes map[string]*string - resourceName := "aws_sqs_queue.queue" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), @@ -584,66 +668,6 @@ func testAccCheckAWSSQSQueueExists(resourceName string, queueAttributes *map[str } } -func testAccCheckAWSSQSQueueDefaultAttributes(queueAttributes *map[string]*string) resource.TestCheckFunc { - return func(s *terraform.State) error { - // checking if attributes are defaults - for key, valuePointer := range *queueAttributes { - value := aws.StringValue(valuePointer) - if key == "VisibilityTimeout" && value != "30" { - return fmt.Errorf("VisibilityTimeout (%s) was not set to 30", value) - } - - if key == "MessageRetentionPeriod" && value != "345600" { - return fmt.Errorf("MessageRetentionPeriod (%s) was not set to 345600", value) - } - - if key == "MaximumMessageSize" && value != "262144" { - return fmt.Errorf("MaximumMessageSize (%s) was not set to 262144", value) - } - - if key == "DelaySeconds" && value != "0" { - return fmt.Errorf("DelaySeconds (%s) was not set to 0", value) - } - - if key == "ReceiveMessageWaitTimeSeconds" && value != "0" { - return fmt.Errorf("ReceiveMessageWaitTimeSeconds (%s) was not set to 0", value) - } - } - - return nil - } -} - -func testAccCheckAWSSQSQueueOverrideAttributes(queueAttributes *map[string]*string) resource.TestCheckFunc { - return func(s *terraform.State) error { - // checking if attributes match our overrides - for key, valuePointer := range *queueAttributes { - value := aws.StringValue(valuePointer) - if key == "VisibilityTimeout" && value != "60" { - return fmt.Errorf("VisibilityTimeout (%s) was not set to 60", value) - } - - if key == "MessageRetentionPeriod" && value != "86400" { - return fmt.Errorf("MessageRetentionPeriod (%s) was not set to 86400", value) - } - - if key == "MaximumMessageSize" && value != "2048" { - return fmt.Errorf("MaximumMessageSize (%s) was not set to 2048", value) - } - - if key == "DelaySeconds" && value != "90" { - return fmt.Errorf("DelaySeconds (%s) was not set to 90", value) - } - - if key == "ReceiveMessageWaitTimeSeconds" && value != "10" { - return fmt.Errorf("ReceiveMessageWaitTimeSeconds (%s) was not set to 10", value) - } - } - - return nil - } -} - const testAccAWSSQSQueueConfigNameGenerated = ` resource "aws_sqs_queue" "test" {} ` From 289a49212ef627fe4e756d1766cfdd906f7fc37c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 19 Apr 2021 09:06:19 -0400 Subject: [PATCH 0234/1208] Add attrmap package. --- aws/internal/attrmap/attrmap.go | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 aws/internal/attrmap/attrmap.go diff --git a/aws/internal/attrmap/attrmap.go b/aws/internal/attrmap/attrmap.go new file mode 100644 index 000000000000..e587aa967f0a --- /dev/null +++ b/aws/internal/attrmap/attrmap.go @@ -0,0 +1,38 @@ +package attrmap + +import ( + "fmt" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// AttributeMap represents a map of Terraform resource attribute name to AWS API attribute name. +// Useful for SQS Queue or SNS Topic attribute handling. +type AttributeMap map[string]string + +// ResourceDataToApiAttributes returns a map of AWS API attributes from Terraform ResourceData. +func (m AttributeMap) ResourceDataToApiAttributes(d *schema.ResourceData) (map[string]string, error) { + apiAttributes := map[string]string{} + + for tfAttributeName, apiAttributeName := range m { + if v, ok := d.GetOk(tfAttributeName); ok { + var apiAttributeValue string + + switch v := v.(type) { + case int: + apiAttributeValue = strconv.Itoa(v) + case bool: + apiAttributeValue = strconv.FormatBool(v) + case string: + apiAttributeValue = v + default: + return nil, fmt.Errorf("attribute %s is of unsupported type: %T", tfAttributeName, v) + } + + apiAttributes[apiAttributeName] = apiAttributeValue + } + } + + return apiAttributes, nil +} From 213f692d8a695681bdb47f489ed02c5e12bf21a0 Mon Sep 17 00:00:00 2001 From: Roberth Kulbin Date: Wed, 2 Jun 2021 17:13:23 +0100 Subject: [PATCH 0235/1208] r/aws_sqs_queue: add deduplication_scope, fifo_throughput_limit attributes --- .changelog/19639.txt | 3 + aws/resource_aws_sqs_queue.go | 28 ++++++++ aws/resource_aws_sqs_queue_test.go | 89 ++++++++++++++++++++++++++ website/docs/r/sqs_queue.html.markdown | 13 ++++ 4 files changed, 133 insertions(+) create mode 100644 .changelog/19639.txt diff --git a/.changelog/19639.txt b/.changelog/19639.txt new file mode 100644 index 000000000000..91679dea7d09 --- /dev/null +++ b/.changelog/19639.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_sqs_queue: Add `deduplication_scope` and `fifo_throughput_limit` arguments +``` diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index 44026dc5192a..a54f90cfa50d 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -37,6 +37,8 @@ var sqsQueueAttributeMap = map[string]string{ "content_based_deduplication": sqs.QueueAttributeNameContentBasedDeduplication, "kms_master_key_id": sqs.QueueAttributeNameKmsMasterKeyId, "kms_data_key_reuse_period_seconds": sqs.QueueAttributeNameKmsDataKeyReusePeriodSeconds, + "deduplication_scope": sqs.QueueAttributeNameDeduplicationScope, + "fifo_throughput_limit": sqs.QueueAttributeNameFifoThroughputLimit, } // A number of these are marked as computed because if you don't @@ -136,6 +138,22 @@ func resourceAwsSqsQueue() *schema.Resource { Computed: true, Optional: true, }, + "deduplication_scope": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice( + []string{"messageGroup", "queue"}, + false), + }, + "fifo_throughput_limit": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice( + []string{"perQueue", "perMessageGroupId"}, + false), + }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), }, @@ -306,6 +324,8 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { d.Set("receive_wait_time_seconds", tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds) d.Set("redrive_policy", "") d.Set("visibility_timeout_seconds", tfsqs.DefaultQueueVisibilityTimeout) + d.Set("deduplication_scope", "") + d.Set("fifo_throughput_limit", "") if attributeOutput != nil { queueAttributes := aws.StringValueMap(attributeOutput.Attributes) @@ -405,6 +425,14 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { d.Set("visibility_timeout_seconds", vInt) } + + if v, ok := queueAttributes[sqs.QueueAttributeNameDeduplicationScope]; ok && v != "" { + d.Set("deduplication_scope", v) + } + + if v, ok := queueAttributes[sqs.QueueAttributeNameFifoThroughputLimit]; ok && v != "" { + d.Set("fifo_throughput_limit", v) + } } d.Set("fifo_queue", fifoQueue) diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index bdc118db8573..402f535b721f 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -95,6 +95,9 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), + // These two should only be set for FIFO queues. + resource.TestCheckResourceAttr(resourceName, "deduplication_scope", ""), + resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), ), }, { @@ -487,6 +490,8 @@ func TestAccAWSSQSQueue_FIFO(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), + resource.TestCheckResourceAttr(resourceName, "deduplication_scope", "queue"), + resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", "perQueue"), ), }, { @@ -540,6 +545,51 @@ func TestAccAWSSQSQueue_FIFOWithContentBasedDeduplication(t *testing.T) { }) } +func TestAccAWSSQSQueue_FIFOWithHighThroughputMode(t *testing.T) { + var queueAttributes map[string]*string + + resourceName := "aws_sqs_queue.queue" + queueName := acctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSQSQueueDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSQSConfigWithFIFOHighThroughputMode1(queueName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), + resource.TestCheckResourceAttr(resourceName, "deduplication_scope", "queue"), + resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", "perQueue"), + testAccCheckAWSSQSFIFOQueueHighThroughputAttributes(&queueAttributes, "queue", "perQueue"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSQSConfigWithFIFOHighThroughputMode2(queueName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + resource.TestCheckResourceAttr(resourceName, "deduplication_scope", "messageGroup"), + resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", "perMessageGroupId"), + testAccCheckAWSSQSFIFOQueueHighThroughputAttributes(&queueAttributes, "messageGroup", "perMessageGroupId"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSSQSQueue_ExpectContentBasedDeduplicationError(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -668,6 +718,25 @@ func testAccCheckAWSSQSQueueExists(resourceName string, queueAttributes *map[str } } +func testAccCheckAWSSQSFIFOQueueHighThroughputAttributes(queueAttributes *map[string]*string, deduplicationScope, fifoThroughputLimit string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // checking if attributes are defaults + for key, valuePointer := range *queueAttributes { + value := aws.StringValue(valuePointer) + + if key == "DeduplicationScope" && value != deduplicationScope { + return fmt.Errorf("DeduplicationScope (%s) was not set to %s", value, deduplicationScope) + } + + if key == "FifoThroughputLimit" && value != fifoThroughputLimit { + return fmt.Errorf("FifoThroughputLimit (%s) was not set to %s", value, fifoThroughputLimit) + } + } + + return nil + } +} + const testAccAWSSQSQueueConfigNameGenerated = ` resource "aws_sqs_queue" "test" {} ` @@ -815,6 +884,26 @@ resource "aws_sqs_queue" "queue" { `, queue) } +func testAccAWSSQSConfigWithFIFOHighThroughputMode1(queue string) string { + return fmt.Sprintf(` +resource "aws_sqs_queue" "queue" { + name = "%s.fifo" + fifo_queue = true +} +`, queue) +} + +func testAccAWSSQSConfigWithFIFOHighThroughputMode2(queue string) string { + return fmt.Sprintf(` +resource "aws_sqs_queue" "queue" { + name = "%s.fifo" + fifo_queue = true + deduplication_scope = "messageGroup" + fifo_throughput_limit = "perMessageGroupId" +} +`, queue) +} + func testAccAWSSQSConfigWithFIFOExpectError(queue string) string { return fmt.Sprintf(` resource "aws_sqs_queue" "queue" { diff --git a/website/docs/r/sqs_queue.html.markdown b/website/docs/r/sqs_queue.html.markdown index a4a2bfe4f9e6..5e2fc90b0393 100644 --- a/website/docs/r/sqs_queue.html.markdown +++ b/website/docs/r/sqs_queue.html.markdown @@ -38,6 +38,17 @@ resource "aws_sqs_queue" "terraform_queue" { } ``` +## High-throughput FIFO queue + +```terraform +resource "aws_sqs_queue" "terraform_queue" { + name = "terraform-example-queue.fifo" + fifo_queue = true + deduplication_scope = "messageGroup" + fifo_throughput_limit = "perMessageGroupId" +} +``` + ## Server-side encryption (SSE) ```terraform @@ -65,6 +76,8 @@ The following arguments are supported: * `content_based_deduplication` - (Optional) Enables content-based deduplication for FIFO queues. For more information, see the [related documentation](http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-exactly-once-processing) * `kms_master_key_id` - (Optional) The ID of an AWS-managed customer master key (CMK) for Amazon SQS or a custom CMK. For more information, see [Key Terms](http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-sse-key-terms). * `kms_data_key_reuse_period_seconds` - (Optional) The length of time, in seconds, for which Amazon SQS can reuse a data key to encrypt or decrypt messages before calling AWS KMS again. An integer representing seconds, between 60 seconds (1 minute) and 86,400 seconds (24 hours). The default is 300 (5 minutes). +* `deduplication_scope` - (Optional) Specifies whether message deduplication occurs at the message group or queue level. Valid values are `messageGroup` and `queue` (default). +* `fifo_throughput_limit` - (Optional) Specifies whether the FIFO queue throughput quota applies to the entire queue or per message group. Valid values are `perQueue` (default) and `perMessageGroupId`. * `tags` - (Optional) A map of tags to assign to the queue. 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 From f8dc547450a7b2bd1af42b98b5a617f276b5bf34 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 4 Jun 2021 10:53:32 -0400 Subject: [PATCH 0236/1208] Add deduplication_scope and fifo_throughput_limit values to internal consts. --- aws/internal/service/sqs/consts.go | 24 ++++++++++++++++++++++++ aws/resource_aws_sqs_queue.go | 20 ++++++++------------ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/aws/internal/service/sqs/consts.go b/aws/internal/service/sqs/consts.go index 61adf57fb417..0c70773e947c 100644 --- a/aws/internal/service/sqs/consts.go +++ b/aws/internal/service/sqs/consts.go @@ -11,3 +11,27 @@ const ( DefaultQueueReceiveMessageWaitTimeSeconds = 0 DefaultQueueVisibilityTimeout = 30 ) + +const ( + DeduplicationScopeMessageGroup = "messageGroup" + DeduplicationScopeQueue = "queue" +) + +func DeduplicationScope_Values() []string { + return []string{ + DeduplicationScopeMessageGroup, + DeduplicationScopeQueue, + } +} + +const ( + FifoThroughputLimitPerMessageGroupId = "perMessageGroupId" + FifoThroughputLimitPerQueue = "perQueue" +) + +func FifoThroughputLimit_Values() []string { + return []string{ + FifoThroughputLimitPerMessageGroupId, + FifoThroughputLimitPerQueue, + } +} diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index a54f90cfa50d..a91e3c34958e 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -139,20 +139,16 @@ func resourceAwsSqsQueue() *schema.Resource { Optional: true, }, "deduplication_scope": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice( - []string{"messageGroup", "queue"}, - false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(tfsqs.DeduplicationScope_Values(), false), }, "fifo_throughput_limit": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice( - []string{"perQueue", "perMessageGroupId"}, - false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(tfsqs.FifoThroughputLimit_Values(), false), }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), From b78870110a21ad408cb158d3e8e66caf2d80b81e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 4 Jun 2021 11:08:32 -0400 Subject: [PATCH 0237/1208] r/aws_sqs_queue: Use paginated ListQueues in test sweeper. --- aws/resource_aws_sqs_queue.go | 12 +++++++- aws/resource_aws_sqs_queue_test.go | 48 ++++++++++++++++-------------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index a91e3c34958e..86af38416168 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -14,6 +14,7 @@ import ( "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/service/sqs" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -467,10 +468,19 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsSqsQueueDelete(d *schema.ResourceData, meta interface{}) error { sqsconn := meta.(*AWSClient).sqsconn - log.Printf("[DEBUG] SQS Delete Queue: %s", d.Id()) + log.Printf("[DEBUG] Deleting SQS Queue: %s", d.Id()) _, err := sqsconn.DeleteQueue(&sqs.DeleteQueueInput{ QueueUrl: aws.String(d.Id()), }) + + if tfawserr.ErrCodeEquals(err, sqs.ErrCodeQueueDoesNotExist) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting SQS Queue (%s): %w", d.Id(), err) + } + return err } diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index 402f535b721f..f586c07e8e22 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -44,32 +44,34 @@ func testSweepSqsQueues(region string) error { input := &sqs.ListQueuesInput{} var sweeperErrs *multierror.Error - output, err := conn.ListQueues(input) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping SQS Queues sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() - } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving SQS Queues: %w", err)) - return sweeperErrs - } + err = conn.ListQueuesPages(input, func(page *sqs.ListQueuesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } - for _, queueUrl := range output.QueueUrls { - url := aws.StringValue(queueUrl) + for _, queueUrl := range page.QueueUrls { + r := resourceAwsSqsQueue() + d := r.Data(nil) + d.SetId(aws.StringValue(queueUrl)) + err = r.Delete(d, client) - log.Printf("[INFO] Deleting SQS Queue: %s", url) - _, err := conn.DeleteQueue(&sqs.DeleteQueueInput{ - QueueUrl: aws.String(url), - }) - if isAWSErr(err, sqs.ErrCodeQueueDoesNotExist, "") { - continue - } - if err != nil { - sweeperErr := fmt.Errorf("error deleting SQS Queue (%s): %w", url, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue + if err != nil { + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) + continue + } } + + return !lastPage + }) + + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping SQS Queue sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + } + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing SQS Queues: %w", err)) } return sweeperErrs.ErrorOrNil() From 1cfff5efcba9e2ac909065198ca1233b03a9374d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 4 Jun 2021 11:26:23 -0400 Subject: [PATCH 0238/1208] r/aws_sqs_queue: Add internal finder package. --- aws/internal/service/sqs/finder/finder.go | 37 ++++++++++++ aws/resource_aws_sqs_queue_test.go | 69 ++++++++++------------- 2 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 aws/internal/service/sqs/finder/finder.go diff --git a/aws/internal/service/sqs/finder/finder.go b/aws/internal/service/sqs/finder/finder.go new file mode 100644 index 000000000000..6b813258d2e1 --- /dev/null +++ b/aws/internal/service/sqs/finder/finder.go @@ -0,0 +1,37 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/sqs" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func QueueAttributesByURL(conn *sqs.SQS, url string) (map[string]*string, error) { + input := &sqs.GetQueueAttributesInput{ + AttributeNames: aws.StringSlice([]string{sqs.QueueAttributeNameAll}), + QueueUrl: aws.String(url), + } + + output, err := conn.GetQueueAttributes(input) + + if tfawserr.ErrCodeEquals(err, sqs.ErrCodeQueueDoesNotExist) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Attributes == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.Attributes, nil +} diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index f586c07e8e22..6ed6dffbafb8 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -6,7 +6,6 @@ import ( "regexp" "strconv" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/sqs" @@ -17,6 +16,8 @@ import ( awspolicy "github.com/jen20/awspolicyequivalence" "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" tfsqs "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -633,36 +634,6 @@ func TestAccAWSSQSQueue_Encryption(t *testing.T) { }) } -func testAccCheckAWSSQSQueueDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).sqsconn - - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_sqs_queue" { - continue - } - - // Check if queue exists by checking for its attributes - params := &sqs.GetQueueAttributesInput{ - QueueUrl: aws.String(rs.Primary.ID), - } - err := resource.Retry(15*time.Second, func() *resource.RetryError { - _, err := conn.GetQueueAttributes(params) - if err != nil { - if isAWSErr(err, sqs.ErrCodeQueueDoesNotExist, "") { - return nil - } - return resource.NonRetryableError(err) - } - return resource.RetryableError(fmt.Errorf("Queue %s still exists. Failing!", rs.Primary.ID)) - }) - if err != nil { - return err - } - } - - return nil -} - func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]*string, topicName, queueName string) resource.TestCheckFunc { return func(s *terraform.State) error { accountID := testAccProvider.Meta().(*AWSClient).accountid @@ -691,7 +662,7 @@ func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]*string, } } -func testAccCheckAWSSQSQueueExists(resourceName string, queueAttributes *map[string]*string) resource.TestCheckFunc { +func testAccCheckAWSSQSQueueExists(resourceName string, v *map[string]*string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -699,27 +670,47 @@ func testAccCheckAWSSQSQueueExists(resourceName string, queueAttributes *map[str } if rs.Primary.ID == "" { - return fmt.Errorf("No Queue URL specified!") + return fmt.Errorf("No SQS Queue URL is set") } conn := testAccProvider.Meta().(*AWSClient).sqsconn - input := &sqs.GetQueueAttributesInput{ - QueueUrl: aws.String(rs.Primary.ID), - AttributeNames: []*string{aws.String("All")}, - } - output, err := conn.GetQueueAttributes(input) + output, err := finder.QueueAttributesByURL(conn, rs.Primary.ID) if err != nil { return err } - *queueAttributes = output.Attributes + *v = output return nil } } +func testAccCheckAWSSQSQueueDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).sqsconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_sqs_queue" { + continue + } + + _, err := finder.QueueAttributesByURL(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("SQS Queue %s still exists", rs.Primary.ID) + } + + return nil +} + func testAccCheckAWSSQSFIFOQueueHighThroughputAttributes(queueAttributes *map[string]*string, deduplicationScope, fifoThroughputLimit string) resource.TestCheckFunc { return func(s *terraform.State) error { // checking if attributes are defaults From 12a417aef74c5b23cb84acd77ce1e0830756c120 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 4 Jun 2021 09:17:28 -0700 Subject: [PATCH 0239/1208] Makes global replication group disassociation concurrent and reduces timeouts --- .../service/elasticache/waiter/waiter.go | 5 +- ...ws_elasticache_global_replication_group.go | 9 ++- ...asticache_global_replication_group_test.go | 81 +++++++++++++------ ...ource_aws_elasticache_replication_group.go | 18 ++++- 4 files changed, 80 insertions(+), 33 deletions(-) diff --git a/aws/internal/service/elasticache/waiter/waiter.go b/aws/internal/service/elasticache/waiter/waiter.go index 4012e5c77d89..d0af31d8afc7 100644 --- a/aws/internal/service/elasticache/waiter/waiter.go +++ b/aws/internal/service/elasticache/waiter/waiter.go @@ -201,8 +201,11 @@ func GlobalReplicationGroupDeleted(conn *elasticache.ElastiCache, globalReplicat } const ( - GlobalReplicationGroupDisassociationRetryTimeout = 45 * time.Minute + // GlobalReplicationGroupDisassociationReadyTimeout specifies how long to wait for a global replication group + // to be in a valid state before disassociating + GlobalReplicationGroupDisassociationReadyTimeout = 45 * time.Minute + // globalReplicationGroupDisassociationTimeout specifies how long to wait for the actual disassociation globalReplicationGroupDisassociationTimeout = 20 * time.Minute globalReplicationGroupDisassociationMinTimeout = 10 * time.Second diff --git a/aws/resource_aws_elasticache_global_replication_group.go b/aws/resource_aws_elasticache_global_replication_group.go index 6ee1d1350094..d46e5d46c61c 100644 --- a/aws/resource_aws_elasticache_global_replication_group.go +++ b/aws/resource_aws_elasticache_global_replication_group.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/elasticache" @@ -255,7 +256,8 @@ func updateElasticacheGlobalReplicationGroup(conn *elasticache.ElastiCache, id s func resourceAwsElasticacheGlobalReplicationGroupDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).elasticacheconn - err := deleteElasticacheGlobalReplicationGroup(conn, d.Id()) + // Using Update timeout because the Global Replication Group could be in the middle of an update operation + err := deleteElasticacheGlobalReplicationGroup(conn, d.Id(), waiter.GlobalReplicationGroupDefaultUpdatedTimeout) if err != nil { return fmt.Errorf("error deleting ElastiCache Global Replication Group: %w", err) } @@ -263,14 +265,13 @@ func resourceAwsElasticacheGlobalReplicationGroupDelete(d *schema.ResourceData, return nil } -func deleteElasticacheGlobalReplicationGroup(conn *elasticache.ElastiCache, id string) error { +func deleteElasticacheGlobalReplicationGroup(conn *elasticache.ElastiCache, id string, readyTimeout time.Duration) error { input := &elasticache.DeleteGlobalReplicationGroupInput{ GlobalReplicationGroupId: aws.String(id), RetainPrimaryReplicationGroup: aws.Bool(true), } - // Using Update timeout because the Global Replication Group could be in the middle of an update operation - err := resource.Retry(waiter.GlobalReplicationGroupDefaultUpdatedTimeout, func() *resource.RetryError { + err := resource.Retry(readyTimeout, func() *resource.RetryError { _, err := conn.DeleteGlobalReplicationGroup(input) if tfawserr.ErrCodeEquals(err, elasticache.ErrCodeGlobalReplicationGroupNotFoundFault) { return resource.NonRetryableError(&resource.NotFoundError{ diff --git a/aws/resource_aws_elasticache_global_replication_group_test.go b/aws/resource_aws_elasticache_global_replication_group_test.go index 9c1e649029bb..12836f6667c3 100644 --- a/aws/resource_aws_elasticache_global_replication_group_test.go +++ b/aws/resource_aws_elasticache_global_replication_group_test.go @@ -5,6 +5,7 @@ import ( "log" "regexp" "testing" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/elasticache" @@ -26,6 +27,12 @@ func init() { }) } +// These timeouts are lower to fail faster during sweepers +const ( + sweeperGlobalReplicationGroupDisassociationReadyTimeout = 10 * time.Minute + sweeperGlobalReplicationGroupDefaultUpdatedTimeout = 10 * time.Minute +) + func testSweepElasticacheGlobalReplicationGroups(region string) error { client, err := sharedClientForRegion(region) if err != nil { @@ -33,7 +40,7 @@ func testSweepElasticacheGlobalReplicationGroups(region string) error { } conn := client.(*AWSClient).elasticacheconn - var sweeperErrs *multierror.Error + var grgGroup multierror.Group input := &elasticache.DescribeGlobalReplicationGroupsInput{ ShowMemberInfo: aws.Bool(true), @@ -44,46 +51,72 @@ func testSweepElasticacheGlobalReplicationGroups(region string) error { } for _, globalReplicationGroup := range page.GlobalReplicationGroups { - id := aws.StringValue(globalReplicationGroup.GlobalReplicationGroupId) + globalReplicationGroup := globalReplicationGroup - for _, member := range globalReplicationGroup.Members { - if aws.StringValue(member.Role) == GlobalReplicationGroupMemberRolePrimary { - continue - } + grgGroup.Go(func() error { + id := aws.StringValue(globalReplicationGroup.GlobalReplicationGroupId) - if err := disassociateElasticacheReplicationGroup(conn, id, aws.StringValue(member.ReplicationGroupId), aws.StringValue(member.ReplicationGroupRegion)); err != nil { - sweeperErr := fmt.Errorf( - "error disassociating ElastiCache Replication Group (%s) in %s from Global Group (%s): %w", - aws.StringValue(member.ReplicationGroupId), aws.StringValue(member.ReplicationGroupRegion), id, err, - ) + disassociationErrors := disassociateMembers(conn, globalReplicationGroup) + if disassociationErrors != nil { + sweeperErr := fmt.Errorf("failed to disassociate ElastiCache Global Replication Group (%s) members: %w", id, disassociationErrors) log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + return sweeperErr } - } - log.Printf("[INFO] Deleting ElastiCache Global Replication Group: %s", id) - err := deleteElasticacheGlobalReplicationGroup(conn, id) - if err != nil { - sweeperErr := fmt.Errorf("error deleting ElastiCache Global Replication Group (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + log.Printf("[INFO] Deleting ElastiCache Global Replication Group: %s", id) + err := deleteElasticacheGlobalReplicationGroup(conn, id, sweeperGlobalReplicationGroupDefaultUpdatedTimeout) + if err != nil { + sweeperErr := fmt.Errorf("error deleting ElastiCache Global Replication Group (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } + return nil + }) } return !lastPage }) + grgErrs := grgGroup.Wait() + if testSweepSkipSweepError(err) { log.Printf("[WARN] Skipping ElastiCache Global Replication Group sweep for %q: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + return grgErrs.ErrorOrNil() // In case we have completed some pages, but had errors } if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing ElastiCache Global Replication Groups: %w", err)) + grgErrs = multierror.Append(grgErrs, fmt.Errorf("error listing ElastiCache Global Replication Groups: %w", err)) + } + + return grgErrs.ErrorOrNil() +} + +func disassociateMembers(conn *elasticache.ElastiCache, globalReplicationGroup *elasticache.GlobalReplicationGroup) error { + var membersGroup multierror.Group + + for _, member := range globalReplicationGroup.Members { + member := member + + if aws.StringValue(member.Role) == GlobalReplicationGroupMemberRolePrimary { + continue + } + + id := aws.StringValue(globalReplicationGroup.GlobalReplicationGroupId) + + membersGroup.Go(func() error { + if err := disassociateElasticacheReplicationGroup(conn, id, aws.StringValue(member.ReplicationGroupId), aws.StringValue(member.ReplicationGroupRegion), sweeperGlobalReplicationGroupDisassociationReadyTimeout); err != nil { + sweeperErr := fmt.Errorf( + "error disassociating ElastiCache Replication Group (%s) in %s from Global Group (%s): %w", + aws.StringValue(member.ReplicationGroupId), aws.StringValue(member.ReplicationGroupRegion), id, err, + ) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } + return nil + }) } - return sweeperErrs.ErrorOrNil() + return membersGroup.Wait().ErrorOrNil() } func TestAccAWSElasticacheGlobalReplicationGroup_basic(t *testing.T) { diff --git a/aws/resource_aws_elasticache_replication_group.go b/aws/resource_aws_elasticache_replication_group.go index d4a8f0b4f9ad..ebcade4f5410 100644 --- a/aws/resource_aws_elasticache_replication_group.go +++ b/aws/resource_aws_elasticache_replication_group.go @@ -436,6 +436,16 @@ func resourceAwsElasticacheReplicationGroupCreate(d *schema.ResourceData, meta i return fmt.Errorf("error creating ElastiCache Replication Group (%s): waiting for completion: %w", d.Id(), err) } + if v, ok := d.GetOk("global_replication_group_id"); ok { + // When adding a replication group to a global replication group, the replication group can be in the "available" + // state, but the global replication group can still be in the "modifying" state. Wait for the replication group + // to be fully added to the global replication group. + // API calls to the global replication group can be made in any region. + if _, err := waiter.GlobalReplicationGroupAvailable(conn, v.(string), waiter.GlobalReplicationGroupDefaultCreatedTimeout); err != nil { + return fmt.Errorf("error waiting for ElastiCache Global Replication Group (%s) availability: %w", v, err) + } + } + return resourceAwsElasticacheReplicationGroupRead(d, meta) } @@ -703,7 +713,7 @@ func resourceAwsElasticacheReplicationGroupDelete(d *schema.ResourceData, meta i conn := meta.(*AWSClient).elasticacheconn if globalReplicationGroupID, ok := d.GetOk("global_replication_group_id"); ok { - err := disassociateElasticacheReplicationGroup(conn, globalReplicationGroupID.(string), d.Id(), meta.(*AWSClient).region) + err := disassociateElasticacheReplicationGroup(conn, globalReplicationGroupID.(string), d.Id(), meta.(*AWSClient).region, waiter.GlobalReplicationGroupDisassociationReadyTimeout) if err != nil { return fmt.Errorf("error disassociating ElastiCache Replication Group (%s) from Global Replication Group (%s): %w", d.Id(), globalReplicationGroupID, err) } @@ -718,13 +728,13 @@ func resourceAwsElasticacheReplicationGroupDelete(d *schema.ResourceData, meta i return nil } -func disassociateElasticacheReplicationGroup(conn *elasticache.ElastiCache, globalReplicationGroupID, id, region string) error { +func disassociateElasticacheReplicationGroup(conn *elasticache.ElastiCache, globalReplicationGroupID, id, region string, readyTimeout time.Duration) error { input := &elasticache.DisassociateGlobalReplicationGroupInput{ GlobalReplicationGroupId: aws.String(globalReplicationGroupID), ReplicationGroupId: aws.String(id), ReplicationGroupRegion: aws.String(region), } - err := resource.Retry(waiter.GlobalReplicationGroupDisassociationRetryTimeout, func() *resource.RetryError { + err := resource.Retry(readyTimeout, func() *resource.RetryError { _, err := conn.DisassociateGlobalReplicationGroup(input) if tfawserr.ErrCodeEquals(err, elasticache.ErrCodeGlobalReplicationGroupNotFoundFault) { return nil @@ -745,7 +755,7 @@ func disassociateElasticacheReplicationGroup(conn *elasticache.ElastiCache, glob return nil } if tfawserr.ErrCodeEquals(err, elasticache.ErrCodeInvalidGlobalReplicationGroupStateFault) { - return fmt.Errorf("tried for %s: %w", waiter.GlobalReplicationGroupDisassociationRetryTimeout.String(), err) + return fmt.Errorf("tried for %s: %w", readyTimeout.String(), err) } if err != nil { From 310518b625cc23ffa85112760a39a4f787f2a7d1 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 19:23:34 +0300 Subject: [PATCH 0240/1208] add fsx win fs support --- aws/resource_aws_ecs_task_definition.go | 541 +++++++++++++++---- aws/resource_aws_ecs_task_definition_test.go | 75 +++ aws/structure.go | 188 ------- 3 files changed, 508 insertions(+), 296 deletions(-) diff --git a/aws/resource_aws_ecs_task_definition.go b/aws/resource_aws_ecs_task_definition.go index df7e4f049674..ec4d438c90fb 100644 --- a/aws/resource_aws_ecs_task_definition.go +++ b/aws/resource_aws_ecs_task_definition.go @@ -61,9 +61,10 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { }, "family": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, "revision": { @@ -115,16 +116,11 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { }, "network_mode": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.NetworkModeBridge, - ecs.NetworkModeHost, - ecs.NetworkModeAwsvpc, - ecs.NetworkModeNone, - }, false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ecs.NetworkMode_Values(), false), }, "volume": { @@ -153,14 +149,11 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "scope": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.ScopeShared, - ecs.ScopeTask, - }, false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ecs.Scope_Values(), false), }, "autoprovision": { Type: schema.TypeBool, @@ -207,13 +200,10 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { Default: "/", }, "transit_encryption": { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.EFSTransitEncryptionEnabled, - ecs.EFSTransitEncryptionDisabled, - }, false), + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: validation.StringInSlice(ecs.EFSTransitEncryption_Values(), false), }, "transit_encryption_port": { Type: schema.TypeInt, @@ -234,13 +224,51 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { Optional: true, }, "iam": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: validation.StringInSlice(ecs.EFSAuthorizationConfigIAM_Values(), false), + }, + }, + }, + }, + }, + }, + }, + "fsx_windows_file_server_volume_configuration": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "file_system_id": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + "root_directory": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + "authorization_config": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credentials_parameter": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + ValidateFunc: validateArn, + }, + "domain": { Type: schema.TypeString, ForceNew: true, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.EFSAuthorizationConfigIAMEnabled, - ecs.EFSAuthorizationConfigIAMDisabled, - }, false), + Required: true, }, }, }, @@ -261,12 +289,10 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "type": { - Type: schema.TypeString, - ForceNew: true, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.TaskDefinitionPlacementConstraintTypeMemberOf, - }, false), + Type: schema.TypeString, + ForceNew: true, + Required: true, + ValidateFunc: validation.StringInSlice(ecs.TaskDefinitionPlacementConstraintType_Values(), false), }, "expression": { Type: schema.TypeString, @@ -281,28 +307,28 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { Type: schema.TypeSet, Optional: true, ForceNew: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + "EC2", + "FARGATE", + "EXTERNAL", + }, false), + }, }, "ipc_mode": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.IpcModeHost, - ecs.IpcModeNone, - ecs.IpcModeTask, - }, false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ecs.IpcMode_Values(), false), }, "pid_mode": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.PidModeHost, - ecs.PidModeTask, - }, false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ecs.PidMode_Values(), false), }, "proxy_configuration": { @@ -324,13 +350,11 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { ForceNew: true, }, "type": { - Type: schema.TypeString, - Default: ecs.ProxyConfigurationTypeAppmesh, - Optional: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.ProxyConfigurationTypeAppmesh, - }, false), + Type: schema.TypeString, + Default: ecs.ProxyConfigurationTypeAppmesh, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ecs.ProxyConfigurationType_Values(), false), }, }, }, @@ -430,20 +454,11 @@ func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{} constraints := d.Get("placement_constraints").(*schema.Set).List() if len(constraints) > 0 { - var pc []*ecs.TaskDefinitionPlacementConstraint - for _, raw := range constraints { - p := raw.(map[string]interface{}) - t := p["type"].(string) - e := p["expression"].(string) - if err := validateAwsEcsPlacementConstraint(t, e); err != nil { - return err - } - pc = append(pc, &ecs.TaskDefinitionPlacementConstraint{ - Type: aws.String(t), - Expression: aws.String(e), - }) + cons, err := expandEcsTaskDefinitionPlacementConstraints(constraints) + if err != nil { + return err } - input.PlacementConstraints = pc + input.PlacementConstraints = cons } if v, ok := d.GetOk("requires_compatibilities"); ok && v.(*schema.Set).Len() > 0 { @@ -452,30 +467,7 @@ func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{} proxyConfigs := d.Get("proxy_configuration").([]interface{}) if len(proxyConfigs) > 0 { - proxyConfig := proxyConfigs[0] - configMap := proxyConfig.(map[string]interface{}) - - containerName := configMap["container_name"].(string) - proxyType := configMap["type"].(string) - - rawProperties := configMap["properties"].(map[string]interface{}) - - properties := make([]*ecs.KeyValuePair, len(rawProperties)) - i := 0 - for name, value := range rawProperties { - properties[i] = &ecs.KeyValuePair{ - Name: aws.String(name), - Value: aws.String(value.(string)), - } - i++ - } - - var ecsProxyConfig ecs.ProxyConfiguration - ecsProxyConfig.ContainerName = aws.String(containerName) - ecsProxyConfig.Type = aws.String(proxyType) - ecsProxyConfig.Properties = properties - - input.ProxyConfiguration = &ecsProxyConfig + input.ProxyConfiguration = expandEcsTaskDefinitionProxyConfiguration(proxyConfigs) } log.Printf("[DEBUG] Registering ECS task definition: %s", input) @@ -558,23 +550,23 @@ func resourceAwsEcsTaskDefinitionRead(d *schema.ResourceData, meta interface{}) } if err := d.Set("volume", flattenEcsVolumes(taskDefinition.Volumes)); err != nil { - return fmt.Errorf("error setting volume: %s", err) + return fmt.Errorf("error setting volume: %w", err) } if err := d.Set("inference_accelerator", flattenEcsInferenceAccelerators(taskDefinition.InferenceAccelerators)); err != nil { - return fmt.Errorf("error setting inference accelerators: %s", err) + return fmt.Errorf("error setting inference accelerators: %w", err) } if err := d.Set("placement_constraints", flattenPlacementConstraints(taskDefinition.PlacementConstraints)); err != nil { - log.Printf("[ERR] Error setting placement_constraints for (%s): %s", d.Id(), err) + return fmt.Errorf("error setting placement_constraints: %w", err) } if err := d.Set("requires_compatibilities", flattenStringList(taskDefinition.RequiresCompatibilities)); err != nil { - return fmt.Errorf("error setting requires_compatibilities: %s", err) + return fmt.Errorf("error setting requires_compatibilities: %w", err) } if err := d.Set("proxy_configuration", flattenProxyConfiguration(taskDefinition.ProxyConfiguration)); err != nil { - return fmt.Errorf("error setting proxy_configuration: %s", err) + return fmt.Errorf("error setting proxy_configuration: %w", err) } return nil @@ -587,8 +579,8 @@ func flattenPlacementConstraints(pcs []*ecs.TaskDefinitionPlacementConstraint) [ results := make([]map[string]interface{}, 0) for _, pc := range pcs { c := make(map[string]interface{}) - c["type"] = *pc.Type - c["expression"] = *pc.Expression + c["type"] = aws.StringValue(pc.Type) + c["expression"] = aws.StringValue(pc.Expression) results = append(results, c) } return results @@ -677,7 +669,28 @@ func resourceAwsEcsTaskDefinitionVolumeHash(v interface{}) int { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } } + } + if v, ok := m["fsx_windows_file_server_volume_configuration"]; ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + m := v.([]interface{})[0].(map[string]interface{}) + + if v, ok := m["file_system_id"]; ok && v.(string) != "" { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + + if v, ok := m["root_directory"]; ok && v.(string) != "" { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + + if v, ok := m["authorization_config"]; ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + m := v.([]interface{})[0].(map[string]interface{}) + if v, ok := m["credentials_parameter"]; ok && v.(string) != "" { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + if v, ok := m["domain"]; ok && v.(string) != "" { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } } return hashcode.String(buf.String()) @@ -687,8 +700,8 @@ func flattenEcsInferenceAccelerators(list []*ecs.InferenceAccelerator) []map[str result := make([]map[string]interface{}, 0, len(list)) for _, iAcc := range list { l := map[string]interface{}{ - "device_name": *iAcc.DeviceName, - "device_type": *iAcc.DeviceType, + "device_name": aws.StringValue(iAcc.DeviceName), + "device_type": aws.StringValue(iAcc.DeviceType), } result = append(result, l) @@ -709,3 +722,315 @@ func expandEcsInferenceAccelerators(configured []interface{}) []*ecs.InferenceAc return iAccs } + +func expandEcsTaskDefinitionPlacementConstraints(constraints []interface{}) ([]*ecs.TaskDefinitionPlacementConstraint, error) { + var pc []*ecs.TaskDefinitionPlacementConstraint + for _, raw := range constraints { + p := raw.(map[string]interface{}) + t := p["type"].(string) + e := p["expression"].(string) + if err := validateAwsEcsPlacementConstraint(t, e); err != nil { + return nil, err + } + pc = append(pc, &ecs.TaskDefinitionPlacementConstraint{ + Type: aws.String(t), + Expression: aws.String(e), + }) + } + + return pc, nil +} + +func expandEcsTaskDefinitionProxyConfiguration(proxyConfigs []interface{}) *ecs.ProxyConfiguration { + proxyConfig := proxyConfigs[0] + configMap := proxyConfig.(map[string]interface{}) + + rawProperties := configMap["properties"].(map[string]interface{}) + + properties := make([]*ecs.KeyValuePair, len(rawProperties)) + i := 0 + for name, value := range rawProperties { + properties[i] = &ecs.KeyValuePair{ + Name: aws.String(name), + Value: aws.String(value.(string)), + } + i++ + } + + ecsProxyConfig := &ecs.ProxyConfiguration{ + ContainerName: aws.String(configMap["container_name"].(string)), + Type: aws.String(configMap["type"].(string)), + Properties: properties, + } + + return ecsProxyConfig +} + +func expandEcsVolumes(configured []interface{}) []*ecs.Volume { + volumes := make([]*ecs.Volume, 0, len(configured)) + + // Loop over our configured volumes and create + // an array of aws-sdk-go compatible objects + for _, lRaw := range configured { + data := lRaw.(map[string]interface{}) + + l := &ecs.Volume{ + Name: aws.String(data["name"].(string)), + } + + hostPath := data["host_path"].(string) + if hostPath != "" { + l.Host = &ecs.HostVolumeProperties{ + SourcePath: aws.String(hostPath), + } + } + + if v, ok := data["docker_volume_configuration"].([]interface{}); ok && len(v) > 0 { + l.DockerVolumeConfiguration = expandEcsVolumesDockerVolume(v) + } + + if v, ok := data["efs_volume_configuration"].([]interface{}); ok && len(v) > 0 { + l.EfsVolumeConfiguration = expandEcsVolumesEFSVolume(v) + } + + if v, ok := data["fsx_windows_file_server_volume_configuration"].([]interface{}); ok && len(v) > 0 { + l.FsxWindowsFileServerVolumeConfiguration = expandEcsVolumesFsxWinVolume(v) + } + + volumes = append(volumes, l) + } + + return volumes +} + +func expandEcsVolumesDockerVolume(configList []interface{}) *ecs.DockerVolumeConfiguration { + config := configList[0].(map[string]interface{}) + dockerVol := &ecs.DockerVolumeConfiguration{} + + if v, ok := config["scope"].(string); ok && v != "" { + dockerVol.Scope = aws.String(v) + } + + if v, ok := config["autoprovision"]; ok && v != "" { + scope := dockerVol.Scope + if scope == nil || *scope != ecs.ScopeTask || v.(bool) { + dockerVol.Autoprovision = aws.Bool(v.(bool)) + } + } + + if v, ok := config["driver"].(string); ok && v != "" { + dockerVol.Driver = aws.String(v) + } + + if v, ok := config["driver_opts"].(map[string]interface{}); ok && len(v) > 0 { + dockerVol.DriverOpts = expandStringMap(v) + } + + if v, ok := config["labels"].(map[string]interface{}); ok && len(v) > 0 { + dockerVol.Labels = expandStringMap(v) + } + + return dockerVol +} + +func expandEcsVolumesEFSVolume(efsConfig []interface{}) *ecs.EFSVolumeConfiguration { + config := efsConfig[0].(map[string]interface{}) + efsVol := &ecs.EFSVolumeConfiguration{} + + if v, ok := config["file_system_id"].(string); ok && v != "" { + efsVol.FileSystemId = aws.String(v) + } + + if v, ok := config["root_directory"].(string); ok && v != "" { + efsVol.RootDirectory = aws.String(v) + } + if v, ok := config["transit_encryption"].(string); ok && v != "" { + efsVol.TransitEncryption = aws.String(v) + } + + if v, ok := config["transit_encryption_port"].(int); ok && v > 0 { + efsVol.TransitEncryptionPort = aws.Int64(int64(v)) + } + authConfig, ok := config["authorization_config"].([]interface{}) + if ok && len(authConfig) > 0 { + authconfig := authConfig[0].(map[string]interface{}) + efsVol.RootDirectory = nil + efsVol.AuthorizationConfig = &ecs.EFSAuthorizationConfig{} + + if v, ok := authconfig["access_point_id"].(string); ok && v != "" { + efsVol.AuthorizationConfig.AccessPointId = aws.String(v) + } + + if v, ok := authconfig["iam"].(string); ok && v != "" { + efsVol.AuthorizationConfig.Iam = aws.String(v) + } + } + + return efsVol +} + +func expandEcsVolumesFsxWinVolume(fsxWinConfig []interface{}) *ecs.FSxWindowsFileServerVolumeConfiguration { + config := fsxWinConfig[0].(map[string]interface{}) + fsxVol := &ecs.FSxWindowsFileServerVolumeConfiguration{} + + if v, ok := config["file_system_id"].(string); ok && v != "" { + fsxVol.FileSystemId = aws.String(v) + } + + if v, ok := config["root_directory"].(string); ok && v != "" { + fsxVol.RootDirectory = aws.String(v) + } + + authConfig, ok := config["authorization_config"].([]interface{}) + if ok && len(authConfig) > 0 { + authconfig := authConfig[0].(map[string]interface{}) + fsxVol.AuthorizationConfig = &ecs.FSxWindowsFileServerAuthorizationConfig{} + + if v, ok := authconfig["credentials_parameter"].(string); ok && v != "" { + fsxVol.AuthorizationConfig.CredentialsParameter = aws.String(v) + } + + if v, ok := authconfig["domain"].(string); ok && v != "" { + fsxVol.AuthorizationConfig.Domain = aws.String(v) + } + } + + return fsxVol +} + +func flattenEcsVolumes(list []*ecs.Volume) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(list)) + for _, volume := range list { + l := map[string]interface{}{ + "name": aws.StringValue(volume.Name), + } + + if volume.Host != nil && volume.Host.SourcePath != nil { + l["host_path"] = aws.StringValue(volume.Host.SourcePath) + } + + if volume.DockerVolumeConfiguration != nil { + l["docker_volume_configuration"] = flattenDockerVolumeConfiguration(volume.DockerVolumeConfiguration) + } + + if volume.EfsVolumeConfiguration != nil { + l["efs_volume_configuration"] = flattenEFSVolumeConfiguration(volume.EfsVolumeConfiguration) + } + + if volume.FsxWindowsFileServerVolumeConfiguration != nil { + l["fsx_windows_file_server_volume_configuration"] = flattenFsxWinVolumeConfiguration(volume.FsxWindowsFileServerVolumeConfiguration) + } + + result = append(result, l) + } + return result +} + +func flattenDockerVolumeConfiguration(config *ecs.DockerVolumeConfiguration) []interface{} { + var items []interface{} + m := make(map[string]interface{}) + + if v := config.Scope; v != nil { + m["scope"] = aws.StringValue(v) + } + + if v := config.Autoprovision; v != nil { + m["autoprovision"] = aws.BoolValue(v) + } + + if v := config.Driver; v != nil { + m["driver"] = aws.StringValue(v) + } + + if config.DriverOpts != nil { + m["driver_opts"] = pointersMapToStringList(config.DriverOpts) + } + + if v := config.Labels; v != nil { + m["labels"] = pointersMapToStringList(v) + } + + items = append(items, m) + return items +} + +func flattenEFSVolumeConfiguration(config *ecs.EFSVolumeConfiguration) []interface{} { + var items []interface{} + m := make(map[string]interface{}) + if config != nil { + if v := config.FileSystemId; v != nil { + m["file_system_id"] = aws.StringValue(v) + } + + if v := config.RootDirectory; v != nil { + m["root_directory"] = aws.StringValue(v) + } + if v := config.TransitEncryption; v != nil { + m["transit_encryption"] = aws.StringValue(v) + } + + if v := config.TransitEncryptionPort; v != nil { + m["transit_encryption_port"] = int(aws.Int64Value(v)) + } + + if v := config.AuthorizationConfig; v != nil { + m["authorization_config"] = flattenEFSVolumeAuthorizationConfig(v) + } + } + + items = append(items, m) + return items +} + +func flattenEFSVolumeAuthorizationConfig(config *ecs.EFSAuthorizationConfig) []interface{} { + var items []interface{} + m := make(map[string]interface{}) + if config != nil { + if v := config.AccessPointId; v != nil { + m["access_point_id"] = aws.StringValue(v) + } + if v := config.Iam; v != nil { + m["iam"] = aws.StringValue(v) + } + } + + items = append(items, m) + return items +} + +func flattenFsxWinVolumeConfiguration(config *ecs.FSxWindowsFileServerVolumeConfiguration) []interface{} { + var items []interface{} + m := make(map[string]interface{}) + if config != nil { + if v := config.FileSystemId; v != nil { + m["file_system_id"] = aws.StringValue(v) + } + + if v := config.RootDirectory; v != nil { + m["root_directory"] = aws.StringValue(v) + } + + if v := config.AuthorizationConfig; v != nil { + m["authorization_config"] = flattenFsxWinVolumeAuthorizationConfig(v) + } + } + + items = append(items, m) + return items +} + +func flattenFsxWinVolumeAuthorizationConfig(config *ecs.FSxWindowsFileServerAuthorizationConfig) []interface{} { + var items []interface{} + m := make(map[string]interface{}) + if config != nil { + if v := config.CredentialsParameter; v != nil { + m["credentials_parameters"] = aws.StringValue(v) + } + if v := config.Domain; v != nil { + m["domain"] = aws.StringValue(v) + } + } + + items = append(items, m) + return items +} diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index b6206f7d76a8..03e5a09bdd85 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -303,6 +303,35 @@ func TestAccAWSEcsTaskDefinition_withEFSAccessPoint(t *testing.T) { }) } +func TestAccAWSEcsTaskDefinition_withFsxWinFileSystem(t *testing.T) { + var def ecs.TaskDefinition + + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_ecs_task_definition.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ecs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEcsTaskDefinitionWithFsxVolume(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), + resource.TestCheckResourceAttr(resourceName, "volume.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAWSEcsTaskDefinitionImportStateIdFunc(resourceName), + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSEcsTaskDefinition_withTaskScopedDockerVolume(t *testing.T) { var def ecs.TaskDefinition @@ -2204,6 +2233,52 @@ TASK_DEFINITION `, tdName) } +func testAccAWSEcsTaskDefinitionWithFsxVolume(tdName string) string { + return testAccAwsFsxWindowsFileSystemConfigSubnetIds1() + fmt.Sprintf(` +resource "aws_secretsmanager_secret" "test" { + name = %[1]q + recovery_window_in_days = 0 +} + +resource "aws_secretsmanager_secret_version" "test" { + secret_id = aws_secretsmanager_secret.test.id + secret_string = jsonencode({ username : "admin", password : "${aws_directory_service_directory.test.password}" }) +} + +resource "aws_ecs_task_definition" "test" { + family = %[1]q + + container_definitions = < 0 { - config := configList[0].(map[string]interface{}) - l.DockerVolumeConfiguration = &ecs.DockerVolumeConfiguration{} - - if v, ok := config["scope"].(string); ok && v != "" { - l.DockerVolumeConfiguration.Scope = aws.String(v) - } - - if v, ok := config["autoprovision"]; ok && v != "" { - scope := l.DockerVolumeConfiguration.Scope - if scope == nil || *scope != ecs.ScopeTask || v.(bool) { - l.DockerVolumeConfiguration.Autoprovision = aws.Bool(v.(bool)) - } - } - - if v, ok := config["driver"].(string); ok && v != "" { - l.DockerVolumeConfiguration.Driver = aws.String(v) - } - - if v, ok := config["driver_opts"].(map[string]interface{}); ok && len(v) > 0 { - l.DockerVolumeConfiguration.DriverOpts = expandStringMap(v) - } - - if v, ok := config["labels"].(map[string]interface{}); ok && len(v) > 0 { - l.DockerVolumeConfiguration.Labels = expandStringMap(v) - } - } - - efsConfig, ok := data["efs_volume_configuration"].([]interface{}) - if ok && len(efsConfig) > 0 { - config := efsConfig[0].(map[string]interface{}) - l.EfsVolumeConfiguration = &ecs.EFSVolumeConfiguration{} - - if v, ok := config["file_system_id"].(string); ok && v != "" { - l.EfsVolumeConfiguration.FileSystemId = aws.String(v) - } - - if v, ok := config["root_directory"].(string); ok && v != "" { - l.EfsVolumeConfiguration.RootDirectory = aws.String(v) - } - if v, ok := config["transit_encryption"].(string); ok && v != "" { - l.EfsVolumeConfiguration.TransitEncryption = aws.String(v) - } - - if v, ok := config["transit_encryption_port"].(int); ok && v > 0 { - l.EfsVolumeConfiguration.TransitEncryptionPort = aws.Int64(int64(v)) - } - authConfig, ok := config["authorization_config"].([]interface{}) - if ok && len(authConfig) > 0 { - authconfig := authConfig[0].(map[string]interface{}) - l.EfsVolumeConfiguration.RootDirectory = nil - l.EfsVolumeConfiguration.AuthorizationConfig = &ecs.EFSAuthorizationConfig{} - - if v, ok := authconfig["access_point_id"].(string); ok && v != "" { - l.EfsVolumeConfiguration.AuthorizationConfig.AccessPointId = aws.String(v) - } - - if v, ok := authconfig["iam"].(string); ok && v != "" { - l.EfsVolumeConfiguration.AuthorizationConfig.Iam = aws.String(v) - } - } - } - - volumes = append(volumes, l) - } - - return volumes -} - // Takes JSON in a string. Decodes JSON into // an array of ecs.ContainerDefinition compatible objects func expandEcsContainerDefinitions(rawDefinitions string) ([]*ecs.ContainerDefinition, error) { @@ -682,103 +591,6 @@ func flattenListeners(list []*elb.ListenerDescription) []map[string]interface{} return result } -// Flattens an array of Volumes into a []map[string]interface{} -func flattenEcsVolumes(list []*ecs.Volume) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(list)) - for _, volume := range list { - l := map[string]interface{}{ - "name": *volume.Name, - } - - if volume.Host != nil && volume.Host.SourcePath != nil { - l["host_path"] = *volume.Host.SourcePath - } - - if volume.DockerVolumeConfiguration != nil { - l["docker_volume_configuration"] = flattenDockerVolumeConfiguration(volume.DockerVolumeConfiguration) - } - - if volume.EfsVolumeConfiguration != nil { - l["efs_volume_configuration"] = flattenEFSVolumeConfiguration(volume.EfsVolumeConfiguration) - } - - result = append(result, l) - } - return result -} - -func flattenDockerVolumeConfiguration(config *ecs.DockerVolumeConfiguration) []interface{} { - var items []interface{} - m := make(map[string]interface{}) - - if v := config.Scope; v != nil { - m["scope"] = aws.StringValue(v) - } - - if v := config.Autoprovision; v != nil { - m["autoprovision"] = aws.BoolValue(v) - } - - if v := config.Driver; v != nil { - m["driver"] = aws.StringValue(v) - } - - if config.DriverOpts != nil { - m["driver_opts"] = pointersMapToStringList(config.DriverOpts) - } - - if v := config.Labels; v != nil { - m["labels"] = pointersMapToStringList(v) - } - - items = append(items, m) - return items -} - -func flattenEFSVolumeConfiguration(config *ecs.EFSVolumeConfiguration) []interface{} { - var items []interface{} - m := make(map[string]interface{}) - if config != nil { - if v := config.FileSystemId; v != nil { - m["file_system_id"] = aws.StringValue(v) - } - - if v := config.RootDirectory; v != nil { - m["root_directory"] = aws.StringValue(v) - } - if v := config.TransitEncryption; v != nil { - m["transit_encryption"] = aws.StringValue(v) - } - - if v := config.TransitEncryptionPort; v != nil { - m["transit_encryption_port"] = int(aws.Int64Value(v)) - } - - if v := config.AuthorizationConfig; v != nil { - m["authorization_config"] = flattenEFSVolumeAuthorizationConfig(v) - } - } - - items = append(items, m) - return items -} - -func flattenEFSVolumeAuthorizationConfig(config *ecs.EFSAuthorizationConfig) []interface{} { - var items []interface{} - m := make(map[string]interface{}) - if config != nil { - if v := config.AccessPointId; v != nil { - m["access_point_id"] = aws.StringValue(v) - } - if v := config.Iam; v != nil { - m["iam"] = aws.StringValue(v) - } - } - - items = append(items, m) - return items -} - // Flattens an array of ECS LoadBalancers into a []map[string]interface{} func flattenEcsLoadBalancers(list []*ecs.LoadBalancer) []map[string]interface{} { result := make([]map[string]interface{}, 0, len(list)) From 092ab0584165a2c49d51eba6f4f85d1da786dec0 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 19:27:19 +0300 Subject: [PATCH 0241/1208] changelog --- .changelog/19670.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/19670.txt diff --git a/.changelog/19670.txt b/.changelog/19670.txt new file mode 100644 index 000000000000..aaa44144676e --- /dev/null +++ b/.changelog/19670.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_ecs_task_definition: Add plan time validation for `family` and `requires_compatibilities`. +``` + +```release-note:enhancement +resource/aws_ecs_task_definition: Add support for `fsx_windows_file_server_volume_configuration`. +``` \ No newline at end of file From d74c7e1e55fc44f9feafea4544478a020c124f59 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 19:28:47 +0300 Subject: [PATCH 0242/1208] fmt --- aws/resource_aws_ecs_task_definition_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index 03e5a09bdd85..41e9ab4de714 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -2267,7 +2267,7 @@ TASK_DEFINITION fsx_windows_file_server_volume_configuration { file_system_id = aws_fsx_windows_file_system.test.id - root_directory = "\\data" + root_directory = "\\data" authorization_config { credentials_parameter = aws_secretsmanager_secret_version.test.arn From e2bb2a5583c462636973a6efc8566e72aefc5680 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 21:32:52 +0300 Subject: [PATCH 0243/1208] add iam role to test --- aws/resource_aws_ecs_task_definition_test.go | 44 +++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index 41e9ab4de714..f8442e346ffd 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -2235,6 +2235,8 @@ TASK_DEFINITION func testAccAWSEcsTaskDefinitionWithFsxVolume(tdName string) string { return testAccAwsFsxWindowsFileSystemConfigSubnetIds1() + fmt.Sprintf(` +data "aws_partition" "current" {} + resource "aws_secretsmanager_secret" "test" { name = %[1]q recovery_window_in_days = 0 @@ -2242,11 +2244,45 @@ resource "aws_secretsmanager_secret" "test" { resource "aws_secretsmanager_secret_version" "test" { secret_id = aws_secretsmanager_secret.test.id - secret_string = jsonencode({ username : "admin", password : "${aws_directory_service_directory.test.password}" }) + secret_string = jsonencode({ username : "admin", password : aws_directory_service_directory.test.password }) +} + +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = jsonencode({ + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Principal": { + "Service": "ecs-tasks.${data.aws_partition.current.dns_suffix}" + }, + "Effect": "Allow", + "Sid": "" + } + ] +}) +} + +resource "aws_iam_role_policy_attachment" "test" { + role = aws_iam_role.test.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +resource "aws_iam_role_policy_attachment" "test2" { + role = aws_iam_role.test.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/SecretsManagerReadWrite" +} + +resource "aws_iam_role_policy_attachment" "test3" { + role = aws_iam_role.test.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonFSxReadOnlyAccess" } resource "aws_ecs_task_definition" "test" { - family = %[1]q + family = %[1]q + execution_role_arn = aws_iam_role.test.arn container_definitions = < Date: Fri, 4 Jun 2021 21:33:02 +0300 Subject: [PATCH 0244/1208] fix arg --- aws/resource_aws_ecs_task_definition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_ecs_task_definition.go b/aws/resource_aws_ecs_task_definition.go index ec4d438c90fb..2d2acab4d2de 100644 --- a/aws/resource_aws_ecs_task_definition.go +++ b/aws/resource_aws_ecs_task_definition.go @@ -1024,7 +1024,7 @@ func flattenFsxWinVolumeAuthorizationConfig(config *ecs.FSxWindowsFileServerAuth m := make(map[string]interface{}) if config != nil { if v := config.CredentialsParameter; v != nil { - m["credentials_parameters"] = aws.StringValue(v) + m["credentials_parameter"] = aws.StringValue(v) } if v := config.Domain; v != nil { m["domain"] = aws.StringValue(v) From d938d778176a4ad3552151d2cb296e197f31ea86 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 21:38:04 +0300 Subject: [PATCH 0245/1208] fmt --- aws/resource_aws_ecs_task_definition_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index f8442e346ffd..99bac8de877d 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -2312,9 +2312,11 @@ TASK_DEFINITION } } - depends_on = [aws_iam_role_policy_attachment.test, - aws_iam_role_policy_attachment.test2, - aws_iam_role_policy_attachment.test3] + depends_on = [ + aws_iam_role_policy_attachment.test, + aws_iam_role_policy_attachment.test2, + aws_iam_role_policy_attachment.test3 + ] } `, tdName) } From 1c5d35312c4a67369b688add454da3cc0ed69c49 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 21:43:14 +0300 Subject: [PATCH 0246/1208] fmt --- aws/resource_aws_ecs_task_definition_test.go | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index 99bac8de877d..214d46bd8390 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -2251,18 +2251,18 @@ resource "aws_iam_role" "test" { name = %[1]q assume_role_policy = jsonencode({ - "Version": "2012-10-17", - "Statement": [ - { - "Action": "sts:AssumeRole", - "Principal": { - "Service": "ecs-tasks.${data.aws_partition.current.dns_suffix}" - }, - "Effect": "Allow", - "Sid": "" - } - ] -}) + "Version" : "2012-10-17", + "Statement" : [ + { + "Action" : "sts:AssumeRole", + "Principal" : { + "Service" : "ecs-tasks.${data.aws_partition.current.dns_suffix}" + }, + "Effect" : "Allow", + "Sid" : "" + } + ] + }) } resource "aws_iam_role_policy_attachment" "test" { From 5fe4b73200e917271c4d828fe0f8889890cbd2eb Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 21:55:37 +0300 Subject: [PATCH 0247/1208] move to ecs from structure --- aws/resource_aws_ecs_task_definition.go | 22 ++++++++++++++++++++++ aws/structure.go | 24 ------------------------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/aws/resource_aws_ecs_task_definition.go b/aws/resource_aws_ecs_task_definition.go index 2d2acab4d2de..124d39e621e9 100644 --- a/aws/resource_aws_ecs_task_definition.go +++ b/aws/resource_aws_ecs_task_definition.go @@ -2,12 +2,14 @@ package aws import ( "bytes" + "encoding/json" "fmt" "log" "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil" "github.com/aws/aws-sdk-go/service/ecs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" @@ -1034,3 +1036,23 @@ func flattenFsxWinVolumeAuthorizationConfig(config *ecs.FSxWindowsFileServerAuth items = append(items, m) return items } + +func flattenEcsContainerDefinitions(definitions []*ecs.ContainerDefinition) (string, error) { + b, err := jsonutil.BuildJSON(definitions) + if err != nil { + return "", err + } + + return string(b), nil +} + +func expandEcsContainerDefinitions(rawDefinitions string) ([]*ecs.ContainerDefinition, error) { + var definitions []*ecs.ContainerDefinition + + err := json.Unmarshal([]byte(rawDefinitions), &definitions) + if err != nil { + return nil, fmt.Errorf("Error decoding JSON: %s", err) + } + + return definitions, nil +} diff --git a/aws/structure.go b/aws/structure.go index 4887de3a2afe..abaaf21ca6f2 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -11,7 +11,6 @@ import ( "strings" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil" "github.com/aws/aws-sdk-go/service/apigateway" "github.com/aws/aws-sdk-go/service/appmesh" "github.com/aws/aws-sdk-go/service/autoscaling" @@ -96,19 +95,6 @@ func expandListeners(configured []interface{}) ([]*elb.Listener, error) { return listeners, nil } -// Takes JSON in a string. Decodes JSON into -// an array of ecs.ContainerDefinition compatible objects -func expandEcsContainerDefinitions(rawDefinitions string) ([]*ecs.ContainerDefinition, error) { - var definitions []*ecs.ContainerDefinition - - err := json.Unmarshal([]byte(rawDefinitions), &definitions) - if err != nil { - return nil, fmt.Errorf("Error decoding JSON: %s", err) - } - - return definitions, nil -} - // Takes the result of flatmap. Expand for an array of load balancers and // returns ecs.LoadBalancer compatible objects func expandEcsLoadBalancers(configured []interface{}) []*ecs.LoadBalancer { @@ -613,16 +599,6 @@ func flattenEcsLoadBalancers(list []*ecs.LoadBalancer) []map[string]interface{} return result } -// Encodes an array of ecs.ContainerDefinitions into a JSON string -func flattenEcsContainerDefinitions(definitions []*ecs.ContainerDefinition) (string, error) { - b, err := jsonutil.BuildJSON(definitions) - if err != nil { - return "", err - } - - return string(b), nil -} - // Flattens an array of Options into a []map[string]interface{} func flattenOptions(apiOptions []*rds.Option, optionConfigurations []*rds.OptionConfiguration) []map[string]interface{} { result := make([]map[string]interface{}, 0) From 275be2859071963c0a7e18b497b0d0984ae5f5c0 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 22:09:46 +0300 Subject: [PATCH 0248/1208] better break down of structs --- aws/resource_aws_ecs_task_definition.go | 54 +++++++++++++++---------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/aws/resource_aws_ecs_task_definition.go b/aws/resource_aws_ecs_task_definition.go index 124d39e621e9..243d5d249e37 100644 --- a/aws/resource_aws_ecs_task_definition.go +++ b/aws/resource_aws_ecs_task_definition.go @@ -853,22 +853,27 @@ func expandEcsVolumesEFSVolume(efsConfig []interface{}) *ecs.EFSVolumeConfigurat if v, ok := config["transit_encryption_port"].(int); ok && v > 0 { efsVol.TransitEncryptionPort = aws.Int64(int64(v)) } - authConfig, ok := config["authorization_config"].([]interface{}) - if ok && len(authConfig) > 0 { - authconfig := authConfig[0].(map[string]interface{}) + if v, ok := config["authorization_config"].([]interface{}); ok && len(v) > 0 { efsVol.RootDirectory = nil - efsVol.AuthorizationConfig = &ecs.EFSAuthorizationConfig{} + efsVol.AuthorizationConfig = expandEcsVolumesEFSVolumeAuthorizationConfig(v) + } - if v, ok := authconfig["access_point_id"].(string); ok && v != "" { - efsVol.AuthorizationConfig.AccessPointId = aws.String(v) - } + return efsVol +} - if v, ok := authconfig["iam"].(string); ok && v != "" { - efsVol.AuthorizationConfig.Iam = aws.String(v) - } +func expandEcsVolumesEFSVolumeAuthorizationConfig(efsConfig []interface{}) *ecs.EFSAuthorizationConfig { + authconfig := efsConfig[0].(map[string]interface{}) + auth := &ecs.EFSAuthorizationConfig{} + + if v, ok := authconfig["access_point_id"].(string); ok && v != "" { + auth.AccessPointId = aws.String(v) } - return efsVol + if v, ok := authconfig["iam"].(string); ok && v != "" { + auth.Iam = aws.String(v) + } + + return auth } func expandEcsVolumesFsxWinVolume(fsxWinConfig []interface{}) *ecs.FSxWindowsFileServerVolumeConfiguration { @@ -883,21 +888,26 @@ func expandEcsVolumesFsxWinVolume(fsxWinConfig []interface{}) *ecs.FSxWindowsFil fsxVol.RootDirectory = aws.String(v) } - authConfig, ok := config["authorization_config"].([]interface{}) - if ok && len(authConfig) > 0 { - authconfig := authConfig[0].(map[string]interface{}) - fsxVol.AuthorizationConfig = &ecs.FSxWindowsFileServerAuthorizationConfig{} + if v, ok := config["authorization_config"].([]interface{}); ok && len(v) > 0 { + fsxVol.AuthorizationConfig = expandEcsVolumesFsxWinVolumeAuthorizationConfig(v) + } - if v, ok := authconfig["credentials_parameter"].(string); ok && v != "" { - fsxVol.AuthorizationConfig.CredentialsParameter = aws.String(v) - } + return fsxVol +} - if v, ok := authconfig["domain"].(string); ok && v != "" { - fsxVol.AuthorizationConfig.Domain = aws.String(v) - } +func expandEcsVolumesFsxWinVolumeAuthorizationConfig(config []interface{}) *ecs.FSxWindowsFileServerAuthorizationConfig { + authconfig := config[0].(map[string]interface{}) + auth := &ecs.FSxWindowsFileServerAuthorizationConfig{} + + if v, ok := authconfig["credentials_parameter"].(string); ok && v != "" { + auth.CredentialsParameter = aws.String(v) } - return fsxVol + if v, ok := authconfig["domain"].(string); ok && v != "" { + auth.Domain = aws.String(v) + } + + return auth } func flattenEcsVolumes(list []*ecs.Volume) []map[string]interface{} { From d4af89a53e8a03e799a5ca1c229a0122ab42465c Mon Sep 17 00:00:00 2001 From: Wayne Cheng Date: Fri, 4 Jun 2021 15:12:22 -0400 Subject: [PATCH 0249/1208] eks_node_group documentation fix for exported resources attribute --- website/docs/r/eks_node_group.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/eks_node_group.html.markdown b/website/docs/r/eks_node_group.html.markdown index f7d4f6490d4d..0f5d9059b6f4 100644 --- a/website/docs/r/eks_node_group.html.markdown +++ b/website/docs/r/eks_node_group.html.markdown @@ -169,10 +169,10 @@ In addition to all arguments above, the following attributes are exported: * `arn` - Amazon Resource Name (ARN) of the EKS Node Group. * `id` - EKS Cluster name and EKS Node Group name separated by a colon (`:`). * `resources` - List of objects containing information about underlying resources. -* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block). * `autoscaling_groups` - List of objects containing information about AutoScaling Groups. * `name` - Name of the AutoScaling Group. * `remote_access_security_group_id` - Identifier of the remote access EC2 Security Group. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block). * `status` - Status of the EKS Node Group. ## Timeouts From fdce2015c734dd388729f93badd2fbc82e22ae87 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Jun 2021 23:26:07 +0300 Subject: [PATCH 0250/1208] docs --- .../docs/r/ecs_task_definition.html.markdown | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/website/docs/r/ecs_task_definition.html.markdown b/website/docs/r/ecs_task_definition.html.markdown index 0aa9f1f2caa0..f441a323d053 100644 --- a/website/docs/r/ecs_task_definition.html.markdown +++ b/website/docs/r/ecs_task_definition.html.markdown @@ -128,6 +128,34 @@ resource "aws_ecs_task_definition" "service" { } ``` +### Example Using `fsx_windows_file_server_volume_configuration` + +```terraform +resource "aws_ecs_task_definition" "service" { + family = "service" + container_definitions = file("task-definitions/service.json") + + volume { + name = "service-storage" + + fsx_windows_file_server_volume_configuration { + file_system_id = aws_fsx_windows_file_system.test.id + root_directory = "\\data" + + authorization_config { + credentials_parameter = aws_secretsmanager_secret_version.test.arn + domain = aws_directory_service_directory.test.name + } + } + } +} + +resource "aws_secretsmanager_secret_version" "test" { + secret_id = aws_secretsmanager_secret.test.id + secret_string = jsonencode({ username : "admin", password : aws_directory_service_directory.test.password }) +} +``` + ### Example Using `container_definitions` and `inference_accelerator` ```terraform @@ -198,6 +226,7 @@ The following arguments are optional: * `docker_volume_configuration` - (Optional) Configuration block to configure a [docker volume](#docker_volume_configuration). Detailed below. * `efs_volume_configuration` - (Optional) Configuration block for an [EFS volume](#efs_volume_configuration). Detailed below. +* `fsx_windows_file_server_volume_configuration` - (Optional) Configuration block for an [FSX Windows File Server volume](#fsx_windows_file_server_volume_configuration). Detailed below. * `host_path` - (Optional) Path on the host container instance that is presented to the container. If not set, ECS will create a nonpersistent data volume that starts empty and is deleted after the task has finished. * `name` - (Required) Name of the volume. This name is referenced in the `sourceVolume` parameter of container definition in the `mountPoints` section. @@ -222,11 +251,24 @@ For more information, see [Specifying an EFS volume in your Task Definition Deve * `transit_encryption_port` - (Optional) Port to use for transit encryption. If you do not specify a transit encryption port, it will use the port selection strategy that the Amazon EFS mount helper uses. * `authorization_config` - (Optional) Configuration block for [authorization](#authorization_config) for the Amazon EFS file system. Detailed below. -### authorization_config +#### authorization_config * `access_point_id` - (Optional) Access point ID to use. If an access point is specified, the root directory value will be relative to the directory set for the access point. If specified, transit encryption must be enabled in the EFSVolumeConfiguration. * `iam` - (Optional) Whether or not to use the Amazon ECS task IAM role defined in a task definition when mounting the Amazon EFS file system. If enabled, transit encryption must be enabled in the EFSVolumeConfiguration. Valid values: `ENABLED`, `DISABLED`. If this parameter is omitted, the default value of `DISABLED` is used. +### fsx_windows_file_server_volume_configuration + +For more information, see [Specifying an FSX Windows File Server volume in your Task Definition Developer Guide](https://docs.amazonaws.cn/en_us/AmazonECS/latest/developerguide/tutorial-wfsx-volumes.html) + +* `file_system_id` - (Required) The Amazon FSx for Windows File Server file system ID to use. +* `root_directory` - (Required) The directory within the Amazon FSx for Windows File Server file system to mount as the root directory inside the host. +* `authorization_config` - (OptiRequiredonal) Configuration block for [authorization](#authorization_config) for the Amazon FSx for Windows File Server file system detailed below. + +#### authorization_config + +* `credentials_parameter` - (Required) The authorization credential option to use. The authorization credential options can be provided using either the Amazon Resource Name (ARN) of an AWS Secrets Manager secret or AWS Systems Manager Parameter Store parameter. The ARNs refer to the stored credentials. +* `domain` - (Required) A fully qualified domain name hosted by an AWS Directory Service Managed Microsoft AD (Active Directory) or self-hosted AD on Amazon EC2. + ### placement_constraints * `expression` - (Optional) Cluster Query Language expression to apply to the constraint. For more information, see [Cluster Query Language in the Amazon EC2 Container Service Developer Guide](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-query-language.html). From 5fa4a7a094ec74c71caee6879700709f158ebf36 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 4 Jun 2021 14:11:38 -0700 Subject: [PATCH 0251/1208] Adds CHANGELOG --- .changelog/17610.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/17610.txt diff --git a/.changelog/17610.txt b/.changelog/17610.txt new file mode 100644 index 000000000000..7f3bcaf1cbf6 --- /dev/null +++ b/.changelog/17610.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_lambda_function: Prevents perpetual diff in `vpc_config` +``` From 79b9c0a573548f3f6cb2cc09552f6f1834423e35 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 5 Jun 2021 00:22:52 +0300 Subject: [PATCH 0252/1208] tests --- aws/resource_aws_ecs_task_definition_test.go | 57 ++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index 214d46bd8390..3f441f8815ca 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -147,6 +147,19 @@ func TestAccAWSEcsTaskDefinition_withDockerVolume(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), resource.TestCheckResourceAttr(resourceName, "volume.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "volume.*", map[string]string{ + "name": tdName, + "docker_volume_configuration.#": "1", + "docker_volume_configuration.0.driver": "local", + "docker_volume_configuration.0.scope": "shared", + "docker_volume_configuration.0.autoprovision": "true", + "docker_volume_configuration.0.driver_opts.%": "2", + "docker_volume_configuration.0.driver_opts.device": "tmpfs", + "docker_volume_configuration.0.driver_opts.uid": "1000", + "docker_volume_configuration.0.labels.%": "2", + "docker_volume_configuration.0.labels.environment": "test", + "docker_volume_configuration.0.labels.stack": "april", + }), ), }, { @@ -176,6 +189,11 @@ func TestAccAWSEcsTaskDefinition_withDockerVolumeMinimalConfig(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), resource.TestCheckResourceAttr(resourceName, "volume.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "volume.*", map[string]string{ + "name": tdName, + "docker_volume_configuration.#": "1", + "docker_volume_configuration.0.autoprovision": "true", + }), ), }, { @@ -205,6 +223,11 @@ func TestAccAWSEcsTaskDefinition_withEFSVolumeMinimal(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), resource.TestCheckResourceAttr(resourceName, "volume.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "volume.*", map[string]string{ + "name": tdName, + "efs_volume_configuration.#": "1", + }), + resource.TestCheckTypeSetElemAttrPair(resourceName, "volume.*.efs_volume_configuration.0.file_system_id", "aws_efs_file_system.test", "id"), ), }, { @@ -234,6 +257,12 @@ func TestAccAWSEcsTaskDefinition_withEFSVolume(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), resource.TestCheckResourceAttr(resourceName, "volume.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "volume.*", map[string]string{ + "name": tdName, + "efs_volume_configuration.#": "1", + "efs_volume_configuration.0.root_directory": "/home/test", + }), + resource.TestCheckTypeSetElemAttrPair(resourceName, "volume.*.efs_volume_configuration.0.file_system_id", "aws_efs_file_system.test", "id"), ), }, { @@ -262,6 +291,14 @@ func TestAccAWSEcsTaskDefinition_withTransitEncryptionEFSVolume(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), resource.TestCheckResourceAttr(resourceName, "volume.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "volume.*", map[string]string{ + "name": tdName, + "efs_volume_configuration.#": "1", + "efs_volume_configuration.0.root_directory": "/home/test", + "efs_volume_configuration.0.transit_encryption": "ENABLED", + "efs_volume_configuration.0.transit_encryption_port": "2999", + }), + resource.TestCheckTypeSetElemAttrPair(resourceName, "volume.*.efs_volume_configuration.0.file_system_id", "aws_efs_file_system.test", "id"), ), }, { @@ -291,6 +328,17 @@ func TestAccAWSEcsTaskDefinition_withEFSAccessPoint(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), resource.TestCheckResourceAttr(resourceName, "volume.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "volume.*", map[string]string{ + "name": tdName, + "efs_volume_configuration.#": "1", + "efs_volume_configuration.0.root_directory": "/", + "efs_volume_configuration.0.transit_encryption": "ENABLED", + "efs_volume_configuration.0.transit_encryption_port": "2999", + "efs_volume_configuration.0.authorization_config.#": "1", + "efs_volume_configuration.0.authorization_config.0.iam": "DISABLED", + }), + resource.TestCheckTypeSetElemAttrPair(resourceName, "volume.*.efs_volume_configuration.0.file_system_id", "aws_efs_file_system.test", "id"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "volume.*.efs_volume_configuration.0.authorization_config.0.access_point_id", "aws_efs_access_point.test", "id"), ), }, { @@ -320,6 +368,15 @@ func TestAccAWSEcsTaskDefinition_withFsxWinFileSystem(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), resource.TestCheckResourceAttr(resourceName, "volume.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "volume.*", map[string]string{ + "name": rName, + "fsx_windows_file_server_volume_configuration.#": "1", + "fsx_windows_file_server_volume_configuration.0.root_directory": "\\data", + "fsx_windows_file_server_volume_configuration.0.authorization_config.#": "1", + }), + resource.TestCheckTypeSetElemAttrPair(resourceName, "volume.*.fsx_windows_file_server_volume_configuration.0.file_system_id", "aws_fsx_windows_file_system.test", "id"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "volume.*.fsx_windows_file_server_volume_configuration.0.authorization_config.0.credentials_parameter", "aws_secretsmanager_secret_version.test", "arn"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "volume.*.fsx_windows_file_server_volume_configuration.0.authorization_config.0.domain", "aws_directory_service_directory.test", "name"), ), }, { From 9fa6fe2e7d681eb575404c98f84c03d856ddc107 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 4 Jun 2021 17:45:33 -0400 Subject: [PATCH 0253/1208] r/aws_sqs_queue: Use internal attrmap package. --- aws/internal/attrmap/attrmap.go | 32 +- aws/internal/service/sqs/consts.go | 5 + aws/internal/service/sqs/finder/finder.go | 4 +- aws/internal/service/sqs/name.go | 25 ++ aws/internal/service/sqs/name_test.go | 57 ++++ aws/internal/service/sqs/waiter/waiter.go | 44 +++ aws/resource_aws_sqs_queue.go | 350 ++++++++++------------ aws/resource_aws_sqs_queue_policy_test.go | 6 +- aws/resource_aws_sqs_queue_test.go | 47 ++- 9 files changed, 344 insertions(+), 226 deletions(-) create mode 100644 aws/internal/service/sqs/name.go create mode 100644 aws/internal/service/sqs/name_test.go diff --git a/aws/internal/attrmap/attrmap.go b/aws/internal/attrmap/attrmap.go index e587aa967f0a..62d21f3d8705 100644 --- a/aws/internal/attrmap/attrmap.go +++ b/aws/internal/attrmap/attrmap.go @@ -11,8 +11,9 @@ import ( // Useful for SQS Queue or SNS Topic attribute handling. type AttributeMap map[string]string -// ResourceDataToApiAttributes returns a map of AWS API attributes from Terraform ResourceData. -func (m AttributeMap) ResourceDataToApiAttributes(d *schema.ResourceData) (map[string]string, error) { +// ResourceDataToApiAttributesCreate returns a map of AWS API attributes from Terraform ResourceData. +// The API attributes map is suitable for resource create. +func (m AttributeMap) ResourceDataToApiAttributesCreate(d *schema.ResourceData) (map[string]string, error) { apiAttributes := map[string]string{} for tfAttributeName, apiAttributeName := range m { @@ -36,3 +37,30 @@ func (m AttributeMap) ResourceDataToApiAttributes(d *schema.ResourceData) (map[s return apiAttributes, nil } + +// ResourceDataToApiAttributesUpdate returns a map of AWS API attributes from Terraform ResourceData. +// The API attributes map is suitable for resource update. +func (m AttributeMap) ResourceDataToApiAttributesUpdate(d *schema.ResourceData) (map[string]string, error) { + apiAttributes := map[string]string{} + + for tfAttributeName, apiAttributeName := range m { + if d.HasChange(tfAttributeName) { + var apiAttributeValue string + + switch v := d.Get(tfAttributeName).(type) { + case int: + apiAttributeValue = strconv.Itoa(v) + case bool: + apiAttributeValue = strconv.FormatBool(v) + case string: + apiAttributeValue = v + default: + return nil, fmt.Errorf("attribute %s is of unsupported type: %T", tfAttributeName, v) + } + + apiAttributes[apiAttributeName] = apiAttributeValue + } + } + + return apiAttributes, nil +} diff --git a/aws/internal/service/sqs/consts.go b/aws/internal/service/sqs/consts.go index 0c70773e947c..33ac3d6259b0 100644 --- a/aws/internal/service/sqs/consts.go +++ b/aws/internal/service/sqs/consts.go @@ -1,11 +1,16 @@ package sqs +const ( + ErrCodeInvalidAction = "InvalidAction" +) + const ( FifoQueueNameSuffix = ".fifo" ) const ( DefaultQueueDelaySeconds = 0 + DefaultQueueKmsDataKeyReusePeriodSeconds = 300 DefaultQueueMaximumMessageSize = 262144 DefaultQueueMessageRetentionPeriod = 345600 DefaultQueueReceiveMessageWaitTimeSeconds = 0 diff --git a/aws/internal/service/sqs/finder/finder.go b/aws/internal/service/sqs/finder/finder.go index 6b813258d2e1..545a97d81492 100644 --- a/aws/internal/service/sqs/finder/finder.go +++ b/aws/internal/service/sqs/finder/finder.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func QueueAttributesByURL(conn *sqs.SQS, url string) (map[string]*string, error) { +func QueueAttributesByURL(conn *sqs.SQS, url string) (map[string]string, error) { input := &sqs.GetQueueAttributesInput{ AttributeNames: aws.StringSlice([]string{sqs.QueueAttributeNameAll}), QueueUrl: aws.String(url), @@ -33,5 +33,5 @@ func QueueAttributesByURL(conn *sqs.SQS, url string) (map[string]*string, error) } } - return output.Attributes, nil + return aws.StringValueMap(output.Attributes), nil } diff --git a/aws/internal/service/sqs/name.go b/aws/internal/service/sqs/name.go new file mode 100644 index 000000000000..9653911ecba6 --- /dev/null +++ b/aws/internal/service/sqs/name.go @@ -0,0 +1,25 @@ +package sqs + +import ( + "fmt" + "net/url" + "strings" +) + +// QueueNameFromURL returns the SQS queue name from the specified URL. +func QueueNameFromURL(u string) (string, error) { + v, err := url.Parse(u) + + if err != nil { + return "", err + } + + // http://sqs.us-west-2.amazonaws.com/123456789012/queueName + parts := strings.Split(v.Path, "/") + + if len(parts) != 3 { + return "", fmt.Errorf("SQS Queue URL (%s) is in the incorrect format", u) + } + + return parts[2], nil +} diff --git a/aws/internal/service/sqs/name_test.go b/aws/internal/service/sqs/name_test.go new file mode 100644 index 000000000000..8d70aac27424 --- /dev/null +++ b/aws/internal/service/sqs/name_test.go @@ -0,0 +1,57 @@ +package sqs + +import ( + "testing" +) + +func TestQueueNameFromURL(t *testing.T) { + testCases := []struct { + Name string + URL string + ExpectedQueueName string + ExpectError bool + }{ + { + Name: "empty URL", + ExpectError: true, + }, + { + Name: "invalid URL", + URL: "---", + ExpectError: true, + }, + { + Name: "too few path parts", + URL: "http://sqs.us-west-2.amazonaws.com", + ExpectError: true, + }, + { + Name: "too many path parts", + URL: "http://sqs.us-west-2.amazonaws.com/123456789012/queueName/extra", + ExpectError: true, + }, + { + Name: "valid URL", + URL: "http://sqs.us-west-2.amazonaws.com/123456789012/queueName", + ExpectedQueueName: "queueName", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + got, err := QueueNameFromURL(testCase.URL) + + if err != nil && !testCase.ExpectError { + t.Errorf("got unexpected error: %s", err) + } + + if err == nil && testCase.ExpectError { + t.Errorf("expected error, but received none") + } + + if got != testCase.ExpectedQueueName { + t.Errorf("got %s, expected %s", got, testCase.ExpectedQueueName) + } + }) + } +} diff --git a/aws/internal/service/sqs/waiter/waiter.go b/aws/internal/service/sqs/waiter/waiter.go index 86a2c078cd3d..b580683fa90f 100644 --- a/aws/internal/service/sqs/waiter/waiter.go +++ b/aws/internal/service/sqs/waiter/waiter.go @@ -1,7 +1,13 @@ package waiter import ( + "fmt" "time" + + "github.com/aws/aws-sdk-go/service/sqs" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -11,4 +17,42 @@ const ( // have incorrect references or permissions. // Reference: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SetQueueAttributes.html QueueAttributePropagationTimeout = 1 * time.Minute + + // If you delete a queue, you must wait at least 60 seconds before creating a queue with the same name. + // ReferenceL https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_CreateQueue.html + QueueCreatedTimeout = 70 * time.Second + + QueueDeletedTimeout = 15 * time.Second ) + +func QueueDeleted(conn *sqs.SQS, url string) error { + err := resource.Retry(QueueDeletedTimeout, func() *resource.RetryError { + var err error + + _, err = finder.QueueAttributesByURL(conn, url) + + if tfresource.NotFound(err) { + return nil + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return resource.RetryableError(fmt.Errorf("SQS Queue (%s) still exists", url)) + }) + + if tfresource.TimedOut(err) { + _, err = finder.QueueAttributesByURL(conn, url) + + if tfresource.NotFound(err) { + return nil + } + } + + if err != nil { + return err + } + + return nil +} diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index 86af38416168..76031eee8bf4 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -4,14 +4,10 @@ import ( "context" "fmt" "log" - "net/url" "regexp" "strconv" - "strings" - "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/service/sqs" "github.com/hashicorp/aws-sdk-go-base/tfawserr" @@ -20,12 +16,16 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/attrmap" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" tfsqs "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -var sqsQueueAttributeMap = map[string]string{ +var sqsQueueAttributeMap = attrmap.AttributeMap(map[string]string{ "delay_seconds": sqs.QueueAttributeNameDelaySeconds, "max_message_size": sqs.QueueAttributeNameMaximumMessageSize, "message_retention_seconds": sqs.QueueAttributeNameMessageRetentionPeriod, @@ -40,7 +40,7 @@ var sqsQueueAttributeMap = map[string]string{ "kms_data_key_reuse_period_seconds": sqs.QueueAttributeNameKmsDataKeyReusePeriodSeconds, "deduplication_scope": sqs.QueueAttributeNameDeduplicationScope, "fifo_throughput_limit": sqs.QueueAttributeNameFifoThroughputLimit, -} +}) // A number of these are marked as computed because if you don't // provide a value, SQS will provide you with defaults (which are the @@ -158,7 +158,7 @@ func resourceAwsSqsQueue() *schema.Resource { } func resourceAwsSqsQueueCreate(d *schema.ResourceData, meta interface{}) error { - sqsconn := meta.(*AWSClient).sqsconn + conn := meta.(*AWSClient).sqsconn defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) @@ -171,109 +171,55 @@ func resourceAwsSqsQueueCreate(d *schema.ResourceData, meta interface{}) error { name = naming.Generate(d.Get("name").(string), d.Get("name_prefix").(string)) } - log.Printf("[DEBUG] SQS queue create: %s", name) - - req := &sqs.CreateQueueInput{ + input := &sqs.CreateQueueInput{ QueueName: aws.String(name), } + attributes, err := sqsQueueAttributeMap.ResourceDataToApiAttributesCreate(d) + + if err != nil { + return err + } + + input.Attributes = aws.StringMap(attributes) + // Tag-on-create is currently only supported in AWS Commercial if len(tags) > 0 && meta.(*AWSClient).partition == endpoints.AwsPartitionID { - req.Tags = tags.IgnoreAws().SqsTags() + input.Tags = tags.IgnoreAws().SqsTags() } - attributes := make(map[string]*string) - - queueResource := *resourceAwsSqsQueue() + log.Printf("[DEBUG] Creating SQS Queue: %s", input) + var output *sqs.CreateQueueOutput + err = resource.Retry(waiter.QueueCreatedTimeout, func() *resource.RetryError { + var err error - for k, s := range queueResource.Schema { - if attrKey, ok := sqsQueueAttributeMap[k]; ok { - if value, ok := d.GetOk(k); ok { - switch s.Type { - case schema.TypeInt: - attributes[attrKey] = aws.String(strconv.Itoa(value.(int))) - case schema.TypeBool: - attributes[attrKey] = aws.String(strconv.FormatBool(value.(bool))) - default: - attributes[attrKey] = aws.String(value.(string)) - } - } + output, err = conn.CreateQueue(input) + if tfawserr.ErrCodeEquals(err, sqs.ErrCodeQueueDeletedRecently) { + return resource.RetryableError(err) } - } - - if len(attributes) > 0 { - req.Attributes = attributes - } - var output *sqs.CreateQueueOutput - err := resource.Retry(70*time.Second, func() *resource.RetryError { - var err error - output, err = sqsconn.CreateQueue(req) if err != nil { - if isAWSErr(err, sqs.ErrCodeQueueDeletedRecently, "You must wait 60 seconds after deleting a queue before you can create another with the same name.") { - return resource.RetryableError(err) - } return resource.NonRetryableError(err) } + return nil }) - if isResourceTimeoutError(err) { - output, err = sqsconn.CreateQueue(req) + + if tfresource.TimedOut(err) { + output, err = conn.CreateQueue(input) } + if err != nil { - return fmt.Errorf("Error creating SQS queue: %s", err) + return fmt.Errorf("error creating SQS Queue (%s): %w", name, err) } d.SetId(aws.StringValue(output.QueueUrl)) // Tag-on-create is currently only supported in AWS Commercial - if meta.(*AWSClient).partition == endpoints.AwsPartitionID { - return resourceAwsSqsQueueRead(d, meta) - } else { - return resourceAwsSqsQueueUpdate(d, meta) - } -} - -func resourceAwsSqsQueueUpdate(d *schema.ResourceData, meta interface{}) error { - sqsconn := meta.(*AWSClient).sqsconn - - if d.HasChange("tags_all") { - o, n := d.GetChange("tags_all") - - if err := keyvaluetags.SqsUpdateTags(sqsconn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating SQS Queue (%s) tags: %s", d.Id(), err) - } - } - - attributes := make(map[string]*string) - - resource := *resourceAwsSqsQueue() - - for k, s := range resource.Schema { - if attrKey, ok := sqsQueueAttributeMap[k]; ok { - if d.HasChange(k) { - log.Printf("[DEBUG] Updating %s", attrKey) - _, n := d.GetChange(k) - switch s.Type { - case schema.TypeInt: - attributes[attrKey] = aws.String(strconv.Itoa(n.(int))) - case schema.TypeBool: - attributes[attrKey] = aws.String(strconv.FormatBool(n.(bool))) - default: - attributes[attrKey] = aws.String(n.(string)) - } - } - } - } - - if len(attributes) > 0 { - req := &sqs.SetQueueAttributesInput{ - QueueUrl: aws.String(d.Id()), - Attributes: attributes, - } - if _, err := sqsconn.SetQueueAttributes(req); err != nil { - return fmt.Errorf("Error updating SQS attributes: %s", err) + if len(tags) > 0 && meta.(*AWSClient).partition != endpoints.AwsPartitionID { + if err := keyvaluetags.SqsUpdateTags(conn, d.Id(), nil, tags); err != nil { + return fmt.Errorf("error updating SQS Queue (%s) tags: %w", d.Id(), err) } } @@ -281,28 +227,24 @@ func resourceAwsSqsQueueUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { - sqsconn := meta.(*AWSClient).sqsconn + conn := meta.(*AWSClient).sqsconn defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - attributeOutput, err := sqsconn.GetQueueAttributes(&sqs.GetQueueAttributesInput{ - QueueUrl: aws.String(d.Id()), - AttributeNames: []*string{aws.String("All")}, - }) + output, err := finder.QueueAttributesByURL(conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] SQS Queue (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } if err != nil { - if awsErr, ok := err.(awserr.Error); ok { - log.Printf("ERROR Found %s", awsErr.Code()) - if awsErr.Code() == sqs.ErrCodeQueueDoesNotExist { - d.SetId("") - log.Printf("[DEBUG] SQS Queue (%s) not found", d.Get("name").(string)) - return nil - } - } - return err + return fmt.Errorf("error reading SQS Queue (%s): %w", d.Id(), err) } - name, err := extractNameFromSqsQueueUrl(d.Id()) + name, err := tfsqs.QueueNameFromURL(d.Id()) + if err != nil { return err } @@ -324,114 +266,114 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { d.Set("deduplication_scope", "") d.Set("fifo_throughput_limit", "") - if attributeOutput != nil { - queueAttributes := aws.StringValueMap(attributeOutput.Attributes) + // if attributeOutput != nil { + queueAttributes := output - if v, ok := queueAttributes[sqs.QueueAttributeNameQueueArn]; ok { - d.Set("arn", v) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameContentBasedDeduplication]; ok && v != "" { - vBool, err := strconv.ParseBool(v) + if v, ok := queueAttributes[sqs.QueueAttributeNameQueueArn]; ok { + d.Set("arn", v) + } - if err != nil { - return fmt.Errorf("error parsing content_based_deduplication value (%s) into boolean: %s", v, err) - } + if v, ok := queueAttributes[sqs.QueueAttributeNameContentBasedDeduplication]; ok && v != "" { + vBool, err := strconv.ParseBool(v) - d.Set("content_based_deduplication", vBool) + if err != nil { + return fmt.Errorf("error parsing content_based_deduplication value (%s) into boolean: %s", v, err) } - if v, ok := queueAttributes[sqs.QueueAttributeNameDelaySeconds]; ok && v != "" { - vInt, err := strconv.Atoi(v) + d.Set("content_based_deduplication", vBool) + } - if err != nil { - return fmt.Errorf("error parsing delay_seconds value (%s) into integer: %s", v, err) - } + if v, ok := queueAttributes[sqs.QueueAttributeNameDelaySeconds]; ok && v != "" { + vInt, err := strconv.Atoi(v) - d.Set("delay_seconds", vInt) + if err != nil { + return fmt.Errorf("error parsing delay_seconds value (%s) into integer: %s", v, err) } - if v, ok := queueAttributes[sqs.QueueAttributeNameFifoQueue]; ok && v != "" { - vBool, err := strconv.ParseBool(v) + d.Set("delay_seconds", vInt) + } - if err != nil { - return fmt.Errorf("error parsing fifo_queue value (%s) into boolean: %s", v, err) - } + if v, ok := queueAttributes[sqs.QueueAttributeNameFifoQueue]; ok && v != "" { + vBool, err := strconv.ParseBool(v) - fifoQueue = vBool + if err != nil { + return fmt.Errorf("error parsing fifo_queue value (%s) into boolean: %s", v, err) } - if v, ok := queueAttributes[sqs.QueueAttributeNameKmsDataKeyReusePeriodSeconds]; ok && v != "" { - vInt, err := strconv.Atoi(v) + fifoQueue = vBool + } - if err != nil { - return fmt.Errorf("error parsing kms_data_key_reuse_period_seconds value (%s) into integer: %s", v, err) - } + if v, ok := queueAttributes[sqs.QueueAttributeNameKmsDataKeyReusePeriodSeconds]; ok && v != "" { + vInt, err := strconv.Atoi(v) - d.Set("kms_data_key_reuse_period_seconds", vInt) + if err != nil { + return fmt.Errorf("error parsing kms_data_key_reuse_period_seconds value (%s) into integer: %s", v, err) } - if v, ok := queueAttributes[sqs.QueueAttributeNameKmsMasterKeyId]; ok { - d.Set("kms_master_key_id", v) - } + d.Set("kms_data_key_reuse_period_seconds", vInt) + } - if v, ok := queueAttributes[sqs.QueueAttributeNameMaximumMessageSize]; ok && v != "" { - vInt, err := strconv.Atoi(v) + if v, ok := queueAttributes[sqs.QueueAttributeNameKmsMasterKeyId]; ok { + d.Set("kms_master_key_id", v) + } - if err != nil { - return fmt.Errorf("error parsing max_message_size value (%s) into integer: %s", v, err) - } + if v, ok := queueAttributes[sqs.QueueAttributeNameMaximumMessageSize]; ok && v != "" { + vInt, err := strconv.Atoi(v) - d.Set("max_message_size", vInt) + if err != nil { + return fmt.Errorf("error parsing max_message_size value (%s) into integer: %s", v, err) } - if v, ok := queueAttributes[sqs.QueueAttributeNameMessageRetentionPeriod]; ok && v != "" { - vInt, err := strconv.Atoi(v) + d.Set("max_message_size", vInt) + } - if err != nil { - return fmt.Errorf("error parsing message_retention_seconds value (%s) into integer: %s", v, err) - } + if v, ok := queueAttributes[sqs.QueueAttributeNameMessageRetentionPeriod]; ok && v != "" { + vInt, err := strconv.Atoi(v) - d.Set("message_retention_seconds", vInt) + if err != nil { + return fmt.Errorf("error parsing message_retention_seconds value (%s) into integer: %s", v, err) } - if v, ok := queueAttributes[sqs.QueueAttributeNamePolicy]; ok { - d.Set("policy", v) - } + d.Set("message_retention_seconds", vInt) + } - if v, ok := queueAttributes[sqs.QueueAttributeNameReceiveMessageWaitTimeSeconds]; ok && v != "" { - vInt, err := strconv.Atoi(v) + if v, ok := queueAttributes[sqs.QueueAttributeNamePolicy]; ok { + d.Set("policy", v) + } - if err != nil { - return fmt.Errorf("error parsing receive_wait_time_seconds value (%s) into integer: %s", v, err) - } + if v, ok := queueAttributes[sqs.QueueAttributeNameReceiveMessageWaitTimeSeconds]; ok && v != "" { + vInt, err := strconv.Atoi(v) - d.Set("receive_wait_time_seconds", vInt) + if err != nil { + return fmt.Errorf("error parsing receive_wait_time_seconds value (%s) into integer: %s", v, err) } - if v, ok := queueAttributes[sqs.QueueAttributeNameRedrivePolicy]; ok { - d.Set("redrive_policy", v) - } + d.Set("receive_wait_time_seconds", vInt) + } - if v, ok := queueAttributes[sqs.QueueAttributeNameVisibilityTimeout]; ok && v != "" { - vInt, err := strconv.Atoi(v) + if v, ok := queueAttributes[sqs.QueueAttributeNameRedrivePolicy]; ok { + d.Set("redrive_policy", v) + } - if err != nil { - return fmt.Errorf("error parsing visibility_timeout_seconds value (%s) into integer: %s", v, err) - } + if v, ok := queueAttributes[sqs.QueueAttributeNameVisibilityTimeout]; ok && v != "" { + vInt, err := strconv.Atoi(v) - d.Set("visibility_timeout_seconds", vInt) + if err != nil { + return fmt.Errorf("error parsing visibility_timeout_seconds value (%s) into integer: %s", v, err) } - if v, ok := queueAttributes[sqs.QueueAttributeNameDeduplicationScope]; ok && v != "" { - d.Set("deduplication_scope", v) - } + d.Set("visibility_timeout_seconds", vInt) + } - if v, ok := queueAttributes[sqs.QueueAttributeNameFifoThroughputLimit]; ok && v != "" { - d.Set("fifo_throughput_limit", v) - } + if v, ok := queueAttributes[sqs.QueueAttributeNameDeduplicationScope]; ok && v != "" { + d.Set("deduplication_scope", v) } + if v, ok := queueAttributes[sqs.QueueAttributeNameFifoThroughputLimit]; ok && v != "" { + d.Set("fifo_throughput_limit", v) + } + // } + d.Set("fifo_queue", fifoQueue) d.Set("name", name) if fifoQueue { @@ -440,14 +382,14 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { d.Set("name_prefix", naming.NamePrefixFromName(name)) } - tags, err := keyvaluetags.SqsListTags(sqsconn, d.Id()) + tags, err := keyvaluetags.SqsListTags(conn, d.Id()) if err != nil { // Non-standard partitions (e.g. US Gov) and some local development // solutions do not yet support this API call. Depending on the // implementation it may return InvalidAction or AWS.SimpleQueueService.UnsupportedOperation - if !isAWSErr(err, "InvalidAction", "") && !isAWSErr(err, sqs.ErrCodeUnsupportedOperation, "") { - return fmt.Errorf("error listing tags for SQS Queue (%s): %s", d.Id(), err) + if !tfawserr.ErrCodeEquals(err, tfsqs.ErrCodeInvalidAction) && !tfawserr.ErrCodeEquals(err, sqs.ErrCodeUnsupportedOperation) { + return fmt.Errorf("error listing tags for SQS Queue (%s): %w", d.Id(), err) } } @@ -465,11 +407,44 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { return nil } +func resourceAwsSqsQueueUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).sqsconn + + if d.HasChangesExcept("tags", "tags_all") { + attributes, err := sqsQueueAttributeMap.ResourceDataToApiAttributesUpdate(d) + + if err != nil { + return err + } + + input := &sqs.SetQueueAttributesInput{ + Attributes: aws.StringMap(attributes), + QueueUrl: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Updating SQS Queue: %s", input) + _, err = conn.SetQueueAttributes(input) + + if err != nil { + return fmt.Errorf("error updating SQS Queue (%s) attributes: %w", d.Id(), err) + } + } + + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + if err := keyvaluetags.SqsUpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating SQS Queue (%s) tags: %w", d.Id(), err) + } + } + + return resourceAwsSqsQueueRead(d, meta) +} + func resourceAwsSqsQueueDelete(d *schema.ResourceData, meta interface{}) error { - sqsconn := meta.(*AWSClient).sqsconn + conn := meta.(*AWSClient).sqsconn log.Printf("[DEBUG] Deleting SQS Queue: %s", d.Id()) - _, err := sqsconn.DeleteQueue(&sqs.DeleteQueueInput{ + _, err := conn.DeleteQueue(&sqs.DeleteQueueInput{ QueueUrl: aws.String(d.Id()), }) @@ -481,7 +456,13 @@ func resourceAwsSqsQueueDelete(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error deleting SQS Queue (%s): %w", d.Id(), err) } - return err + err = waiter.QueueDeleted(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for SQS Queue (%s) to delete: %w", d.Id(), err) + } + + return nil } func resourceAwsSqsQueueCustomizeDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error { @@ -519,18 +500,3 @@ func resourceAwsSqsQueueCustomizeDiff(_ context.Context, diff *schema.ResourceDi return nil } - -func extractNameFromSqsQueueUrl(queue string) (string, error) { - //http://sqs.us-west-2.amazonaws.com/123456789012/queueName - u, err := url.Parse(queue) - if err != nil { - return "", err - } - segments := strings.Split(u.Path, "/") - if len(segments) != 3 { - return "", fmt.Errorf("SQS Url not parsed correctly") - } - - return segments[2], nil - -} diff --git a/aws/resource_aws_sqs_queue_policy_test.go b/aws/resource_aws_sqs_queue_policy_test.go index 11b8f863c4a7..727fefc61855 100644 --- a/aws/resource_aws_sqs_queue_policy_test.go +++ b/aws/resource_aws_sqs_queue_policy_test.go @@ -11,7 +11,7 @@ import ( ) func TestAccAWSSQSQueuePolicy_basic(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue_policy.test" queueResourceName := "aws_sqs_queue.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -47,7 +47,7 @@ func TestAccAWSSQSQueuePolicy_basic(t *testing.T) { } func TestAccAWSSQSQueuePolicy_disappears_queue(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string queueResourceName := "aws_sqs_queue.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -70,7 +70,7 @@ func TestAccAWSSQSQueuePolicy_disappears_queue(t *testing.T) { } func TestAccAWSSQSQueuePolicy_disappears(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue_policy.test" queueResourceName := "aws_sqs_queue.test" rName := acctest.RandomWithPrefix("tf-acc-test") diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index 6ed6dffbafb8..d4ac64ea6ae8 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -79,7 +79,7 @@ func testSweepSqsQueues(region string) error { } func TestAccAWSSQSQueue_basic(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) @@ -135,7 +135,7 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { } func TestAccAWSSQSQueue_disappears(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -158,7 +158,7 @@ func TestAccAWSSQSQueue_disappears(t *testing.T) { } func TestAccAWSSQSQueue_tags(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) @@ -216,7 +216,7 @@ func TestAccAWSSQSQueue_tags(t *testing.T) { } func TestAccAWSSQSQueue_Name_Generated(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.test" resource.ParallelTest(t, resource.TestCase{ @@ -249,7 +249,7 @@ func TestAccAWSSQSQueue_Name_Generated(t *testing.T) { } func TestAccAWSSQSQueue_Name_Generated_FIFOQueue(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.test" resource.ParallelTest(t, resource.TestCase{ @@ -282,7 +282,7 @@ func TestAccAWSSQSQueue_Name_Generated_FIFOQueue(t *testing.T) { } func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.test" rName := "tf-acc-test-prefix-" @@ -316,7 +316,7 @@ func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { } func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.test" rName := "tf-acc-test-prefix-" @@ -350,7 +350,7 @@ func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { } func TestAccAWSSQSQueue_policy(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.test-email-events" queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) topicName := fmt.Sprintf("sns-topic-%s", acctest.RandString(10)) @@ -378,7 +378,7 @@ func TestAccAWSSQSQueue_policy(t *testing.T) { } func TestAccAWSSQSQueue_queueDeletedRecently(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) @@ -416,7 +416,7 @@ func TestAccAWSSQSQueue_queueDeletedRecently(t *testing.T) { } func TestAccAWSSQSQueue_redrivePolicy(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.my_dead_letter_queue" resource.ParallelTest(t, resource.TestCase{ @@ -447,7 +447,7 @@ func TestAccAWSSQSQueue_redrivePolicy(t *testing.T) { // Tests formatting and compacting of Policy, Redrive json func TestAccAWSSQSQueue_Policybasic(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.test-email-events" queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) topicName := fmt.Sprintf("sns-topic-%s", acctest.RandString(10)) @@ -479,7 +479,7 @@ func TestAccAWSSQSQueue_Policybasic(t *testing.T) { } func TestAccAWSSQSQueue_FIFO(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" resource.ParallelTest(t, resource.TestCase{ @@ -522,7 +522,7 @@ func TestAccAWSSQSQueue_FIFOExpectNameError(t *testing.T) { } func TestAccAWSSQSQueue_FIFOWithContentBasedDeduplication(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" resource.ParallelTest(t, resource.TestCase{ @@ -549,7 +549,7 @@ func TestAccAWSSQSQueue_FIFOWithContentBasedDeduplication(t *testing.T) { } func TestAccAWSSQSQueue_FIFOWithHighThroughputMode(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" queueName := acctest.RandString(10) @@ -567,7 +567,6 @@ func TestAccAWSSQSQueue_FIFOWithHighThroughputMode(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), resource.TestCheckResourceAttr(resourceName, "deduplication_scope", "queue"), resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", "perQueue"), - testAccCheckAWSSQSFIFOQueueHighThroughputAttributes(&queueAttributes, "queue", "perQueue"), ), }, { @@ -581,14 +580,8 @@ func TestAccAWSSQSQueue_FIFOWithHighThroughputMode(t *testing.T) { testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), resource.TestCheckResourceAttr(resourceName, "deduplication_scope", "messageGroup"), resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", "perMessageGroupId"), - testAccCheckAWSSQSFIFOQueueHighThroughputAttributes(&queueAttributes, "messageGroup", "perMessageGroupId"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, }, }) } @@ -609,7 +602,7 @@ func TestAccAWSSQSQueue_ExpectContentBasedDeduplicationError(t *testing.T) { } func TestAccAWSSQSQueue_Encryption(t *testing.T) { - var queueAttributes map[string]*string + var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" resource.ParallelTest(t, resource.TestCase{ @@ -634,7 +627,7 @@ func TestAccAWSSQSQueue_Encryption(t *testing.T) { }) } -func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]*string, topicName, queueName string) resource.TestCheckFunc { +func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]string, topicName, queueName string) resource.TestCheckFunc { return func(s *terraform.State) error { accountID := testAccProvider.Meta().(*AWSClient).accountid @@ -642,9 +635,9 @@ func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]*string, expectedPolicyText := fmt.Sprintf(expectedPolicyFormat, testAccGetPartition(), testAccGetRegion(), accountID, topicName, queueName) var actualPolicyText string - for key, valuePointer := range *queueAttributes { - if key == "Policy" { - actualPolicyText = aws.StringValue(valuePointer) + for key, value := range *queueAttributes { + if key == sqs.QueueAttributeNamePolicy { + actualPolicyText = value break } } @@ -662,7 +655,7 @@ func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]*string, } } -func testAccCheckAWSSQSQueueExists(resourceName string, v *map[string]*string) resource.TestCheckFunc { +func testAccCheckAWSSQSQueueExists(resourceName string, v *map[string]string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { From 6e2da23dc4f97c663082fab0938841df3b164255 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 4 Jun 2021 16:48:34 -0700 Subject: [PATCH 0254/1208] Adds function to format tags as URL query string without URL encoding --- aws/internal/keyvaluetags/key_value_tags.go | 24 ++++++++ .../keyvaluetags/key_value_tags_test.go | 56 +++++++++++++++++++ aws/resource_aws_iot_topic_rule.go | 2 +- aws/resource_aws_iot_topic_rule_test.go | 8 +-- 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/aws/internal/keyvaluetags/key_value_tags.go b/aws/internal/keyvaluetags/key_value_tags.go index 726087c5c3db..e22c61cac08c 100644 --- a/aws/internal/keyvaluetags/key_value_tags.go +++ b/aws/internal/keyvaluetags/key_value_tags.go @@ -500,6 +500,30 @@ func (tags KeyValueTags) UrlEncode() string { return values.Encode() } +// UrlQueryString returns the KeyValueTags formatted as URL Query parameters without encoding. +func (tags KeyValueTags) UrlQueryString() string { + keys := make([]string, 0, len(tags)) + for k, v := range tags { + if v == nil || v.Value == nil { + continue + } + keys = append(keys, k) + } + sort.Strings(keys) + + var buf strings.Builder + for _, k := range keys { + if buf.Len() > 0 { + buf.WriteByte('&') + } + buf.WriteString(k) + buf.WriteByte('=') + buf.WriteString(*tags[k].Value) + } + + return buf.String() +} + // New creates KeyValueTags from common types or returns an empty KeyValueTags. // // Supports various Terraform Plugin SDK types including map[string]string, diff --git a/aws/internal/keyvaluetags/key_value_tags_test.go b/aws/internal/keyvaluetags/key_value_tags_test.go index 15bef961be42..ef432d1afbc8 100644 --- a/aws/internal/keyvaluetags/key_value_tags_test.go +++ b/aws/internal/keyvaluetags/key_value_tags_test.go @@ -2050,6 +2050,62 @@ func TestKeyValueTagsUrlEncode(t *testing.T) { } } +func TestKeyValueTagsUrlQueryString(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want string + }{ + { + name: "empty", + tags: New(map[string]string{}), + want: "", + }, + { + name: "nil value", + tags: New(map[string]*string{ + "key1": nil, + }), + want: "", + }, + { + name: "single", + tags: New(map[string]string{ + "key1": "value1", + }), + want: "key1=value1", + }, + { + name: "multiple", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: "key1=value1&key2=value2&key3=value3", + }, + { + name: "multiple_with_encoded", + tags: New(map[string]string{ + "key1": "value 1", + "key@2": "value+:2", + "key3": "value3", + }), + want: "key1=value 1&key3=value3&key@2=value+:2", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.UrlQueryString() + + if got != testCase.want { + t.Errorf("unexpected query string value: %q", got) + } + }) + } +} + func TestNew(t *testing.T) { testCases := []struct { name string diff --git a/aws/resource_aws_iot_topic_rule.go b/aws/resource_aws_iot_topic_rule.go index c7142f7f532d..e9820d21292b 100644 --- a/aws/resource_aws_iot_topic_rule.go +++ b/aws/resource_aws_iot_topic_rule.go @@ -1090,7 +1090,7 @@ func resourceAwsIotTopicRuleCreate(d *schema.ResourceData, meta interface{}) err input := &iot.CreateTopicRuleInput{ RuleName: aws.String(ruleName), - Tags: aws.String(tags.IgnoreAws().UrlEncode()), + Tags: aws.String(tags.IgnoreAws().UrlQueryString()), TopicRulePayload: expandIotTopicRulePayload(d), } diff --git a/aws/resource_aws_iot_topic_rule_test.go b/aws/resource_aws_iot_topic_rule_test.go index 061162aab9d7..49a1bd2a79b6 100644 --- a/aws/resource_aws_iot_topic_rule_test.go +++ b/aws/resource_aws_iot_topic_rule_test.go @@ -528,11 +528,11 @@ func TestAccAWSIoTTopicRule_Tags(t *testing.T) { CheckDestroy: testAccCheckAWSIoTTopicRuleDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSIoTTopicRuleTags1(rName, "key1", "value1"), + Config: testAccAWSIoTTopicRuleTags1(rName, "key1", "user@example"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSIoTTopicRuleExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "user@example"), ), }, { @@ -541,11 +541,11 @@ func TestAccAWSIoTTopicRule_Tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSIoTTopicRuleTags2(rName, "key1", "value1updated", "key2", "value2"), + Config: testAccAWSIoTTopicRuleTags2(rName, "key1", "user@example", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSIoTTopicRuleExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "user@example"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, From ed6c241eb49adfc39bc068a56c4cf13047a5c06b Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 4 Jun 2021 16:49:11 -0700 Subject: [PATCH 0255/1208] Validate S3 bucket object tags with '@' --- aws/resource_aws_s3_bucket_object_test.go | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_s3_bucket_object_test.go b/aws/resource_aws_s3_bucket_object_test.go index 805a57a470d3..f88b4283918b 100644 --- a/aws/resource_aws_s3_bucket_object_test.go +++ b/aws/resource_aws_s3_bucket_object_test.go @@ -677,7 +677,7 @@ func TestAccAWSS3BucketObject_tags(t *testing.T) { testAccCheckAWSS3BucketObjectExists(resourceName, &obj1), testAccCheckAWSS3BucketObjectBody(&obj1, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"), ), @@ -690,7 +690,7 @@ func TestAccAWSS3BucketObject_tags(t *testing.T) { testAccCheckAWSS3BucketObjectVersionIdEquals(&obj2, &obj1), testAccCheckAWSS3BucketObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "4"), - resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), + resource.TestCheckResourceAttr(resourceName, "tags.Key2", "B@BB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "X X"), resource.TestCheckResourceAttr(resourceName, "tags.Key4", "DDD"), resource.TestCheckResourceAttr(resourceName, "tags.Key5", "E:/"), @@ -714,7 +714,7 @@ func TestAccAWSS3BucketObject_tags(t *testing.T) { testAccCheckAWSS3BucketObjectVersionIdDiffers(&obj4, &obj3), testAccCheckAWSS3BucketObjectBody(&obj4, "changed stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"), ), @@ -742,7 +742,7 @@ func TestAccAWSS3BucketObject_tagsLeadingSingleSlash(t *testing.T) { testAccCheckAWSS3BucketObjectExists(resourceName, &obj1), testAccCheckAWSS3BucketObjectBody(&obj1, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"), ), @@ -755,7 +755,7 @@ func TestAccAWSS3BucketObject_tagsLeadingSingleSlash(t *testing.T) { testAccCheckAWSS3BucketObjectVersionIdEquals(&obj2, &obj1), testAccCheckAWSS3BucketObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "4"), - resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), + resource.TestCheckResourceAttr(resourceName, "tags.Key2", "B@BB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "X X"), resource.TestCheckResourceAttr(resourceName, "tags.Key4", "DDD"), resource.TestCheckResourceAttr(resourceName, "tags.Key5", "E:/"), @@ -779,7 +779,7 @@ func TestAccAWSS3BucketObject_tagsLeadingSingleSlash(t *testing.T) { testAccCheckAWSS3BucketObjectVersionIdDiffers(&obj4, &obj3), testAccCheckAWSS3BucketObjectBody(&obj4, "changed stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"), ), @@ -807,7 +807,7 @@ func TestAccAWSS3BucketObject_tagsLeadingMultipleSlashes(t *testing.T) { testAccCheckAWSS3BucketObjectExists(resourceName, &obj1), testAccCheckAWSS3BucketObjectBody(&obj1, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"), ), @@ -820,7 +820,7 @@ func TestAccAWSS3BucketObject_tagsLeadingMultipleSlashes(t *testing.T) { testAccCheckAWSS3BucketObjectVersionIdEquals(&obj2, &obj1), testAccCheckAWSS3BucketObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "4"), - resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), + resource.TestCheckResourceAttr(resourceName, "tags.Key2", "B@BB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "X X"), resource.TestCheckResourceAttr(resourceName, "tags.Key4", "DDD"), resource.TestCheckResourceAttr(resourceName, "tags.Key5", "E:/"), @@ -844,7 +844,7 @@ func TestAccAWSS3BucketObject_tagsLeadingMultipleSlashes(t *testing.T) { testAccCheckAWSS3BucketObjectVersionIdDiffers(&obj4, &obj3), testAccCheckAWSS3BucketObjectBody(&obj4, "changed stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"), ), @@ -872,7 +872,7 @@ func TestAccAWSS3BucketObject_tagsMultipleSlashes(t *testing.T) { testAccCheckAWSS3BucketObjectExists(resourceName, &obj1), testAccCheckAWSS3BucketObjectBody(&obj1, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"), ), @@ -885,7 +885,7 @@ func TestAccAWSS3BucketObject_tagsMultipleSlashes(t *testing.T) { testAccCheckAWSS3BucketObjectVersionIdEquals(&obj2, &obj1), testAccCheckAWSS3BucketObjectBody(&obj2, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "4"), - resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), + resource.TestCheckResourceAttr(resourceName, "tags.Key2", "B@BB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "X X"), resource.TestCheckResourceAttr(resourceName, "tags.Key4", "DDD"), resource.TestCheckResourceAttr(resourceName, "tags.Key5", "E:/"), @@ -909,7 +909,7 @@ func TestAccAWSS3BucketObject_tagsMultipleSlashes(t *testing.T) { testAccCheckAWSS3BucketObjectVersionIdDiffers(&obj4, &obj3), testAccCheckAWSS3BucketObjectBody(&obj4, "changed stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"), ), @@ -1707,7 +1707,7 @@ resource "aws_s3_bucket_object" "object" { content = %[3]q tags = { - Key1 = "AAA" + Key1 = "A@AA" Key2 = "BBB" Key3 = "CCC" } @@ -1731,7 +1731,7 @@ resource "aws_s3_bucket_object" "object" { content = %[3]q tags = { - Key2 = "BBB" + Key2 = "B@BB" Key3 = "X X" Key4 = "DDD" Key5 = "E:/" From cc2a072e74af99b20c7d0384f67c64d1fa65f9e2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 6 Jun 2021 16:29:34 -0400 Subject: [PATCH 0256/1208] r/aws_sqs_queue: Add argument validation. --- aws/internal/service/sqs/consts.go | 4 +- aws/internal/service/sqs/waiter/waiter.go | 14 +- aws/resource_aws_sqs_queue.go | 139 ++++++++++-------- aws/resource_aws_sqs_queue_test.go | 165 +++++++++------------- 4 files changed, 163 insertions(+), 159 deletions(-) diff --git a/aws/internal/service/sqs/consts.go b/aws/internal/service/sqs/consts.go index 33ac3d6259b0..d0c8a08e9c99 100644 --- a/aws/internal/service/sqs/consts.go +++ b/aws/internal/service/sqs/consts.go @@ -11,8 +11,8 @@ const ( const ( DefaultQueueDelaySeconds = 0 DefaultQueueKmsDataKeyReusePeriodSeconds = 300 - DefaultQueueMaximumMessageSize = 262144 - DefaultQueueMessageRetentionPeriod = 345600 + DefaultQueueMaximumMessageSize = 262_144 // 256 KiB. + DefaultQueueMessageRetentionPeriod = 345_600 // 4 days. DefaultQueueReceiveMessageWaitTimeSeconds = 0 DefaultQueueVisibilityTimeout = 30 ) diff --git a/aws/internal/service/sqs/waiter/waiter.go b/aws/internal/service/sqs/waiter/waiter.go index b580683fa90f..8cb3563fe6c2 100644 --- a/aws/internal/service/sqs/waiter/waiter.go +++ b/aws/internal/service/sqs/waiter/waiter.go @@ -1,7 +1,7 @@ package waiter import ( - "fmt" + "errors" "time" "github.com/aws/aws-sdk-go/service/sqs" @@ -25,6 +25,10 @@ const ( QueueDeletedTimeout = 15 * time.Second ) +var ( + queueStillExistsError = errors.New("SQS Queue still exists") +) + func QueueDeleted(conn *sqs.SQS, url string) error { err := resource.Retry(QueueDeletedTimeout, func() *resource.RetryError { var err error @@ -39,14 +43,18 @@ func QueueDeleted(conn *sqs.SQS, url string) error { return resource.NonRetryableError(err) } - return resource.RetryableError(fmt.Errorf("SQS Queue (%s) still exists", url)) + return resource.RetryableError(queueStillExistsError) }) if tfresource.TimedOut(err) { _, err = finder.QueueAttributesByURL(conn, url) + if err == nil { + return queueStillExistsError + } + if tfresource.NotFound(err) { - return nil + err = nil } } diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index 76031eee8bf4..9a1a4f9a9143 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -60,6 +60,71 @@ func resourceAwsSqsQueue() *schema.Resource { ), Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + + "content_based_deduplication": { + Type: schema.TypeBool, + Default: false, + Optional: true, + }, + + "deduplication_scope": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(tfsqs.DeduplicationScope_Values(), false), + }, + + "delay_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: tfsqs.DefaultQueueDelaySeconds, + ValidateFunc: validation.IntBetween(0, 900), + }, + + "fifo_queue": { + Type: schema.TypeBool, + Default: false, + ForceNew: true, + Optional: true, + }, + + "fifo_throughput_limit": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(tfsqs.FifoThroughputLimit_Values(), false), + }, + + "kms_data_key_reuse_period_seconds": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + ValidateFunc: validation.IntBetween(60, 86_400), + }, + + "kms_master_key_id": { + Type: schema.TypeString, + Optional: true, + }, + + "max_message_size": { + Type: schema.TypeInt, + Optional: true, + Default: tfsqs.DefaultQueueMaximumMessageSize, + ValidateFunc: validation.IntBetween(1024, 262_144), + }, + + "message_retention_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: tfsqs.DefaultQueueMessageRetentionPeriod, + ValidateFunc: validation.IntBetween(60, 1_209_600), + }, + "name": { Type: schema.TypeString, Optional: true, @@ -67,6 +132,7 @@ func resourceAwsSqsQueue() *schema.Resource { ForceNew: true, ConflictsWith: []string{"name_prefix"}, }, + "name_prefix": { Type: schema.TypeString, Optional: true, @@ -74,31 +140,7 @@ func resourceAwsSqsQueue() *schema.Resource { ForceNew: true, ConflictsWith: []string{"name"}, }, - "delay_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: tfsqs.DefaultQueueDelaySeconds, - }, - "max_message_size": { - Type: schema.TypeInt, - Optional: true, - Default: tfsqs.DefaultQueueMaximumMessageSize, - }, - "message_retention_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: tfsqs.DefaultQueueMessageRetentionPeriod, - }, - "receive_wait_time_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds, - }, - "visibility_timeout_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: tfsqs.DefaultQueueVisibilityTimeout, - }, + "policy": { Type: schema.TypeString, Optional: true, @@ -106,6 +148,13 @@ func resourceAwsSqsQueue() *schema.Resource { ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs, }, + + "receive_wait_time_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds, + }, + "redrive_policy": { Type: schema.TypeString, Optional: true, @@ -115,42 +164,14 @@ func resourceAwsSqsQueue() *schema.Resource { return json }, }, - "arn": { - Type: schema.TypeString, - Computed: true, - }, - "fifo_queue": { - Type: schema.TypeBool, - Default: false, - ForceNew: true, - Optional: true, - }, - "content_based_deduplication": { - Type: schema.TypeBool, - Default: false, - Optional: true, - }, - "kms_master_key_id": { - Type: schema.TypeString, - Optional: true, - }, - "kms_data_key_reuse_period_seconds": { - Type: schema.TypeInt, - Computed: true, - Optional: true, - }, - "deduplication_scope": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice(tfsqs.DeduplicationScope_Values(), false), - }, - "fifo_throughput_limit": { - Type: schema.TypeString, + + "visibility_timeout_seconds": { + Type: schema.TypeInt, Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice(tfsqs.FifoThroughputLimit_Values(), false), + Default: tfsqs.DefaultQueueVisibilityTimeout, + ValidateFunc: validation.IntBetween(0, 43_200), }, + "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), }, diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index d4ac64ea6ae8..d03553083d98 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -81,7 +81,7 @@ func testSweepSqsQueues(region string) error { func TestAccAWSSQSQueue_basic(t *testing.T) { var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" - queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -90,17 +90,26 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigWithDefaults(queueName), - Check: resource.ComposeTestCheckFunc( + Config: testAccAWSSQSConfigName(rName), + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "sqs", rName), + resource.TestCheckResourceAttr(resourceName, "content_based_deduplication", "false"), + resource.TestCheckResourceAttr(resourceName, "deduplication_scope", ""), resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), + resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", strconv.Itoa(tfsqs.DefaultQueueKmsDataKeyReusePeriodSeconds)), + resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", ""), resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "name_prefix", ""), + resource.TestCheckResourceAttr(resourceName, "policy", ""), resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "redrive_policy", ""), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), - // These two should only be set for FIFO queues. - resource.TestCheckResourceAttr(resourceName, "deduplication_scope", ""), - resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), ), }, { @@ -109,7 +118,7 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSSQSConfigWithOverrides(queueName), + Config: testAccAWSSQSConfigWithOverrides(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), resource.TestCheckResourceAttr(resourceName, "delay_seconds", "90"), @@ -120,7 +129,7 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { ), }, { - Config: testAccAWSSQSConfigWithDefaults(queueName), + Config: testAccAWSSQSConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), @@ -146,7 +155,7 @@ func TestAccAWSSQSQueue_disappears(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigWithDefaults(rName), + Config: testAccAWSSQSConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueue(), resourceName), @@ -157,10 +166,10 @@ func TestAccAWSSQSQueue_disappears(t *testing.T) { }) } -func TestAccAWSSQSQueue_tags(t *testing.T) { +func TestAccAWSSQSQueue_Tags(t *testing.T) { var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" - queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -169,16 +178,11 @@ func TestAccAWSSQSQueue_tags(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigWithTags(queueName), + Config: testAccAWSSQSConfigTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.Usage", "original"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { @@ -187,28 +191,20 @@ func TestAccAWSSQSQueue_tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSSQSConfigWithTagsChanged(queueName), + Config: testAccAWSSQSConfigTags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Usage", "changed"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, { - Config: testAccAWSSQSConfigWithDefaults(queueName), + Config: testAccAWSSQSConfigTags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), - resource.TestCheckNoResourceAttr(resourceName, "tags"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, }, @@ -231,8 +227,8 @@ func TestAccAWSSQSQueue_Name_Generated(t *testing.T) { testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), - resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), @@ -284,7 +280,6 @@ func TestAccAWSSQSQueue_Name_Generated_FIFOQueue(t *testing.T) { func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { var queueAttributes map[string]string resourceName := "aws_sqs_queue.test" - rName := "tf-acc-test-prefix-" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -293,11 +288,11 @@ func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSQueueConfigNamePrefix(rName), + Config: testAccAWSSQSQueueConfigNamePrefix("tf-acc-test-prefix-"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", rName), - resource.TestCheckResourceAttr(resourceName, "name_prefix", rName), + naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), @@ -318,7 +313,6 @@ func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { var queueAttributes map[string]string resourceName := "aws_sqs_queue.test" - rName := "tf-acc-test-prefix-" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -327,11 +321,11 @@ func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSQueueConfigNamePrefixFIFOQueue(rName), + Config: testAccAWSSQSQueueConfigNamePrefixFIFOQueue("tf-acc-test-prefix-"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - naming.TestCheckResourceAttrNameWithSuffixFromPrefix(resourceName, "name", rName, tfsqs.FifoQueueNameSuffix), - resource.TestCheckResourceAttr(resourceName, "name_prefix", rName), + naming.TestCheckResourceAttrNameWithSuffixFromPrefix(resourceName, "name", "tf-acc-test-prefix-", tfsqs.FifoQueueNameSuffix), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), @@ -389,7 +383,7 @@ func TestAccAWSSQSQueue_queueDeletedRecently(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigWithDefaults(queueName), + Config: testAccAWSSQSConfigName(queueName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), @@ -400,7 +394,7 @@ func TestAccAWSSQSQueue_queueDeletedRecently(t *testing.T) { ), }, { - Config: testAccAWSSQSConfigWithDefaults(queueName), + Config: testAccAWSSQSConfigName(queueName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), @@ -704,25 +698,6 @@ func testAccCheckAWSSQSQueueDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSSQSFIFOQueueHighThroughputAttributes(queueAttributes *map[string]*string, deduplicationScope, fifoThroughputLimit string) resource.TestCheckFunc { - return func(s *terraform.State) error { - // checking if attributes are defaults - for key, valuePointer := range *queueAttributes { - value := aws.StringValue(valuePointer) - - if key == "DeduplicationScope" && value != deduplicationScope { - return fmt.Errorf("DeduplicationScope (%s) was not set to %s", value, deduplicationScope) - } - - if key == "FifoThroughputLimit" && value != fifoThroughputLimit { - return fmt.Errorf("FifoThroughputLimit (%s) was not set to %s", value, fifoThroughputLimit) - } - } - - return nil - } -} - const testAccAWSSQSQueueConfigNameGenerated = ` resource "aws_sqs_queue" "test" {} ` @@ -733,12 +708,12 @@ resource "aws_sqs_queue" "test" { } ` -func testAccAWSSQSConfigWithDefaults(r string) string { +func testAccAWSSQSConfigName(rName string) string { return fmt.Sprintf(` resource "aws_sqs_queue" "queue" { - name = "%s" + name = %[1]q } -`, r) +`, rName) } func testAccAWSSQSQueueConfigNamePrefix(prefix string) string { @@ -758,17 +733,42 @@ resource "aws_sqs_queue" "test" { `, prefix) } -func testAccAWSSQSConfigWithOverrides(r string) string { +func testAccAWSSQSConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_sqs_queue" "queue" { - name = "%s" + name = %[1]q + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccAWSSQSConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_sqs_queue" "queue" { + name = %[1]q + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} + +func testAccAWSSQSConfigWithOverrides(rName string) string { + return fmt.Sprintf(` +resource "aws_sqs_queue" "queue" { + name = %[1]q delay_seconds = 90 max_message_size = 2048 message_retention_seconds = 86400 receive_wait_time_seconds = 10 visibility_timeout_seconds = 60 } -`, r) +`, rName) } func testAccAWSSQSConfigWithRedrive(name string) string { @@ -917,28 +917,3 @@ resource "aws_sqs_queue" "queue" { } `, queue) } - -func testAccAWSSQSConfigWithTags(r string) string { - return fmt.Sprintf(` -resource "aws_sqs_queue" "queue" { - name = "%s" - - tags = { - Environment = "production" - Usage = "original" - } -} -`, r) -} - -func testAccAWSSQSConfigWithTagsChanged(r string) string { - return fmt.Sprintf(` -resource "aws_sqs_queue" "queue" { - name = "%s" - - tags = { - Usage = "changed" - } -} -`, r) -} From 2eba4dd8c6e321a89392d6e8fe5102ec06de658b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 6 Jun 2021 16:47:55 -0400 Subject: [PATCH 0257/1208] Add 'attrmap.ApiAttributesToResourceData'. --- aws/internal/attrmap/attrmap.go | 13 ++++ aws/resource_aws_sqs_queue.go | 129 +------------------------------- 2 files changed, 17 insertions(+), 125 deletions(-) diff --git a/aws/internal/attrmap/attrmap.go b/aws/internal/attrmap/attrmap.go index 62d21f3d8705..53ac3637bbc6 100644 --- a/aws/internal/attrmap/attrmap.go +++ b/aws/internal/attrmap/attrmap.go @@ -11,6 +11,19 @@ import ( // Useful for SQS Queue or SNS Topic attribute handling. type AttributeMap map[string]string +// ApiAttributesToResourceData sets Terraform ResourceData from a map of AWS API attributes. +func (m AttributeMap) ApiAttributesToResourceData(apiAttributes map[string]string, d *schema.ResourceData) error { + for tfAttributeName, apiAttributeName := range m { + if v, ok := apiAttributes[apiAttributeName]; ok { + if err := d.Set(tfAttributeName, v); err != nil { + return fmt.Errorf("error setting %s: %w", tfAttributeName, err) + } + } + } + + return nil +} + // ResourceDataToApiAttributesCreate returns a map of AWS API attributes from Terraform ResourceData. // The API attributes map is suitable for resource create. func (m AttributeMap) ResourceDataToApiAttributesCreate(d *schema.ResourceData) (map[string]string, error) { diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index 9a1a4f9a9143..815fc7fdd3a2 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -5,7 +5,6 @@ import ( "fmt" "log" "regexp" - "strconv" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/endpoints" @@ -270,134 +269,14 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { return err } - fifoQueue := false - - // Always set attribute defaults - d.Set("arn", "") - d.Set("content_based_deduplication", false) - d.Set("delay_seconds", tfsqs.DefaultQueueDelaySeconds) - d.Set("kms_data_key_reuse_period_seconds", 300) - d.Set("kms_master_key_id", "") - d.Set("max_message_size", tfsqs.DefaultQueueMaximumMessageSize) - d.Set("message_retention_seconds", tfsqs.DefaultQueueMessageRetentionPeriod) - d.Set("policy", "") - d.Set("receive_wait_time_seconds", tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds) - d.Set("redrive_policy", "") - d.Set("visibility_timeout_seconds", tfsqs.DefaultQueueVisibilityTimeout) - d.Set("deduplication_scope", "") - d.Set("fifo_throughput_limit", "") - - // if attributeOutput != nil { - queueAttributes := output - - if v, ok := queueAttributes[sqs.QueueAttributeNameQueueArn]; ok { - d.Set("arn", v) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameContentBasedDeduplication]; ok && v != "" { - vBool, err := strconv.ParseBool(v) - - if err != nil { - return fmt.Errorf("error parsing content_based_deduplication value (%s) into boolean: %s", v, err) - } - - d.Set("content_based_deduplication", vBool) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameDelaySeconds]; ok && v != "" { - vInt, err := strconv.Atoi(v) - - if err != nil { - return fmt.Errorf("error parsing delay_seconds value (%s) into integer: %s", v, err) - } - - d.Set("delay_seconds", vInt) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameFifoQueue]; ok && v != "" { - vBool, err := strconv.ParseBool(v) - - if err != nil { - return fmt.Errorf("error parsing fifo_queue value (%s) into boolean: %s", v, err) - } - - fifoQueue = vBool - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameKmsDataKeyReusePeriodSeconds]; ok && v != "" { - vInt, err := strconv.Atoi(v) - - if err != nil { - return fmt.Errorf("error parsing kms_data_key_reuse_period_seconds value (%s) into integer: %s", v, err) - } - - d.Set("kms_data_key_reuse_period_seconds", vInt) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameKmsMasterKeyId]; ok { - d.Set("kms_master_key_id", v) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameMaximumMessageSize]; ok && v != "" { - vInt, err := strconv.Atoi(v) - - if err != nil { - return fmt.Errorf("error parsing max_message_size value (%s) into integer: %s", v, err) - } - - d.Set("max_message_size", vInt) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameMessageRetentionPeriod]; ok && v != "" { - vInt, err := strconv.Atoi(v) - - if err != nil { - return fmt.Errorf("error parsing message_retention_seconds value (%s) into integer: %s", v, err) - } - - d.Set("message_retention_seconds", vInt) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNamePolicy]; ok { - d.Set("policy", v) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameReceiveMessageWaitTimeSeconds]; ok && v != "" { - vInt, err := strconv.Atoi(v) - - if err != nil { - return fmt.Errorf("error parsing receive_wait_time_seconds value (%s) into integer: %s", v, err) - } + err = sqsQueueAttributeMap.ApiAttributesToResourceData(output, d) - d.Set("receive_wait_time_seconds", vInt) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameRedrivePolicy]; ok { - d.Set("redrive_policy", v) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameVisibilityTimeout]; ok && v != "" { - vInt, err := strconv.Atoi(v) - - if err != nil { - return fmt.Errorf("error parsing visibility_timeout_seconds value (%s) into integer: %s", v, err) - } - - d.Set("visibility_timeout_seconds", vInt) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameDeduplicationScope]; ok && v != "" { - d.Set("deduplication_scope", v) - } - - if v, ok := queueAttributes[sqs.QueueAttributeNameFifoThroughputLimit]; ok && v != "" { - d.Set("fifo_throughput_limit", v) + if err != nil { + return err } - // } - d.Set("fifo_queue", fifoQueue) d.Set("name", name) - if fifoQueue { + if d.Get("fifo_queue").(bool) { d.Set("name_prefix", naming.NamePrefixFromNameWithSuffix(name, tfsqs.FifoQueueNameSuffix)) } else { d.Set("name_prefix", naming.NamePrefixFromName(name)) From f839b96ada9149de0cb225e9b3d3817436c88a70 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 6 Jun 2021 17:57:23 -0400 Subject: [PATCH 0258/1208] AttributeMap now includes attribute type. --- aws/internal/attrmap/attrmap.go | 98 ++++++++--- aws/internal/service/sqs/consts.go | 1 - aws/resource_aws_sqs_queue.go | 262 +++++++++++++++-------------- aws/resource_aws_sqs_queue_test.go | 220 ++++++++++++------------ 4 files changed, 312 insertions(+), 269 deletions(-) diff --git a/aws/internal/attrmap/attrmap.go b/aws/internal/attrmap/attrmap.go index 53ac3637bbc6..b339742c93c0 100644 --- a/aws/internal/attrmap/attrmap.go +++ b/aws/internal/attrmap/attrmap.go @@ -2,6 +2,7 @@ package attrmap import ( "fmt" + "log" "strconv" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -9,15 +10,62 @@ import ( // AttributeMap represents a map of Terraform resource attribute name to AWS API attribute name. // Useful for SQS Queue or SNS Topic attribute handling. -type AttributeMap map[string]string +type attributeInfo struct { + apiAttributeName string + tfType schema.ValueType +} + +type AttributeMap map[string]attributeInfo + +// New returns a new AttributeMap from the specified Terraform resource attribute name to AWS API attribute name map and resource schema. +func New(attrMap map[string]string, schemaMap map[string]*schema.Schema) AttributeMap { + attributeMap := make(AttributeMap) + + for tfAttributeName, apiAttributeName := range attrMap { + if s, ok := schemaMap[tfAttributeName]; ok { + attributeMap[tfAttributeName] = attributeInfo{ + apiAttributeName: apiAttributeName, + tfType: s.Type, + } + } else { + log.Printf("[ERROR] Unknown attribute: %s", tfAttributeName) + } + } + + return attributeMap +} // ApiAttributesToResourceData sets Terraform ResourceData from a map of AWS API attributes. func (m AttributeMap) ApiAttributesToResourceData(apiAttributes map[string]string, d *schema.ResourceData) error { - for tfAttributeName, apiAttributeName := range m { - if v, ok := apiAttributes[apiAttributeName]; ok { - if err := d.Set(tfAttributeName, v); err != nil { + for tfAttributeName, attributeInfo := range m { + if v, ok := apiAttributes[attributeInfo.apiAttributeName]; ok { + var err error + var tfAttributeValue interface{} + + switch t := attributeInfo.tfType; t { + case schema.TypeBool: + tfAttributeValue, err = strconv.ParseBool(v) + + if err != nil { + return fmt.Errorf("error parsing %s value (%s) into boolean: %w", tfAttributeName, v, err) + } + case schema.TypeInt: + tfAttributeValue, err = strconv.Atoi(v) + + if err != nil { + return fmt.Errorf("error parsing %s value (%s) into integer: %w", tfAttributeName, v, err) + } + case schema.TypeString: + tfAttributeValue = v + default: + return fmt.Errorf("attribute %s is of unsupported type: %d", tfAttributeName, t) + } + + if err := d.Set(tfAttributeName, tfAttributeValue); err != nil { return fmt.Errorf("error setting %s: %w", tfAttributeName, err) } + } else { + d.Set(tfAttributeName, nil) } } @@ -29,22 +77,22 @@ func (m AttributeMap) ApiAttributesToResourceData(apiAttributes map[string]strin func (m AttributeMap) ResourceDataToApiAttributesCreate(d *schema.ResourceData) (map[string]string, error) { apiAttributes := map[string]string{} - for tfAttributeName, apiAttributeName := range m { + for tfAttributeName, attributeInfo := range m { if v, ok := d.GetOk(tfAttributeName); ok { var apiAttributeValue string - switch v := v.(type) { - case int: - apiAttributeValue = strconv.Itoa(v) - case bool: - apiAttributeValue = strconv.FormatBool(v) - case string: - apiAttributeValue = v + switch t := attributeInfo.tfType; t { + case schema.TypeBool: + apiAttributeValue = strconv.FormatBool(v.(bool)) + case schema.TypeInt: + apiAttributeValue = strconv.Itoa(v.(int)) + case schema.TypeString: + apiAttributeValue = v.(string) default: - return nil, fmt.Errorf("attribute %s is of unsupported type: %T", tfAttributeName, v) + return nil, fmt.Errorf("attribute %s is of unsupported type: %d", tfAttributeName, t) } - apiAttributes[apiAttributeName] = apiAttributeValue + apiAttributes[attributeInfo.apiAttributeName] = apiAttributeValue } } @@ -56,22 +104,24 @@ func (m AttributeMap) ResourceDataToApiAttributesCreate(d *schema.ResourceData) func (m AttributeMap) ResourceDataToApiAttributesUpdate(d *schema.ResourceData) (map[string]string, error) { apiAttributes := map[string]string{} - for tfAttributeName, apiAttributeName := range m { + for tfAttributeName, attributeInfo := range m { if d.HasChange(tfAttributeName) { + v := d.Get(tfAttributeName) + var apiAttributeValue string - switch v := d.Get(tfAttributeName).(type) { - case int: - apiAttributeValue = strconv.Itoa(v) - case bool: - apiAttributeValue = strconv.FormatBool(v) - case string: - apiAttributeValue = v + switch t := attributeInfo.tfType; t { + case schema.TypeBool: + apiAttributeValue = strconv.FormatBool(v.(bool)) + case schema.TypeInt: + apiAttributeValue = strconv.Itoa(v.(int)) + case schema.TypeString: + apiAttributeValue = v.(string) default: - return nil, fmt.Errorf("attribute %s is of unsupported type: %T", tfAttributeName, v) + return nil, fmt.Errorf("attribute %s is of unsupported type: %d", tfAttributeName, t) } - apiAttributes[apiAttributeName] = apiAttributeValue + apiAttributes[attributeInfo.apiAttributeName] = apiAttributeValue } } diff --git a/aws/internal/service/sqs/consts.go b/aws/internal/service/sqs/consts.go index d0c8a08e9c99..06263aa7c5da 100644 --- a/aws/internal/service/sqs/consts.go +++ b/aws/internal/service/sqs/consts.go @@ -10,7 +10,6 @@ const ( const ( DefaultQueueDelaySeconds = 0 - DefaultQueueKmsDataKeyReusePeriodSeconds = 300 DefaultQueueMaximumMessageSize = 262_144 // 256 KiB. DefaultQueueMessageRetentionPeriod = 345_600 // 4 days. DefaultQueueReceiveMessageWaitTimeSeconds = 0 diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index 815fc7fdd3a2..c321ffb1ecb3 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -24,156 +24,160 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -var sqsQueueAttributeMap = attrmap.AttributeMap(map[string]string{ - "delay_seconds": sqs.QueueAttributeNameDelaySeconds, - "max_message_size": sqs.QueueAttributeNameMaximumMessageSize, - "message_retention_seconds": sqs.QueueAttributeNameMessageRetentionPeriod, - "receive_wait_time_seconds": sqs.QueueAttributeNameReceiveMessageWaitTimeSeconds, - "visibility_timeout_seconds": sqs.QueueAttributeNameVisibilityTimeout, - "policy": sqs.QueueAttributeNamePolicy, - "redrive_policy": sqs.QueueAttributeNameRedrivePolicy, - "arn": sqs.QueueAttributeNameQueueArn, - "fifo_queue": sqs.QueueAttributeNameFifoQueue, - "content_based_deduplication": sqs.QueueAttributeNameContentBasedDeduplication, - "kms_master_key_id": sqs.QueueAttributeNameKmsMasterKeyId, - "kms_data_key_reuse_period_seconds": sqs.QueueAttributeNameKmsDataKeyReusePeriodSeconds, - "deduplication_scope": sqs.QueueAttributeNameDeduplicationScope, - "fifo_throughput_limit": sqs.QueueAttributeNameFifoThroughputLimit, -}) +var ( + sqsQueueSchema = map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, -// A number of these are marked as computed because if you don't -// provide a value, SQS will provide you with defaults (which are the -// default values specified below) -func resourceAwsSqsQueue() *schema.Resource { - return &schema.Resource{ - Create: resourceAwsSqsQueueCreate, - Read: resourceAwsSqsQueueRead, - Update: resourceAwsSqsQueueUpdate, - Delete: resourceAwsSqsQueueDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + "content_based_deduplication": { + Type: schema.TypeBool, + Default: false, + Optional: true, }, - CustomizeDiff: customdiff.Sequence( - resourceAwsSqsQueueCustomizeDiff, - SetTagsDiff, - ), - Schema: map[string]*schema.Schema{ - "arn": { - Type: schema.TypeString, - Computed: true, - }, + "deduplication_scope": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(tfsqs.DeduplicationScope_Values(), false), + }, - "content_based_deduplication": { - Type: schema.TypeBool, - Default: false, - Optional: true, - }, + "delay_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: tfsqs.DefaultQueueDelaySeconds, + ValidateFunc: validation.IntBetween(0, 900), + }, - "deduplication_scope": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice(tfsqs.DeduplicationScope_Values(), false), - }, + "fifo_queue": { + Type: schema.TypeBool, + Default: false, + ForceNew: true, + Optional: true, + }, - "delay_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: tfsqs.DefaultQueueDelaySeconds, - ValidateFunc: validation.IntBetween(0, 900), - }, + "fifo_throughput_limit": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(tfsqs.FifoThroughputLimit_Values(), false), + }, - "fifo_queue": { - Type: schema.TypeBool, - Default: false, - ForceNew: true, - Optional: true, - }, + "kms_data_key_reuse_period_seconds": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + ValidateFunc: validation.IntBetween(60, 86_400), + }, - "fifo_throughput_limit": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice(tfsqs.FifoThroughputLimit_Values(), false), - }, + "kms_master_key_id": { + Type: schema.TypeString, + Optional: true, + }, - "kms_data_key_reuse_period_seconds": { - Type: schema.TypeInt, - Computed: true, - Optional: true, - ValidateFunc: validation.IntBetween(60, 86_400), - }, + "max_message_size": { + Type: schema.TypeInt, + Optional: true, + Default: tfsqs.DefaultQueueMaximumMessageSize, + ValidateFunc: validation.IntBetween(1024, 262_144), + }, - "kms_master_key_id": { - Type: schema.TypeString, - Optional: true, - }, + "message_retention_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: tfsqs.DefaultQueueMessageRetentionPeriod, + ValidateFunc: validation.IntBetween(60, 1_209_600), + }, - "max_message_size": { - Type: schema.TypeInt, - Optional: true, - Default: tfsqs.DefaultQueueMaximumMessageSize, - ValidateFunc: validation.IntBetween(1024, 262_144), - }, + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"name_prefix"}, + }, - "message_retention_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: tfsqs.DefaultQueueMessageRetentionPeriod, - ValidateFunc: validation.IntBetween(60, 1_209_600), - }, + "name_prefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"name"}, + }, - "name": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ConflictsWith: []string{"name_prefix"}, - }, + "policy": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs, + }, - "name_prefix": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ConflictsWith: []string{"name"}, - }, + "receive_wait_time_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds, + }, - "policy": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringIsJSON, - DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs, + "redrive_policy": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsJSON, + StateFunc: func(v interface{}) string { + json, _ := structure.NormalizeJsonString(v) + return json }, + }, - "receive_wait_time_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds, - }, + "visibility_timeout_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: tfsqs.DefaultQueueVisibilityTimeout, + ValidateFunc: validation.IntBetween(0, 43_200), + }, - "redrive_policy": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringIsJSON, - StateFunc: func(v interface{}) string { - json, _ := structure.NormalizeJsonString(v) - return json - }, - }, + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), + } - "visibility_timeout_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: tfsqs.DefaultQueueVisibilityTimeout, - ValidateFunc: validation.IntBetween(0, 43_200), - }, + sqsQueueAttributeMap = attrmap.New(map[string]string{ + "delay_seconds": sqs.QueueAttributeNameDelaySeconds, + "max_message_size": sqs.QueueAttributeNameMaximumMessageSize, + "message_retention_seconds": sqs.QueueAttributeNameMessageRetentionPeriod, + "receive_wait_time_seconds": sqs.QueueAttributeNameReceiveMessageWaitTimeSeconds, + "visibility_timeout_seconds": sqs.QueueAttributeNameVisibilityTimeout, + "policy": sqs.QueueAttributeNamePolicy, + "redrive_policy": sqs.QueueAttributeNameRedrivePolicy, + "arn": sqs.QueueAttributeNameQueueArn, + "fifo_queue": sqs.QueueAttributeNameFifoQueue, + "content_based_deduplication": sqs.QueueAttributeNameContentBasedDeduplication, + "kms_master_key_id": sqs.QueueAttributeNameKmsMasterKeyId, + "kms_data_key_reuse_period_seconds": sqs.QueueAttributeNameKmsDataKeyReusePeriodSeconds, + "deduplication_scope": sqs.QueueAttributeNameDeduplicationScope, + "fifo_throughput_limit": sqs.QueueAttributeNameFifoThroughputLimit, + }, sqsQueueSchema) +) - "tags": tagsSchema(), - "tags_all": tagsSchemaComputed(), +// A number of these are marked as computed because if you don't +// provide a value, SQS will provide you with defaults (which are the +// default values specified below) +func resourceAwsSqsQueue() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSqsQueueCreate, + Read: resourceAwsSqsQueueRead, + Update: resourceAwsSqsQueueUpdate, + Delete: resourceAwsSqsQueueDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, }, + CustomizeDiff: customdiff.Sequence( + resourceAwsSqsQueueCustomizeDiff, + SetTagsDiff, + ), + + Schema: sqsQueueSchema, } } diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index d03553083d98..2e5681bffd7d 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -99,7 +99,50 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), - resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", strconv.Itoa(tfsqs.DefaultQueueKmsDataKeyReusePeriodSeconds)), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", "0"), + resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "name_prefix", ""), + resource.TestCheckResourceAttr(resourceName, "policy", ""), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "redrive_policy", ""), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSSQSQueue_update(t *testing.T) { + var queueAttributes map[string]string + resourceName := "aws_sqs_queue.queue" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSQSQueueDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSQSConfigName(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "sqs", rName), + resource.TestCheckResourceAttr(resourceName, "content_based_deduplication", "false"), + resource.TestCheckResourceAttr(resourceName, "deduplication_scope", ""), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), + resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", "0"), resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", ""), resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), @@ -227,12 +270,7 @@ func TestAccAWSSQSQueue_Name_Generated(t *testing.T) { testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { @@ -261,11 +299,6 @@ func TestAccAWSSQSQueue_Name_Generated_FIFOQueue(t *testing.T) { naming.TestCheckResourceAttrNameWithSuffixGenerated(resourceName, "name", tfsqs.FifoQueueNameSuffix), resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { @@ -294,11 +327,6 @@ func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { @@ -327,11 +355,6 @@ func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { naming.TestCheckResourceAttrNameWithSuffixFromPrefix(resourceName, "name", "tf-acc-test-prefix-", tfsqs.FifoQueueNameSuffix), resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, { @@ -343,11 +366,10 @@ func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { }) } -func TestAccAWSSQSQueue_policy(t *testing.T) { +func TestAccAWSSQSQueue_Policy(t *testing.T) { var queueAttributes map[string]string - resourceName := "aws_sqs_queue.test-email-events" - queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) - topicName := fmt.Sprintf("sns-topic-%s", acctest.RandString(10)) + resourceName := "aws_sqs_queue.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -356,10 +378,15 @@ func TestAccAWSSQSQueue_policy(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfig_PolicyFormat(topicName, queueName), + Config: testAccAWSSQSConfigPolicy(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckAWSSQSQueuePolicyAttribute(&queueAttributes, topicName, queueName), + testAccCheckAWSSQSQueuePolicyAttribute(&queueAttributes, rName), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", "90"), + resource.TestCheckResourceAttr(resourceName, "max_message_size", "2048"), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", "86400"), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", "10"), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", "60"), ), }, { @@ -371,10 +398,10 @@ func TestAccAWSSQSQueue_policy(t *testing.T) { }) } -func TestAccAWSSQSQueue_queueDeletedRecently(t *testing.T) { +func TestAccAWSSQSQueue_RecentlyDeleted(t *testing.T) { var queueAttributes map[string]string resourceName := "aws_sqs_queue.queue" - queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -383,68 +410,27 @@ func TestAccAWSSQSQueue_queueDeletedRecently(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigName(queueName), + Config: testAccAWSSQSConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueue(), resourceName), ), + ExpectNonEmptyPlan: true, }, { - Config: testAccAWSSQSConfigName(queueName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), - ), - Taint: []string{resourceName}, - }, - }, - }) -} - -func TestAccAWSSQSQueue_redrivePolicy(t *testing.T) { - var queueAttributes map[string]string - resourceName := "aws_sqs_queue.my_dead_letter_queue" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSSQSQueueDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSSQSConfigWithRedrive(acctest.RandString(10)), + Config: testAccAWSSQSConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, }, }) } -// Tests formatting and compacting of Policy, Redrive json -func TestAccAWSSQSQueue_Policybasic(t *testing.T) { +func TestAccAWSSQSQueue_RedrivePolicy(t *testing.T) { var queueAttributes map[string]string - resourceName := "aws_sqs_queue.test-email-events" - queueName := fmt.Sprintf("sqs-queue-%s", acctest.RandString(10)) - topicName := fmt.Sprintf("sns-topic-%s", acctest.RandString(10)) + resourceName := "aws_sqs_queue.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -453,14 +439,12 @@ func TestAccAWSSQSQueue_Policybasic(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfig_PolicyFormat(topicName, queueName), + Config: testAccAWSSQSConfigRedrivePolicy(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", "90"), - resource.TestCheckResourceAttr(resourceName, "max_message_size", "2048"), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", "86400"), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", "10"), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", "60"), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", "0"), + resource.TestCheckResourceAttrSet(resourceName, "redrive_policy"), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", "300"), ), }, { @@ -621,12 +605,24 @@ func TestAccAWSSQSQueue_Encryption(t *testing.T) { }) } -func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]string, topicName, queueName string) resource.TestCheckFunc { +func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]string, rName string) resource.TestCheckFunc { return func(s *terraform.State) error { - accountID := testAccProvider.Meta().(*AWSClient).accountid - - expectedPolicyFormat := `{"Version": "2012-10-17","Id": "sqspolicy","Statement":[{"Sid": "Stmt1451501026839","Effect": "Allow","Principal":"*","Action":"sqs:SendMessage","Resource":"arn:%[1]s:sqs:%[2]s:%[3]s:%[4]s","Condition":{"ArnEquals":{"aws:SourceArn":"arn:%[1]s:sns:%[2]s:%[3]s:%[5]s"}}}]}` - expectedPolicyText := fmt.Sprintf(expectedPolicyFormat, testAccGetPartition(), testAccGetRegion(), accountID, topicName, queueName) + expectedPolicyText := fmt.Sprintf( + `{ +"Version": "2012-10-17", +"Id": "sqspolicy", +"Statement":[{ + "Sid": "Stmt1451501026839", + "Effect": "Allow", + "Principal":"*", + "Action":"sqs:SendMessage", + "Resource":"arn:%[1]s:sqs:%[2]s:%[3]s:%[4]s", + "Condition":{ + "ArnEquals":{"aws:SourceArn":"arn:%[1]s:sns:%[2]s:%[3]s:%[5]s"} + } +}] + }`, + testAccGetPartition(), testAccGetRegion(), testAccGetAccountID(), rName, rName) var actualPolicyText string for key, value := range *queueAttributes { @@ -641,8 +637,7 @@ func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]string, return fmt.Errorf("Error testing policy equivalence: %s", err) } if !equivalent { - return fmt.Errorf("Non-equivalent policy error:\n\nexpected: %s\n\n got: %s\n", - expectedPolicyText, actualPolicyText) + return fmt.Errorf("Non-equivalent policy error:\n\nexpected: %s\n\n got: %s\n", expectedPolicyText, actualPolicyText) } return nil @@ -771,39 +766,35 @@ resource "aws_sqs_queue" "queue" { `, rName) } -func testAccAWSSQSConfigWithRedrive(name string) string { +func testAccAWSSQSConfigRedrivePolicy(rName string) string { return fmt.Sprintf(` -resource "aws_sqs_queue" "my_queue" { - name = "tftestqueuq-%[1]s" +resource "aws_sqs_queue" "test" { + name = "%[1]s-1" delay_seconds = 0 visibility_timeout_seconds = 300 redrive_policy = < Date: Sun, 6 Jun 2021 18:28:07 -0400 Subject: [PATCH 0259/1208] r/aws_sqs_queue: All current tests passing in Commercial. --- aws/resource_aws_sqs_queue_test.go | 374 +++++++++++++++-------------- 1 file changed, 191 insertions(+), 183 deletions(-) diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index 2e5681bffd7d..f12a1da6058f 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -80,7 +80,7 @@ func testSweepSqsQueues(region string) error { func TestAccAWSSQSQueue_basic(t *testing.T) { var queueAttributes map[string]string - resourceName := "aws_sqs_queue.queue" + resourceName := "aws_sqs_queue.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -121,9 +121,9 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { }) } -func TestAccAWSSQSQueue_update(t *testing.T) { +func TestAccAWSSQSQueue_disappears(t *testing.T) { var queueAttributes map[string]string - resourceName := "aws_sqs_queue.queue" + resourceName := "aws_sqs_queue.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -134,98 +134,61 @@ func TestAccAWSSQSQueue_update(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSQSConfigName(rName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "sqs", rName), - resource.TestCheckResourceAttr(resourceName, "content_based_deduplication", "false"), - resource.TestCheckResourceAttr(resourceName, "deduplication_scope", ""), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), - resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), - resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", "0"), - resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", ""), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttr(resourceName, "name_prefix", ""), - resource.TestCheckResourceAttr(resourceName, "policy", ""), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "redrive_policy", ""), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccAWSSQSConfigWithOverrides(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", "90"), - resource.TestCheckResourceAttr(resourceName, "max_message_size", "2048"), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", "86400"), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", "10"), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", "60"), - ), - }, - { - Config: testAccAWSSQSConfigName(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), - resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), - resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), - resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), - resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueue(), resourceName), ), + ExpectNonEmptyPlan: true, }, }, }) } -func TestAccAWSSQSQueue_disappears(t *testing.T) { +func TestAccAWSSQSQueue_Name_Generated(t *testing.T) { var queueAttributes map[string]string - resourceName := "aws_sqs_queue.queue" - rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_sqs_queue.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), Providers: testAccProviders, + ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigName(rName), + Config: testAccAWSSQSQueueConfigNameGenerated, Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueue(), resourceName), + naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), ), - ExpectNonEmptyPlan: true, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) } -func TestAccAWSSQSQueue_Tags(t *testing.T) { +func TestAccAWSSQSQueue_Name_Generated_FIFOQueue(t *testing.T) { var queueAttributes map[string]string - resourceName := "aws_sqs_queue.queue" - rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_sqs_queue.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), Providers: testAccProviders, + ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigTags1(rName, "key1", "value1"), + Config: testAccAWSSQSQueueConfigNameGeneratedFIFOQueue, Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + naming.TestCheckResourceAttrNameWithSuffixGenerated(resourceName, "name", tfsqs.FifoQueueNameSuffix), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), ), }, { @@ -233,43 +196,26 @@ func TestAccAWSSQSQueue_Tags(t *testing.T) { ImportState: true, ImportStateVerify: true, }, - { - Config: testAccAWSSQSConfigTags2(rName, "key1", "value1updated", "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), - ), - }, - { - Config: testAccAWSSQSConfigTags1(rName, "key2", "value2"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), - ), - }, }, }) } -func TestAccAWSSQSQueue_Name_Generated(t *testing.T) { +func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { var queueAttributes map[string]string resourceName := "aws_sqs_queue.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), + Providers: testAccProviders, CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSQueueConfigNameGenerated, + Config: testAccAWSSQSQueueConfigNamePrefix("tf-acc-test-prefix-"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), - resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), ), }, @@ -282,22 +228,22 @@ func TestAccAWSSQSQueue_Name_Generated(t *testing.T) { }) } -func TestAccAWSSQSQueue_Name_Generated_FIFOQueue(t *testing.T) { +func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { var queueAttributes map[string]string resourceName := "aws_sqs_queue.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), + Providers: testAccProviders, CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSQueueConfigNameGeneratedFIFOQueue, + Config: testAccAWSSQSQueueConfigNamePrefixFIFOQueue("tf-acc-test-prefix-"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - naming.TestCheckResourceAttrNameWithSuffixGenerated(resourceName, "name", tfsqs.FifoQueueNameSuffix), - resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + naming.TestCheckResourceAttrNameWithSuffixFromPrefix(resourceName, "name", "tf-acc-test-prefix-", tfsqs.FifoQueueNameSuffix), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), ), }, @@ -310,9 +256,10 @@ func TestAccAWSSQSQueue_Name_Generated_FIFOQueue(t *testing.T) { }) } -func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { +func TestAccAWSSQSQueue_Tags(t *testing.T) { var queueAttributes map[string]string resourceName := "aws_sqs_queue.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -321,12 +268,11 @@ func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSQueueConfigNamePrefix("tf-acc-test-prefix-"), + Config: testAccAWSSQSConfigTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), - resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), - resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { @@ -334,13 +280,31 @@ func TestAccAWSSQSQueue_NamePrefix(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccAWSSQSConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSSQSConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, }, }) } -func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { +func TestAccAWSSQSQueue_Update(t *testing.T) { var queueAttributes map[string]string resourceName := "aws_sqs_queue.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -349,12 +313,49 @@ func TestAccAWSSQSQueue_NamePrefix_FIFOQueue(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSQueueConfigNamePrefixFIFOQueue("tf-acc-test-prefix-"), - Check: resource.ComposeTestCheckFunc( + Config: testAccAWSSQSConfigName(rName), + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - naming.TestCheckResourceAttrNameWithSuffixFromPrefix(resourceName, "name", "tf-acc-test-prefix-", tfsqs.FifoQueueNameSuffix), - resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), - resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "sqs", rName), + resource.TestCheckResourceAttr(resourceName, "content_based_deduplication", "false"), + resource.TestCheckResourceAttr(resourceName, "deduplication_scope", ""), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), + resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", "0"), + resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "name_prefix", ""), + resource.TestCheckResourceAttr(resourceName, "policy", ""), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), + resource.TestCheckResourceAttr(resourceName, "redrive_policy", ""), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), + ), + }, + { + Config: testAccAWSSQSConfigUpdated(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "sqs", rName), + resource.TestCheckResourceAttr(resourceName, "content_based_deduplication", "false"), + resource.TestCheckResourceAttr(resourceName, "deduplication_scope", ""), + resource.TestCheckResourceAttr(resourceName, "delay_seconds", "90"), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), + resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", "0"), + resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "max_message_size", "2048"), + resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", "86400"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "name_prefix", ""), + resource.TestCheckResourceAttr(resourceName, "policy", ""), + resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", "10"), + resource.TestCheckResourceAttr(resourceName, "redrive_policy", ""), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", "60"), ), }, { @@ -400,7 +401,7 @@ func TestAccAWSSQSQueue_Policy(t *testing.T) { func TestAccAWSSQSQueue_RecentlyDeleted(t *testing.T) { var queueAttributes map[string]string - resourceName := "aws_sqs_queue.queue" + resourceName := "aws_sqs_queue.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -456,9 +457,10 @@ func TestAccAWSSQSQueue_RedrivePolicy(t *testing.T) { }) } -func TestAccAWSSQSQueue_FIFO(t *testing.T) { +func TestAccAWSSQSQueue_FIFOQueue(t *testing.T) { var queueAttributes map[string]string - resourceName := "aws_sqs_queue.queue" + resourceName := "aws_sqs_queue.test" + rName := fmt.Sprintf("%s.fifo", acctest.RandomWithPrefix("tf-acc-test")) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -467,11 +469,11 @@ func TestAccAWSSQSQueue_FIFO(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigWithFIFO(acctest.RandString(10)), + Config: testAccAWSSQSConfigFIFOQueue(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), resource.TestCheckResourceAttr(resourceName, "deduplication_scope", "queue"), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", "perQueue"), ), }, @@ -484,7 +486,9 @@ func TestAccAWSSQSQueue_FIFO(t *testing.T) { }) } -func TestAccAWSSQSQueue_FIFOExpectNameError(t *testing.T) { +func TestAccAWSSQSQueue_FIFOQueue_ExpectNameError(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), @@ -492,16 +496,17 @@ func TestAccAWSSQSQueue_FIFOExpectNameError(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigWithFIFOExpectError(acctest.RandString(10)), + Config: testAccAWSSQSConfigFIFOQueue(rName), ExpectError: regexp.MustCompile(`invalid queue name:`), }, }, }) } -func TestAccAWSSQSQueue_FIFOWithContentBasedDeduplication(t *testing.T) { +func TestAccAWSSQSQueue_FIFOQueue_ContentBasedDeduplication(t *testing.T) { var queueAttributes map[string]string - resourceName := "aws_sqs_queue.queue" + resourceName := "aws_sqs_queue.test" + rName := fmt.Sprintf("%s.fifo", acctest.RandomWithPrefix("tf-acc-test")) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -510,11 +515,11 @@ func TestAccAWSSQSQueue_FIFOWithContentBasedDeduplication(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigWithFIFOContentBasedDeduplication(acctest.RandString(10)), + Config: testAccAWSSQSConfigFIFOQueueContentBasedDeduplication(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), resource.TestCheckResourceAttr(resourceName, "content_based_deduplication", "true"), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), ), }, { @@ -526,11 +531,10 @@ func TestAccAWSSQSQueue_FIFOWithContentBasedDeduplication(t *testing.T) { }) } -func TestAccAWSSQSQueue_FIFOWithHighThroughputMode(t *testing.T) { +func TestAccAWSSQSQueue_FIFOQueue_HighThroughputMode(t *testing.T) { var queueAttributes map[string]string - - resourceName := "aws_sqs_queue.queue" - queueName := acctest.RandString(10) + resourceName := "aws_sqs_queue.test" + rName := fmt.Sprintf("%s.fifo", acctest.RandomWithPrefix("tf-acc-test")) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -539,11 +543,11 @@ func TestAccAWSSQSQueue_FIFOWithHighThroughputMode(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigWithFIFOHighThroughputMode1(queueName), + Config: testAccAWSSQSConfigFIFOQueueHighThroughputMode(rName, "null", "null"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), - resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), resource.TestCheckResourceAttr(resourceName, "deduplication_scope", "queue"), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", "perQueue"), ), }, @@ -553,10 +557,11 @@ func TestAccAWSSQSQueue_FIFOWithHighThroughputMode(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSSQSConfigWithFIFOHighThroughputMode2(queueName), + Config: testAccAWSSQSConfigFIFOQueueHighThroughputMode(rName, "messageGroup", "perMessageGroupId"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), resource.TestCheckResourceAttr(resourceName, "deduplication_scope", "messageGroup"), + resource.TestCheckResourceAttr(resourceName, "fifo_queue", "true"), resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", "perMessageGroupId"), ), }, @@ -564,7 +569,9 @@ func TestAccAWSSQSQueue_FIFOWithHighThroughputMode(t *testing.T) { }) } -func TestAccAWSSQSQueue_ExpectContentBasedDeduplicationError(t *testing.T) { +func TestAccAWSSQSQueue_StandardQueue_ExpectContentBasedDeduplicationError(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), @@ -572,7 +579,7 @@ func TestAccAWSSQSQueue_ExpectContentBasedDeduplicationError(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccExpectContentBasedDeduplicationError(acctest.RandString(10)), + Config: testAccAWSSQSConfigStandardQueueExpectContentBasedDeduplicationError(rName), ExpectError: regexp.MustCompile(`content-based deduplication can only be set for FIFO queue`), }, }, @@ -581,7 +588,8 @@ func TestAccAWSSQSQueue_ExpectContentBasedDeduplicationError(t *testing.T) { func TestAccAWSSQSQueue_Encryption(t *testing.T) { var queueAttributes map[string]string - resourceName := "aws_sqs_queue.queue" + resourceName := "aws_sqs_queue.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -590,9 +598,10 @@ func TestAccAWSSQSQueue_Encryption(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSConfigWithEncryption(acctest.RandString(10)), + Config: testAccAWSSQSConfigEncryption(rName, "null"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", "300"), resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", "alias/aws/sqs"), ), }, @@ -601,6 +610,14 @@ func TestAccAWSSQSQueue_Encryption(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccAWSSQSConfigEncryption(rName, "3600"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", "3600"), + resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", "alias/aws/sqs"), + ), + }, }, }) } @@ -705,7 +722,7 @@ resource "aws_sqs_queue" "test" { func testAccAWSSQSConfigName(rName string) string { return fmt.Sprintf(` -resource "aws_sqs_queue" "queue" { +resource "aws_sqs_queue" "test" { name = %[1]q } `, rName) @@ -730,7 +747,7 @@ resource "aws_sqs_queue" "test" { func testAccAWSSQSConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` -resource "aws_sqs_queue" "queue" { +resource "aws_sqs_queue" "test" { name = %[1]q tags = { @@ -742,7 +759,7 @@ resource "aws_sqs_queue" "queue" { func testAccAWSSQSConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` -resource "aws_sqs_queue" "queue" { +resource "aws_sqs_queue" "test" { name = %[1]q tags = { @@ -753,9 +770,9 @@ resource "aws_sqs_queue" "queue" { `, rName, tagKey1, tagValue1, tagKey2, tagValue2) } -func testAccAWSSQSConfigWithOverrides(rName string) string { +func testAccAWSSQSConfigUpdated(rName string) string { return fmt.Sprintf(` -resource "aws_sqs_queue" "queue" { +resource "aws_sqs_queue" "test" { name = %[1]q delay_seconds = 90 max_message_size = 2048 @@ -766,27 +783,6 @@ resource "aws_sqs_queue" "queue" { `, rName) } -func testAccAWSSQSConfigRedrivePolicy(rName string) string { - return fmt.Sprintf(` -resource "aws_sqs_queue" "test" { - name = "%[1]s-1" - delay_seconds = 0 - visibility_timeout_seconds = 300 - - redrive_policy = < Date: Sun, 6 Jun 2021 18:41:20 -0400 Subject: [PATCH 0260/1208] Simplify 'QueueDeleted' waiter - Now get correct failures in GovCloud. --- aws/internal/service/sqs/waiter/status.go | 24 +++++++++++++ aws/internal/service/sqs/waiter/waiter.go | 44 +++++------------------ 2 files changed, 33 insertions(+), 35 deletions(-) create mode 100644 aws/internal/service/sqs/waiter/status.go diff --git a/aws/internal/service/sqs/waiter/status.go b/aws/internal/service/sqs/waiter/status.go new file mode 100644 index 000000000000..a7f9210c466a --- /dev/null +++ b/aws/internal/service/sqs/waiter/status.go @@ -0,0 +1,24 @@ +package waiter + +import ( + "github.com/aws/aws-sdk-go/service/sqs" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func QueueState(conn *sqs.SQS, url string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.QueueAttributesByURL(conn, url) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, queueStateExists, nil + } +} diff --git a/aws/internal/service/sqs/waiter/waiter.go b/aws/internal/service/sqs/waiter/waiter.go index 8cb3563fe6c2..b859970dc619 100644 --- a/aws/internal/service/sqs/waiter/waiter.go +++ b/aws/internal/service/sqs/waiter/waiter.go @@ -1,13 +1,10 @@ package waiter import ( - "errors" "time" "github.com/aws/aws-sdk-go/service/sqs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/finder" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -23,44 +20,21 @@ const ( QueueCreatedTimeout = 70 * time.Second QueueDeletedTimeout = 15 * time.Second -) -var ( - queueStillExistsError = errors.New("SQS Queue still exists") + queueStateExists = "exists" ) func QueueDeleted(conn *sqs.SQS, url string) error { - err := resource.Retry(QueueDeletedTimeout, func() *resource.RetryError { - var err error - - _, err = finder.QueueAttributesByURL(conn, url) - - if tfresource.NotFound(err) { - return nil - } - - if err != nil { - return resource.NonRetryableError(err) - } + stateConf := &resource.StateChangeConf{ + Pending: []string{queueStateExists}, + Target: []string{}, + Refresh: QueueState(conn, url), + Timeout: QueueDeletedTimeout, - return resource.RetryableError(queueStillExistsError) - }) - - if tfresource.TimedOut(err) { - _, err = finder.QueueAttributesByURL(conn, url) - - if err == nil { - return queueStillExistsError - } - - if tfresource.NotFound(err) { - err = nil - } + ContinuousTargetOccurence: 3, } - if err != nil { - return err - } + _, err := stateConf.WaitForState() - return nil + return err } From 32da7839bb2770aef10d0700b044cfc5b5ae8a00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jun 2021 06:33:07 +0000 Subject: [PATCH 0261/1208] build(deps): bump github/issue-labeler from 2.3 to 2.4 Bumps [github/issue-labeler](https://github.com/github/issue-labeler) from 2.3 to 2.4. - [Release notes](https://github.com/github/issue-labeler/releases) - [Commits](https://github.com/github/issue-labeler/compare/v2.3...v2.4) --- updated-dependencies: - dependency-name: github/issue-labeler dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/issues.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml index b37a71dd387c..f9c6b48ad02c 100644 --- a/.github/workflows/issues.yml +++ b/.github/workflows/issues.yml @@ -9,13 +9,13 @@ jobs: - uses: actions/checkout@v2 - name: Apply Issue needs-triage Label if: github.event.action == 'opened' && !contains(fromJSON('["anGie44", "bflad", "bill-rich", "breathingdust", "DrFaust92", "ewbankkit", "gdavison", "maryelizbeth", "YakDriver"]'), github.actor) - uses: github/issue-labeler@v2.3 + uses: github/issue-labeler@v2.4 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" configuration-path: .github/labeler-issue-needs-triage.yml enable-versioned-regex: 0 - name: Apply Issue Triage Labels - uses: github/issue-labeler@v2.3 + uses: github/issue-labeler@v2.4 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" configuration-path: .github/labeler-issue-triage.yml From 49f7aaee8378d81bfc6befacd41bd0c1b238556f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jun 2021 06:41:32 +0000 Subject: [PATCH 0262/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.54 to 1.38.55 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.54 to 1.38.55. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.54...v1.38.55) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 467802da399e..10d25f67814d 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.54 + github.com/aws/aws-sdk-go v1.38.55 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index db173458b47c..beed01024c1f 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.54 h1:fsiNnyso3kIWmUdCSYZt/4oodinY6O6biM1CJMsdYpc= -github.com/aws/aws-sdk-go v1.38.54/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.55 h1:1Wv5CE1Zy0hJ6MJUQ1ekFiCsNKBK5W69+towYQ1P4Vs= +github.com/aws/aws-sdk-go v1.38.55/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 9f7d458989eceb4fd2e4f2f82d51e29fe4c63839 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Jun 2021 06:47:03 +0000 Subject: [PATCH 0263/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.54 to 1.38.55. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.54...v1.38.55) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- .../aws/aws-sdk-go/internal/s3shared/arn/arn.go | 4 ++++ .../aws-sdk-go/internal/s3shared/endpoint_errors.go | 13 +++++++++++++ .../internal/s3shared/resource_request.go | 2 ++ .../aws/aws-sdk-go/service/s3/endpoint.go | 5 +++-- awsproviderlint/vendor/modules.txt | 2 +- 8 files changed, 27 insertions(+), 7 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 6d654639ae40..d7ef9205c62f 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.54 + github.com/aws/aws-sdk-go v1.38.55 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index b83998d7df43..8266381ef234 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.54 h1:fsiNnyso3kIWmUdCSYZt/4oodinY6O6biM1CJMsdYpc= -github.com/aws/aws-sdk-go v1.38.54/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.55 h1:1Wv5CE1Zy0hJ6MJUQ1ekFiCsNKBK5W69+towYQ1P4Vs= +github.com/aws/aws-sdk-go v1.38.55/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index 572b480d25e6..ba613df59b20 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.54" +const SDKVersion = "1.38.55" diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/arn/arn.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/arn/arn.go index 3079e4ab0e24..216c4baabfe4 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/arn/arn.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/arn/arn.go @@ -48,6 +48,10 @@ func ParseResource(s string, resParser ResourceParser) (resARN Resource, err err return nil, InvalidARNError{ARN: a, Reason: "service is not supported"} } + if strings.HasPrefix(a.Region, "fips-") || strings.HasSuffix(a.Region, "-fips") { + return nil, InvalidARNError{ARN: a, Reason: "FIPS region not allowed in ARN"} + } + if len(a.Resource) == 0 { return nil, InvalidARNError{ARN: a, Reason: "resource not set"} } diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/endpoint_errors.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/endpoint_errors.go index e756b2f8733a..4290ff676011 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/endpoint_errors.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/endpoint_errors.go @@ -71,6 +71,8 @@ func NewInvalidARNWithUnsupportedPartitionError(resource arn.Resource, err error } // NewInvalidARNWithFIPSError ARN not supported for FIPS region +// +// Deprecated: FIPS will not appear in the ARN region component. func NewInvalidARNWithFIPSError(resource arn.Resource, err error) InvalidARNError { return InvalidARNError{ message: "resource ARN not supported for FIPS region", @@ -155,6 +157,17 @@ func NewClientConfiguredForFIPSError(resource arn.Resource, clientPartitionID, c } } +// NewFIPSConfigurationError denotes a configuration error when a client or request is configured for FIPS +func NewFIPSConfigurationError(resource arn.Resource, clientPartitionID, clientRegion string, err error) ConfigurationError { + return ConfigurationError{ + message: "use of ARN is not supported when client or request is configured for FIPS", + origErr: err, + resource: resource, + clientPartitionID: clientPartitionID, + clientRegion: clientRegion, + } +} + // NewClientConfiguredForAccelerateError denotes client config error for unsupported S3 accelerate func NewClientConfiguredForAccelerateError(resource arn.Resource, clientPartitionID, clientRegion string, err error) ConfigurationError { return ConfigurationError{ diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/resource_request.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/resource_request.go index 9f70a64ecff5..2091ba6ba315 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/resource_request.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/s3shared/resource_request.go @@ -31,6 +31,8 @@ func (r ResourceRequest) UseFIPS() bool { } // ResourceConfiguredForFIPS returns true if resource ARNs region is FIPS +// +// Deprecated: FIPS pseudo-regions will not be in the ARN func (r ResourceRequest) ResourceConfiguredForFIPS() bool { return IsFIPS(r.ARN().Region) } diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/s3/endpoint.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/s3/endpoint.go index 9fc2105fd2f3..ba1a84d091fd 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/s3/endpoint.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/s3/endpoint.go @@ -155,8 +155,9 @@ func endpointHandler(req *request.Request) { } case arn.OutpostAccessPointARN: // outposts does not support FIPS regions - if resReq.ResourceConfiguredForFIPS() { - req.Error = s3shared.NewInvalidARNWithFIPSError(resource, nil) + if resReq.UseFIPS() { + req.Error = s3shared.NewFIPSConfigurationError(resource, req.ClientInfo.PartitionID, + aws.StringValue(req.Config.Region), nil) return } diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index cd642952109e..99bbc4679da0 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.54 +# github.com/aws/aws-sdk-go v1.38.55 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 056477369e1ceea9348243346e39869cd8d062a1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 7 Jun 2021 06:22:55 -0400 Subject: [PATCH 0264/1208] Suppress GovCloud acceptance testing errors. --- aws/resource_aws_ecs_task_definition_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index 3f441f8815ca..bf0159411352 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -15,6 +15,8 @@ import ( ) func init() { + RegisterServiceErrorCheckFunc(ecs.EndpointsID, testAccErrorCheckSkipECS) + resource.AddTestSweepers("aws_ecs_task_definition", &resource.Sweeper{ Name: "aws_ecs_task_definition", F: testSweepEcsTaskDefinitions, @@ -65,6 +67,12 @@ func testSweepEcsTaskDefinitions(region string) error { return sweeperErrs.ErrorOrNil() } +func testAccErrorCheckSkipECS(t *testing.T) resource.ErrorCheckFunc { + return testAccErrorCheckSkipMessagesContaining(t, + "Unsupported field 'inferenceAccelerators'", + ) +} + func TestAccAWSEcsTaskDefinition_basic(t *testing.T) { var def ecs.TaskDefinition @@ -357,6 +365,10 @@ func TestAccAWSEcsTaskDefinition_withFsxWinFileSystem(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_ecs_task_definition.test" + if testAccGetPartition() == "aws-us-gov" { + t.Skip("Amazon FSx for Windows File Server volumes for ECS tasks are not supported in GovCloud partition") + } + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, ecs.EndpointsID), From 7677eb75d7f79d7333997c22da9e2c1b7b5c9781 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 11:02:55 +0300 Subject: [PATCH 0265/1208] docs --- aws/resource_aws_gamelift_build.go | 3 +- aws/resource_aws_gamelift_fleet.go | 184 +++++++++++++++--- aws/resource_aws_gamelift_fleet_test.go | 85 ++++---- .../docs/r/ecs_task_definition.html.markdown | 4 +- 4 files changed, 196 insertions(+), 80 deletions(-) diff --git a/aws/resource_aws_gamelift_build.go b/aws/resource_aws_gamelift_build.go index a78e2ec0fa07..7aaa476774f8 100644 --- a/aws/resource_aws_gamelift_build.go +++ b/aws/resource_aws_gamelift_build.go @@ -11,6 +11,7 @@ import ( "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" + iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" ) func resourceAwsGameliftBuild() *schema.Resource { @@ -93,7 +94,7 @@ func resourceAwsGameliftBuildCreate(d *schema.ResourceData, meta interface{}) er } log.Printf("[INFO] Creating Gamelift Build: %s", input) var out *gamelift.CreateBuildOutput - err := resource.Retry(30*time.Second, func() *resource.RetryError { + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { var err error out, err = conn.CreateBuild(&input) if err != nil { diff --git a/aws/resource_aws_gamelift_fleet.go b/aws/resource_aws_gamelift_fleet.go index 38ae1164bc1b..fe104354a1f3 100644 --- a/aws/resource_aws_gamelift_fleet.go +++ b/aws/resource_aws_gamelift_fleet.go @@ -23,7 +23,9 @@ func resourceAwsGameliftFleet() *schema.Resource { Read: resourceAwsGameliftFleetRead, Update: resourceAwsGameliftFleetUpdate, Delete: resourceAwsGameliftFleetDelete, - + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(70 * time.Minute), Delete: schema.DefaultTimeout(20 * time.Minute), @@ -39,20 +41,41 @@ func resourceAwsGameliftFleet() *schema.Resource { Required: true, ForceNew: true, }, - "ec2_instance_type": { - Type: schema.TypeString, - Required: true, + "certificate_configuration": { + Type: schema.TypeList, + Optional: true, ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate_type": { + Type: schema.TypeString, + Optional: true, + Default: gamelift.CertificateTypeDisabled, + ValidateFunc: validation.StringInSlice(gamelift.CertificateType_Values(), false), + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if d.Get("certificate_configuration.0.certificate_type").(string) == "" { + return true + } + + return true + }, + }, + }, + }, + }, + "ec2_instance_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(gamelift.EC2InstanceType_Values(), false), }, "fleet_type": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: gamelift.FleetTypeOnDemand, - ValidateFunc: validation.StringInSlice([]string{ - gamelift.FleetTypeOnDemand, - gamelift.FleetTypeSpot, - }, false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: gamelift.FleetTypeOnDemand, + ValidateFunc: validation.StringInSlice(gamelift.FleetType_Values(), false), }, "name": { Type: schema.TypeString, @@ -87,12 +110,9 @@ func resourceAwsGameliftFleet() *schema.Resource { ValidateFunc: validateCIDRNetworkAddress, }, "protocol": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - gamelift.IpProtocolTcp, - gamelift.IpProtocolUdp, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(gamelift.IpProtocol_Values(), false), }, "to_port": { Type: schema.TypeInt, @@ -107,6 +127,20 @@ func resourceAwsGameliftFleet() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + // "location_configuration": { + // Type: schema.TypeList, + // Optional: true, + // Computed: true + // MaxItems: 100, + // Elem: &schema.Resource{ + // Schema: map[string]*schema.Schema{ + // "location": { + // Type: schema.TypeString, + // Optional: true, + // }, + // }, + // }, + // }, "metric_groups": { Type: schema.TypeList, Optional: true, @@ -117,13 +151,10 @@ func resourceAwsGameliftFleet() *schema.Resource { }, }, "new_game_session_protection_policy": { - Type: schema.TypeString, - Optional: true, - Default: gamelift.ProtectionPolicyNoProtection, - ValidateFunc: validation.StringInSlice([]string{ - gamelift.ProtectionPolicyNoProtection, - gamelift.ProtectionPolicyFullProtection, - }, false), + Type: schema.TypeString, + Optional: true, + Default: gamelift.ProtectionPolicyNoProtection, + ValidateFunc: validation.StringInSlice(gamelift.ProtectionPolicy_Values(), false), }, "operating_system": { Type: schema.TypeString, @@ -191,6 +222,17 @@ func resourceAwsGameliftFleet() *schema.Resource { }, }, }, + "peer_vpc_aws_account_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validateAwsAccountId, + }, + "peer_vpc_id": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), @@ -238,6 +280,15 @@ func resourceAwsGameliftFleetCreate(d *schema.ResourceData, meta interface{}) er if v, ok := d.GetOk("runtime_configuration"); ok { input.RuntimeConfiguration = expandGameliftRuntimeConfiguration(v.([]interface{})) } + if v, ok := d.GetOk("certificate_configuration"); ok { + input.CertificateConfiguration = expandGameliftFleetCertificateConfiguration(v.([]interface{})) + } + if v, ok := d.GetOk("peer_vpc_aws_account_id"); ok { + input.PeerVpcAwsAccountId = aws.String(v.(string)) + } + if v, ok := d.GetOk("peer_vpc_id"); ok { + input.PeerVpcId = aws.String(v.(string)) + } log.Printf("[INFO] Creating Gamelift Fleet: %s", input) var out *gamelift.CreateFleetOutput @@ -340,6 +391,7 @@ func resourceAwsGameliftFleetRead(d *schema.ResourceData, meta interface{}) erro arn := aws.StringValue(fleet.FleetArn) d.Set("build_id", fleet.BuildId) d.Set("description", fleet.Description) + d.Set("ec2_instance_type", fleet.InstanceType) d.Set("arn", arn) d.Set("log_paths", aws.StringValueSlice(fleet.LogPaths)) d.Set("metric_groups", flattenStringList(fleet.MetricGroups)) @@ -348,7 +400,25 @@ func resourceAwsGameliftFleetRead(d *schema.ResourceData, meta interface{}) erro d.Set("instance_role_arn", fleet.InstanceRoleArn) d.Set("new_game_session_protection_policy", fleet.NewGameSessionProtectionPolicy) d.Set("operating_system", fleet.OperatingSystem) - d.Set("resource_creation_limit_policy", flattenGameliftResourceCreationLimitPolicy(fleet.ResourceCreationLimitPolicy)) + + if err := d.Set("resource_creation_limit_policy", flattenGameliftResourceCreationLimitPolicy(fleet.ResourceCreationLimitPolicy)); err != nil { + return fmt.Errorf("error setting resource_creation_limit_policy: %w", err) + } + + if err := d.Set("certificate_configuration", flattenGameliftFleetCertificateConfiguration(fleet.CertificateConfiguration)); err != nil { + return fmt.Errorf("error setting certificate_configuration: %w", err) + } + + runtimeOut, err := conn.DescribeRuntimeConfiguration(&gamelift.DescribeRuntimeConfigurationInput{ + FleetId: aws.String(d.Id()), + }) + if err != nil { + return fmt.Errorf("error describing Game Lift Fleet Runtime Configuration (%s): %w", arn, err) + } + if err := d.Set("runtime_configuration", flattenGameliftFleetRuntimeConfiguration(runtimeOut.RuntimeConfiguration)); err != nil { + return fmt.Errorf("error setting runtime_configuration: %w", err) + } + tags, err := keyvaluetags.GameliftListTags(conn, arn) if isAWSErr(err, gamelift.ErrCodeInvalidRequestException, fmt.Sprintf("Resource %s is not in a taggable state", d.Id())) { @@ -356,7 +426,7 @@ func resourceAwsGameliftFleetRead(d *schema.ResourceData, meta interface{}) erro } if err != nil { - return fmt.Errorf("error listing tags for Game Lift Fleet (%s): %s", arn, err) + return fmt.Errorf("error listing tags for Game Lift Fleet (%s): %w", arn, err) } tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -547,8 +617,8 @@ func flattenGameliftResourceCreationLimitPolicy(policy *gamelift.ResourceCreatio } m := make(map[string]interface{}) - m["new_game_sessions_per_creator"] = *policy.NewGameSessionsPerCreator - m["policy_period_in_minutes"] = *policy.PolicyPeriodInMinutes + m["new_game_sessions_per_creator"] = aws.Int64Value(policy.NewGameSessionsPerCreator) + m["policy_period_in_minutes"] = aws.Int64Value(policy.PolicyPeriodInMinutes) return []interface{}{m} } @@ -679,3 +749,59 @@ OUTER: } return } + +func flattenGameliftFleetRuntimeConfiguration(config *gamelift.RuntimeConfiguration) []interface{} { + if config == nil { + return []interface{}{} + } + + m := make(map[string]interface{}) + m["game_session_activation_timeout_seconds"] = aws.Int64Value(config.GameSessionActivationTimeoutSeconds) + m["max_concurrent_game_session_activations"] = aws.Int64Value(config.MaxConcurrentGameSessionActivations) + m["server_process"] = flattenGameliftFleetRuntimeConfigurationServerProcess(config.ServerProcesses) + + return []interface{}{m} +} + +func flattenGameliftFleetRuntimeConfigurationServerProcess(configs []*gamelift.ServerProcess) []interface{} { + result := make([]interface{}, 0, len(configs)) + + for _, config := range configs { + m := make(map[string]interface{}) + m["concurrent_executions"] = aws.Int64Value(config.ConcurrentExecutions) + m["launch_path"] = aws.StringValue(config.LaunchPath) + + if config.Parameters != nil { + m["parameters"] = aws.StringValue(config.LaunchPath) + } + + result = append(result, m) + } + + return result +} + +func expandGameliftFleetCertificateConfiguration(cfg []interface{}) *gamelift.CertificateConfiguration { + if len(cfg) < 1 { + return nil + } + out := gamelift.CertificateConfiguration{} + m := cfg[0].(map[string]interface{}) + + if v, ok := m["certificate_type"].(string); ok && v != "" { + out.CertificateType = aws.String(v) + } + + return &out +} + +func flattenGameliftFleetCertificateConfiguration(config *gamelift.CertificateConfiguration) []interface{} { + if config == nil { + return []interface{}{} + } + + m := make(map[string]interface{}) + m["certificate_type"] = aws.StringValue(config.CertificateType) + + return []interface{}{m} +} diff --git a/aws/resource_aws_gamelift_fleet_test.go b/aws/resource_aws_gamelift_fleet_test.go index a610038a157c..f74158daaa9c 100644 --- a/aws/resource_aws_gamelift_fleet_test.go +++ b/aws/resource_aws_gamelift_fleet_test.go @@ -274,7 +274,7 @@ func TestAccAWSGameliftFleet_basic(t *testing.T) { Config: testAccAWSGameliftFleetBasicConfig(fleetName, launchPath, params, buildName, bucketName, key, roleArn), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGameliftFleetExists(resourceName, &conf), - resource.TestCheckResourceAttrSet(resourceName, "build_id"), + resource.TestCheckResourceAttrPair(resourceName, "build_id", "aws_gamelift_build.test", "id"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "gamelift", regexp.MustCompile(`fleet/fleet-.+`)), resource.TestCheckResourceAttr(resourceName, "ec2_instance_type", "c4.large"), resource.TestCheckResourceAttr(resourceName, "log_paths.#", "0"), @@ -290,12 +290,18 @@ func TestAccAWSGameliftFleet_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccAWSGameliftFleetBasicUpdatedConfig(desc, uFleetName, launchPath, params, buildName, bucketName, key, roleArn), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGameliftFleetExists(resourceName, &conf), - resource.TestCheckResourceAttrSet(resourceName, "build_id"), - testAccMatchResourceAttrRegionalARN(resourceName, "arn", "gamelift", regexp.MustCompile(`fleet/fleet-.+`)), resource.TestCheckResourceAttr(resourceName, "ec2_instance_type", "c4.large"), + resource.TestCheckResourceAttrPair(resourceName, "build_id", "aws_gamelift_build.test", "id"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "gamelift", regexp.MustCompile(`fleet/fleet-.+`)), + resource.TestCheckResourceAttr(resourceName, "ec2_instance_type", "c4.large"), resource.TestCheckResourceAttr(resourceName, "log_paths.#", "0"), resource.TestCheckResourceAttr(resourceName, "name", uFleetName), resource.TestCheckResourceAttr(resourceName, "description", desc), @@ -360,6 +366,11 @@ func TestAccAWSGameliftFleet_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccAWSGameliftFleetBasicConfigTags2(fleetName, launchPath, params, buildName, bucketName, key, roleArn, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( @@ -461,6 +472,11 @@ func TestAccAWSGameliftFleet_allFields(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "runtime_configuration.0.server_process.0.parameters", params[0]), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccAWSGameliftFleetAllFieldsUpdatedConfig(fleetName, desc, launchPath, params[1], buildName, bucketName, key, roleArn), Check: resource.ComposeTestCheckFunc( @@ -544,7 +560,7 @@ func TestAccAWSGameliftFleet_disappears(t *testing.T) { Config: testAccAWSGameliftFleetBasicConfig(fleetName, launchPath, params, buildName, bucketName, key, roleArn), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGameliftFleetExists(resourceName, &conf), - testAccCheckAWSGameliftFleetDisappears(&conf), + testAccCheckResourceDisappears(testAccProvider, resourceAwsGameliftFleet(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -591,33 +607,6 @@ func testAccCheckAWSGameliftFleetExists(n string, res *gamelift.FleetAttributes) } } -func testAccCheckAWSGameliftFleetDisappears(res *gamelift.FleetAttributes) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).gameliftconn - - input := &gamelift.DeleteFleetInput{FleetId: res.FleetId} - err := resource.Retry(60*time.Minute, func() *resource.RetryError { - _, err := conn.DeleteFleet(input) - if err != nil { - msg := fmt.Sprintf("Cannot delete fleet %s that is in status of ", *res.FleetId) - if isAWSErr(err, gamelift.ErrCodeInvalidRequestException, msg) { - return resource.RetryableError(err) - } - return resource.NonRetryableError(err) - } - return nil - }) - if isResourceTimeoutError(err) { - _, err = conn.DeleteFleet(input) - } - if err != nil { - return fmt.Errorf("Error deleting Gamelift fleet: %s", err) - } - - return waitForGameliftFleetToBeDeleted(conn, *res.FleetId, 15*time.Minute) - } -} - func testAccCheckAWSGameliftFleetDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).gameliftconn @@ -860,6 +849,8 @@ resource "aws_gamelift_build" "test" { func testAccAWSGameLiftFleetIAMRole(rName string) string { return fmt.Sprintf(` +data "aws_partition" "current" {} + resource "aws_iam_role" "test" { name = "test-role-%[1]s" @@ -872,7 +863,7 @@ resource "aws_iam_role" "test" { "Effect": "Allow", "Principal": { "Service": [ - "gamelift.amazonaws.com" + "gamelift.${data.aws_partition.current.dns_suffix}" ] }, "Action": [ @@ -889,23 +880,21 @@ resource "aws_iam_policy" "test" { path = "/" description = "GameLift Fleet PassRole Policy" - policy = < Date: Mon, 7 Jun 2021 11:03:33 +0300 Subject: [PATCH 0266/1208] Revert "docs" This reverts commit 2ff8db8b63107f398dae08ac74fd7aea705b8aee. --- aws/resource_aws_gamelift_build.go | 3 +- aws/resource_aws_gamelift_fleet.go | 184 +++--------------- aws/resource_aws_gamelift_fleet_test.go | 85 ++++---- .../docs/r/ecs_task_definition.html.markdown | 4 +- 4 files changed, 80 insertions(+), 196 deletions(-) diff --git a/aws/resource_aws_gamelift_build.go b/aws/resource_aws_gamelift_build.go index 7aaa476774f8..a78e2ec0fa07 100644 --- a/aws/resource_aws_gamelift_build.go +++ b/aws/resource_aws_gamelift_build.go @@ -11,7 +11,6 @@ import ( "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" - iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" ) func resourceAwsGameliftBuild() *schema.Resource { @@ -94,7 +93,7 @@ func resourceAwsGameliftBuildCreate(d *schema.ResourceData, meta interface{}) er } log.Printf("[INFO] Creating Gamelift Build: %s", input) var out *gamelift.CreateBuildOutput - err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + err := resource.Retry(30*time.Second, func() *resource.RetryError { var err error out, err = conn.CreateBuild(&input) if err != nil { diff --git a/aws/resource_aws_gamelift_fleet.go b/aws/resource_aws_gamelift_fleet.go index fe104354a1f3..38ae1164bc1b 100644 --- a/aws/resource_aws_gamelift_fleet.go +++ b/aws/resource_aws_gamelift_fleet.go @@ -23,9 +23,7 @@ func resourceAwsGameliftFleet() *schema.Resource { Read: resourceAwsGameliftFleetRead, Update: resourceAwsGameliftFleetUpdate, Delete: resourceAwsGameliftFleetDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, + Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(70 * time.Minute), Delete: schema.DefaultTimeout(20 * time.Minute), @@ -41,41 +39,20 @@ func resourceAwsGameliftFleet() *schema.Resource { Required: true, ForceNew: true, }, - "certificate_configuration": { - Type: schema.TypeList, - Optional: true, - ForceNew: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "certificate_type": { - Type: schema.TypeString, - Optional: true, - Default: gamelift.CertificateTypeDisabled, - ValidateFunc: validation.StringInSlice(gamelift.CertificateType_Values(), false), - DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - if d.Get("certificate_configuration.0.certificate_type").(string) == "" { - return true - } - - return true - }, - }, - }, - }, - }, "ec2_instance_type": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice(gamelift.EC2InstanceType_Values(), false), + Type: schema.TypeString, + Required: true, + ForceNew: true, }, "fleet_type": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: gamelift.FleetTypeOnDemand, - ValidateFunc: validation.StringInSlice(gamelift.FleetType_Values(), false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: gamelift.FleetTypeOnDemand, + ValidateFunc: validation.StringInSlice([]string{ + gamelift.FleetTypeOnDemand, + gamelift.FleetTypeSpot, + }, false), }, "name": { Type: schema.TypeString, @@ -110,9 +87,12 @@ func resourceAwsGameliftFleet() *schema.Resource { ValidateFunc: validateCIDRNetworkAddress, }, "protocol": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(gamelift.IpProtocol_Values(), false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + gamelift.IpProtocolTcp, + gamelift.IpProtocolUdp, + }, false), }, "to_port": { Type: schema.TypeInt, @@ -127,20 +107,6 @@ func resourceAwsGameliftFleet() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - // "location_configuration": { - // Type: schema.TypeList, - // Optional: true, - // Computed: true - // MaxItems: 100, - // Elem: &schema.Resource{ - // Schema: map[string]*schema.Schema{ - // "location": { - // Type: schema.TypeString, - // Optional: true, - // }, - // }, - // }, - // }, "metric_groups": { Type: schema.TypeList, Optional: true, @@ -151,10 +117,13 @@ func resourceAwsGameliftFleet() *schema.Resource { }, }, "new_game_session_protection_policy": { - Type: schema.TypeString, - Optional: true, - Default: gamelift.ProtectionPolicyNoProtection, - ValidateFunc: validation.StringInSlice(gamelift.ProtectionPolicy_Values(), false), + Type: schema.TypeString, + Optional: true, + Default: gamelift.ProtectionPolicyNoProtection, + ValidateFunc: validation.StringInSlice([]string{ + gamelift.ProtectionPolicyNoProtection, + gamelift.ProtectionPolicyFullProtection, + }, false), }, "operating_system": { Type: schema.TypeString, @@ -222,17 +191,6 @@ func resourceAwsGameliftFleet() *schema.Resource { }, }, }, - "peer_vpc_aws_account_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ValidateFunc: validateAwsAccountId, - }, - "peer_vpc_id": { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), @@ -280,15 +238,6 @@ func resourceAwsGameliftFleetCreate(d *schema.ResourceData, meta interface{}) er if v, ok := d.GetOk("runtime_configuration"); ok { input.RuntimeConfiguration = expandGameliftRuntimeConfiguration(v.([]interface{})) } - if v, ok := d.GetOk("certificate_configuration"); ok { - input.CertificateConfiguration = expandGameliftFleetCertificateConfiguration(v.([]interface{})) - } - if v, ok := d.GetOk("peer_vpc_aws_account_id"); ok { - input.PeerVpcAwsAccountId = aws.String(v.(string)) - } - if v, ok := d.GetOk("peer_vpc_id"); ok { - input.PeerVpcId = aws.String(v.(string)) - } log.Printf("[INFO] Creating Gamelift Fleet: %s", input) var out *gamelift.CreateFleetOutput @@ -391,7 +340,6 @@ func resourceAwsGameliftFleetRead(d *schema.ResourceData, meta interface{}) erro arn := aws.StringValue(fleet.FleetArn) d.Set("build_id", fleet.BuildId) d.Set("description", fleet.Description) - d.Set("ec2_instance_type", fleet.InstanceType) d.Set("arn", arn) d.Set("log_paths", aws.StringValueSlice(fleet.LogPaths)) d.Set("metric_groups", flattenStringList(fleet.MetricGroups)) @@ -400,25 +348,7 @@ func resourceAwsGameliftFleetRead(d *schema.ResourceData, meta interface{}) erro d.Set("instance_role_arn", fleet.InstanceRoleArn) d.Set("new_game_session_protection_policy", fleet.NewGameSessionProtectionPolicy) d.Set("operating_system", fleet.OperatingSystem) - - if err := d.Set("resource_creation_limit_policy", flattenGameliftResourceCreationLimitPolicy(fleet.ResourceCreationLimitPolicy)); err != nil { - return fmt.Errorf("error setting resource_creation_limit_policy: %w", err) - } - - if err := d.Set("certificate_configuration", flattenGameliftFleetCertificateConfiguration(fleet.CertificateConfiguration)); err != nil { - return fmt.Errorf("error setting certificate_configuration: %w", err) - } - - runtimeOut, err := conn.DescribeRuntimeConfiguration(&gamelift.DescribeRuntimeConfigurationInput{ - FleetId: aws.String(d.Id()), - }) - if err != nil { - return fmt.Errorf("error describing Game Lift Fleet Runtime Configuration (%s): %w", arn, err) - } - if err := d.Set("runtime_configuration", flattenGameliftFleetRuntimeConfiguration(runtimeOut.RuntimeConfiguration)); err != nil { - return fmt.Errorf("error setting runtime_configuration: %w", err) - } - + d.Set("resource_creation_limit_policy", flattenGameliftResourceCreationLimitPolicy(fleet.ResourceCreationLimitPolicy)) tags, err := keyvaluetags.GameliftListTags(conn, arn) if isAWSErr(err, gamelift.ErrCodeInvalidRequestException, fmt.Sprintf("Resource %s is not in a taggable state", d.Id())) { @@ -426,7 +356,7 @@ func resourceAwsGameliftFleetRead(d *schema.ResourceData, meta interface{}) erro } if err != nil { - return fmt.Errorf("error listing tags for Game Lift Fleet (%s): %w", arn, err) + return fmt.Errorf("error listing tags for Game Lift Fleet (%s): %s", arn, err) } tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -617,8 +547,8 @@ func flattenGameliftResourceCreationLimitPolicy(policy *gamelift.ResourceCreatio } m := make(map[string]interface{}) - m["new_game_sessions_per_creator"] = aws.Int64Value(policy.NewGameSessionsPerCreator) - m["policy_period_in_minutes"] = aws.Int64Value(policy.PolicyPeriodInMinutes) + m["new_game_sessions_per_creator"] = *policy.NewGameSessionsPerCreator + m["policy_period_in_minutes"] = *policy.PolicyPeriodInMinutes return []interface{}{m} } @@ -749,59 +679,3 @@ OUTER: } return } - -func flattenGameliftFleetRuntimeConfiguration(config *gamelift.RuntimeConfiguration) []interface{} { - if config == nil { - return []interface{}{} - } - - m := make(map[string]interface{}) - m["game_session_activation_timeout_seconds"] = aws.Int64Value(config.GameSessionActivationTimeoutSeconds) - m["max_concurrent_game_session_activations"] = aws.Int64Value(config.MaxConcurrentGameSessionActivations) - m["server_process"] = flattenGameliftFleetRuntimeConfigurationServerProcess(config.ServerProcesses) - - return []interface{}{m} -} - -func flattenGameliftFleetRuntimeConfigurationServerProcess(configs []*gamelift.ServerProcess) []interface{} { - result := make([]interface{}, 0, len(configs)) - - for _, config := range configs { - m := make(map[string]interface{}) - m["concurrent_executions"] = aws.Int64Value(config.ConcurrentExecutions) - m["launch_path"] = aws.StringValue(config.LaunchPath) - - if config.Parameters != nil { - m["parameters"] = aws.StringValue(config.LaunchPath) - } - - result = append(result, m) - } - - return result -} - -func expandGameliftFleetCertificateConfiguration(cfg []interface{}) *gamelift.CertificateConfiguration { - if len(cfg) < 1 { - return nil - } - out := gamelift.CertificateConfiguration{} - m := cfg[0].(map[string]interface{}) - - if v, ok := m["certificate_type"].(string); ok && v != "" { - out.CertificateType = aws.String(v) - } - - return &out -} - -func flattenGameliftFleetCertificateConfiguration(config *gamelift.CertificateConfiguration) []interface{} { - if config == nil { - return []interface{}{} - } - - m := make(map[string]interface{}) - m["certificate_type"] = aws.StringValue(config.CertificateType) - - return []interface{}{m} -} diff --git a/aws/resource_aws_gamelift_fleet_test.go b/aws/resource_aws_gamelift_fleet_test.go index f74158daaa9c..a610038a157c 100644 --- a/aws/resource_aws_gamelift_fleet_test.go +++ b/aws/resource_aws_gamelift_fleet_test.go @@ -274,7 +274,7 @@ func TestAccAWSGameliftFleet_basic(t *testing.T) { Config: testAccAWSGameliftFleetBasicConfig(fleetName, launchPath, params, buildName, bucketName, key, roleArn), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGameliftFleetExists(resourceName, &conf), - resource.TestCheckResourceAttrPair(resourceName, "build_id", "aws_gamelift_build.test", "id"), + resource.TestCheckResourceAttrSet(resourceName, "build_id"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "gamelift", regexp.MustCompile(`fleet/fleet-.+`)), resource.TestCheckResourceAttr(resourceName, "ec2_instance_type", "c4.large"), resource.TestCheckResourceAttr(resourceName, "log_paths.#", "0"), @@ -290,18 +290,12 @@ func TestAccAWSGameliftFleet_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, { Config: testAccAWSGameliftFleetBasicUpdatedConfig(desc, uFleetName, launchPath, params, buildName, bucketName, key, roleArn), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGameliftFleetExists(resourceName, &conf), - resource.TestCheckResourceAttrPair(resourceName, "build_id", "aws_gamelift_build.test", "id"), - testAccMatchResourceAttrRegionalARN(resourceName, "arn", "gamelift", regexp.MustCompile(`fleet/fleet-.+`)), - resource.TestCheckResourceAttr(resourceName, "ec2_instance_type", "c4.large"), + resource.TestCheckResourceAttrSet(resourceName, "build_id"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "gamelift", regexp.MustCompile(`fleet/fleet-.+`)), resource.TestCheckResourceAttr(resourceName, "ec2_instance_type", "c4.large"), resource.TestCheckResourceAttr(resourceName, "log_paths.#", "0"), resource.TestCheckResourceAttr(resourceName, "name", uFleetName), resource.TestCheckResourceAttr(resourceName, "description", desc), @@ -366,11 +360,6 @@ func TestAccAWSGameliftFleet_tags(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, { Config: testAccAWSGameliftFleetBasicConfigTags2(fleetName, launchPath, params, buildName, bucketName, key, roleArn, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( @@ -472,11 +461,6 @@ func TestAccAWSGameliftFleet_allFields(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "runtime_configuration.0.server_process.0.parameters", params[0]), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, { Config: testAccAWSGameliftFleetAllFieldsUpdatedConfig(fleetName, desc, launchPath, params[1], buildName, bucketName, key, roleArn), Check: resource.ComposeTestCheckFunc( @@ -560,7 +544,7 @@ func TestAccAWSGameliftFleet_disappears(t *testing.T) { Config: testAccAWSGameliftFleetBasicConfig(fleetName, launchPath, params, buildName, bucketName, key, roleArn), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGameliftFleetExists(resourceName, &conf), - testAccCheckResourceDisappears(testAccProvider, resourceAwsGameliftFleet(), resourceName), + testAccCheckAWSGameliftFleetDisappears(&conf), ), ExpectNonEmptyPlan: true, }, @@ -607,6 +591,33 @@ func testAccCheckAWSGameliftFleetExists(n string, res *gamelift.FleetAttributes) } } +func testAccCheckAWSGameliftFleetDisappears(res *gamelift.FleetAttributes) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).gameliftconn + + input := &gamelift.DeleteFleetInput{FleetId: res.FleetId} + err := resource.Retry(60*time.Minute, func() *resource.RetryError { + _, err := conn.DeleteFleet(input) + if err != nil { + msg := fmt.Sprintf("Cannot delete fleet %s that is in status of ", *res.FleetId) + if isAWSErr(err, gamelift.ErrCodeInvalidRequestException, msg) { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + if isResourceTimeoutError(err) { + _, err = conn.DeleteFleet(input) + } + if err != nil { + return fmt.Errorf("Error deleting Gamelift fleet: %s", err) + } + + return waitForGameliftFleetToBeDeleted(conn, *res.FleetId, 15*time.Minute) + } +} + func testAccCheckAWSGameliftFleetDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).gameliftconn @@ -849,8 +860,6 @@ resource "aws_gamelift_build" "test" { func testAccAWSGameLiftFleetIAMRole(rName string) string { return fmt.Sprintf(` -data "aws_partition" "current" {} - resource "aws_iam_role" "test" { name = "test-role-%[1]s" @@ -863,7 +872,7 @@ resource "aws_iam_role" "test" { "Effect": "Allow", "Principal": { "Service": [ - "gamelift.${data.aws_partition.current.dns_suffix}" + "gamelift.amazonaws.com" ] }, "Action": [ @@ -880,21 +889,23 @@ resource "aws_iam_policy" "test" { path = "/" description = "GameLift Fleet PassRole Policy" - policy = jsonencode({ - "Version" : "2012-10-17", - "Statement" : [ - { - "Effect" : "Allow", - "Action" : [ - "iam:PassRole", - "sts:AssumeRole" - ], - "Resource" : [ - "*" - ] - }, + policy = < Date: Mon, 7 Jun 2021 11:06:05 +0300 Subject: [PATCH 0267/1208] docs --- website/docs/r/ecs_task_definition.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/ecs_task_definition.html.markdown b/website/docs/r/ecs_task_definition.html.markdown index f441a323d053..f1d885c55532 100644 --- a/website/docs/r/ecs_task_definition.html.markdown +++ b/website/docs/r/ecs_task_definition.html.markdown @@ -258,11 +258,11 @@ For more information, see [Specifying an EFS volume in your Task Definition Deve ### fsx_windows_file_server_volume_configuration -For more information, see [Specifying an FSX Windows File Server volume in your Task Definition Developer Guide](https://docs.amazonaws.cn/en_us/AmazonECS/latest/developerguide/tutorial-wfsx-volumes.html) +For more information, see [Specifying an FSX Windows File Server volume in your Task Definition Developer Guide](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/tutorial-wfsx-volumes.html) * `file_system_id` - (Required) The Amazon FSx for Windows File Server file system ID to use. * `root_directory` - (Required) The directory within the Amazon FSx for Windows File Server file system to mount as the root directory inside the host. -* `authorization_config` - (OptiRequiredonal) Configuration block for [authorization](#authorization_config) for the Amazon FSx for Windows File Server file system detailed below. +* `authorization_config` - (Required) Configuration block for [authorization](#authorization_config) for the Amazon FSx for Windows File Server file system detailed below. #### authorization_config From 41c9de57e01bcf51090d0dabe677700a2589e2b1 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 13:31:31 +0300 Subject: [PATCH 0268/1208] add support for domain --- aws/resource_aws_transfer_server.go | 12 +++++++ aws/resource_aws_transfer_server_test.go | 36 ++++++++++++++++++++ website/docs/r/transfer_server.html.markdown | 1 + 3 files changed, 49 insertions(+) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 86a0bd6b24aa..eef991d07cec 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -40,6 +40,13 @@ func resourceAwsTransferServer() *schema.Resource { Optional: true, ValidateFunc: validateArn, }, + "domain": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: transfer.DomainS3, + ValidateFunc: validation.StringInSlice(transfer.Domain_Values(), false), + }, "endpoint": { Type: schema.TypeString, @@ -175,6 +182,10 @@ func resourceAwsTransferServerCreate(d *schema.ResourceData, meta interface{}) e input.Certificate = aws.String(v.(string)) } + if v, ok := d.GetOk("domain"); ok { + input.Domain = aws.String(v.(string)) + } + if v, ok := d.GetOk("endpoint_details"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.EndpointDetails = expandTransferEndpointDetails(v.([]interface{})[0].(map[string]interface{})) @@ -286,6 +297,7 @@ func resourceAwsTransferServerRead(d *schema.ResourceData, meta interface{}) err d.Set("arn", output.Arn) d.Set("certificate", output.Certificate) + d.Set("domain", output.Domain) d.Set("endpoint", meta.(*AWSClient).RegionalHostname(fmt.Sprintf("%s.server.transfer", d.Id()))) if output.EndpointDetails != nil { if err := d.Set("endpoint_details", []interface{}{flattenTransferEndpointDetails(output.EndpointDetails)}); err != nil { diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index c369117b9a2e..1480ef6872c6 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -121,6 +121,7 @@ func TestAccAWSTransferServer_basic(t *testing.T) { testAccCheckAWSTransferServerExists(resourceName, &conf), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "transfer", regexp.MustCompile(`server/.+`)), resource.TestCheckResourceAttr(resourceName, "certificate", ""), + resource.TestCheckResourceAttr(resourceName, "domain", "S3"), testAccMatchResourceAttrRegionalHostname(resourceName, "endpoint", "server.transfer", regexp.MustCompile(`s-[a-z0-9]+`)), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "PUBLIC"), @@ -141,6 +142,33 @@ func TestAccAWSTransferServer_basic(t *testing.T) { }) } +func TestAccAWSTransferServer_domain(t *testing.T) { + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferServerDomainConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "domain", "EFS"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + func TestAccAWSTransferServer_disappears(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" @@ -679,6 +707,14 @@ resource "aws_transfer_server" "test" {} ` } +func testAccAWSTransferServerDomainConfig() string { + return ` +resource "aws_transfer_server" "test" { + domain = "EFS" +} +` +} + func testAccAWSTransferServerSecurityPolicyConfig(policy string) string { return fmt.Sprintf(` resource "aws_transfer_server" "test" { diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index b5f0a9bf96c6..6b172348db8a 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -86,6 +86,7 @@ resource "aws_transfer_server" "example" { The following arguments are supported: * `certificate` - (Optional) The Amazon Resource Name (ARN) of the AWS Certificate Manager (ACM) certificate. This is required when `protocols` is set to `FTPS` +* `domain` - (Optional) The domain of the storage system that is used for file transfers. Valid values are: `S3` and `EFS`. The default value is `S3`. * `protocols` - (Optional) Specifies the file transfer protocol or protocols over which your file transfer protocol client can connect to your server's endpoint. This defaults to `SFTP` . The available protocols are: * `SFTP`: File transfer over SSH * `FTPS`: File transfer with TLS encryption From 116c4f9a805ff9f15fb1cdf155784db0471db1bd Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 13:35:16 +0300 Subject: [PATCH 0269/1208] add domain for data source --- aws/data_source_aws_transfer_server.go | 5 +++++ aws/data_source_aws_transfer_server_test.go | 1 + website/docs/d/transfer_server.html.markdown | 1 + 3 files changed, 7 insertions(+) diff --git a/aws/data_source_aws_transfer_server.go b/aws/data_source_aws_transfer_server.go index 69047839a1af..3359335cd43a 100644 --- a/aws/data_source_aws_transfer_server.go +++ b/aws/data_source_aws_transfer_server.go @@ -20,6 +20,10 @@ func dataSourceAwsTransferServer() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "domain": { + Type: schema.TypeString, + Computed: true, + }, "endpoint": { Type: schema.TypeString, @@ -88,6 +92,7 @@ func dataSourceAwsTransferServerRead(d *schema.ResourceData, meta interface{}) e d.SetId(aws.StringValue(output.ServerId)) d.Set("arn", output.Arn) d.Set("certificate", output.Certificate) + d.Set("domain", output.Domain) d.Set("endpoint", meta.(*AWSClient).RegionalHostname(fmt.Sprintf("%s.server.transfer", serverID))) d.Set("endpoint_type", output.EndpointType) d.Set("identity_provider_type", output.IdentityProviderType) diff --git a/aws/data_source_aws_transfer_server_test.go b/aws/data_source_aws_transfer_server_test.go index 5a0e22104d3a..b70552453010 100644 --- a/aws/data_source_aws_transfer_server_test.go +++ b/aws/data_source_aws_transfer_server_test.go @@ -22,6 +22,7 @@ func TestAccDataSourceAwsTransferServer_basic(t *testing.T) { Config: testAccDataSourceAwsTransferServerConfig_basic, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(datasourceName, "domain", resourceName, "domain"), resource.TestCheckResourceAttrPair(datasourceName, "endpoint", resourceName, "endpoint"), resource.TestCheckResourceAttrPair(datasourceName, "identity_provider_type", resourceName, "identity_provider_type"), resource.TestCheckResourceAttrPair(datasourceName, "logging_role", resourceName, "logging_role"), diff --git a/website/docs/d/transfer_server.html.markdown b/website/docs/d/transfer_server.html.markdown index 5ca0b17bfc13..a0bdfb807caa 100644 --- a/website/docs/d/transfer_server.html.markdown +++ b/website/docs/d/transfer_server.html.markdown @@ -27,6 +27,7 @@ data "aws_transfer_server" "example" { * `arn` - Amazon Resource Name (ARN) of Transfer Server. * `certificate` - The ARN of any certificate. +* `domain` - The domain of the storage system that is used for file transfers. * `endpoint` - The endpoint of the Transfer Server (e.g. `s-12345678.server.transfer.REGION.amazonaws.com`). * `endpoint_type` - The type of endpoint that the server is connected to. * `identity_provider_type` - The mode of authentication enabled for this service. The default value is `SERVICE_MANAGED`, which allows you to store and access SFTP user credentials within the service. `API_GATEWAY` indicates that user authentication requires a call to an API Gateway endpoint URL provided by you to integrate an identity provider of your choice. From 1c655a809d437915cb129cafd9ed9c9adaf00340 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 13:36:45 +0300 Subject: [PATCH 0270/1208] changelog --- .changelog/19691.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/19691.txt diff --git a/.changelog/19691.txt b/.changelog/19691.txt new file mode 100644 index 000000000000..832d0c032589 --- /dev/null +++ b/.changelog/19691.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_transfer_server: Add `domain` argument. +``` + +```release-note:enhancement +data-source/aws_transfer_server: Add `domain` attribute. +``` \ No newline at end of file From 2b7a455339b3e0d303b0342d98cb2cebde143acf Mon Sep 17 00:00:00 2001 From: changelogbot Date: Mon, 7 Jun 2021 11:25:35 +0000 Subject: [PATCH 0271/1208] Update CHANGELOG.md for #19687 --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6a7ff3a80aa..6a6a4fbe89ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,15 @@ ## 3.45.0 (Unreleased) + +ENHANCEMENTS: + +* resource/aws_ecs_task_definition: Add plan time validation for `family` and `requires_compatibilities`. ([#19670](https://github.com/hashicorp/terraform-provider-aws/issues/19670)) +* resource/aws_ecs_task_definition: Add support for `fsx_windows_file_server_volume_configuration`. ([#19670](https://github.com/hashicorp/terraform-provider-aws/issues/19670)) +* resource/aws_fsx_lustre_filesystem: Add `data_compression_type` argument. ([#19664](https://github.com/hashicorp/terraform-provider-aws/issues/19664)) + +BUG FIXES: + +* resource/aws_lambda_function: Prevents perpetual diff in `vpc_config` ([#17610](https://github.com/hashicorp/terraform-provider-aws/issues/17610)) + ## 3.44.0 (June 03, 2021) FEATURES: From 7577840b7453a36f075f53c00199b2e207fe9a1f Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 15:19:08 +0300 Subject: [PATCH 0272/1208] add ephemral storage --- aws/resource_aws_ecs_task_definition.go | 45 ++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_ecs_task_definition.go b/aws/resource_aws_ecs_task_definition.go index 243d5d249e37..9e6aa7a79dfe 100644 --- a/aws/resource_aws_ecs_task_definition.go +++ b/aws/resource_aws_ecs_task_definition.go @@ -96,7 +96,22 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { }, ValidateFunc: validateAwsEcsTaskDefinitionContainerDefinitions, }, - + "ephemeral_storage": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size_in_gib": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(21, 200), + }, + }, + }, + }, "task_role_arn": { Type: schema.TypeString, Optional: true, @@ -472,6 +487,10 @@ func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{} input.ProxyConfiguration = expandEcsTaskDefinitionProxyConfiguration(proxyConfigs) } + if v, ok := d.GetOk("ephemeral_storage"); ok && len(v.([]interface{})) > 0 { + input.EphemeralStorage = expandEcsTaskDefinitionEphemeralStorage(v.([]interface{})) + } + log.Printf("[DEBUG] Registering ECS task definition: %s", input) out, err := conn.RegisterTaskDefinition(&input) if err != nil { @@ -571,6 +590,9 @@ func resourceAwsEcsTaskDefinitionRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("error setting proxy_configuration: %w", err) } + if err := d.Set("ephemeral_storage", flattenEcsTaskDefinitionEphemeralStorage(taskDefinition.EphemeralStorage)); err != nil { + return fmt.Errorf("error setting ephemeral_storage: %w", err) + } return nil } @@ -1066,3 +1088,24 @@ func expandEcsContainerDefinitions(rawDefinitions string) ([]*ecs.ContainerDefin return definitions, nil } + +func expandEcsTaskDefinitionEphemeralStorage(config []interface{}) *ecs.EphemeralStorage { + configMap := config[0].(map[string]interface{}) + + es := &ecs.EphemeralStorage{ + SizeInGiB: aws.Int64(int64(configMap["size_in_gib"].(int))), + } + + return es +} + +func flattenEcsTaskDefinitionEphemeralStorage(pc *ecs.EphemeralStorage) []map[string]interface{} { + if pc == nil { + return nil + } + + m := make(map[string]interface{}) + m["size_in_gib"] = aws.Int64Value(pc.SizeInGiB) + + return []map[string]interface{}{m} +} From c1aaf09d85cbaa393d615bd7ce7336a2f043d141 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 15:22:27 +0300 Subject: [PATCH 0273/1208] docs --- website/docs/r/ecs_task_definition.html.markdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/docs/r/ecs_task_definition.html.markdown b/website/docs/r/ecs_task_definition.html.markdown index f1d885c55532..eaeb3d34b0e9 100644 --- a/website/docs/r/ecs_task_definition.html.markdown +++ b/website/docs/r/ecs_task_definition.html.markdown @@ -217,6 +217,7 @@ The following arguments are optional: * `pid_mode` - (Optional) Process namespace to use for the containers in the task. The valid values are `host` and `task`. * `placement_constraints` - (Optional) Configuration block for rules that are taken into consideration during task placement. Maximum number of `placement_constraints` is `10`. [Detailed below](#placement_constraints). * `proxy_configuration` - (Optional) Configuration block for the App Mesh proxy. [Detailed below.](#proxy_configuration) +* `ephemeral_storage` - (Optional) The amount of ephemeral storage to allocate for the task. This parameter is used to expand the total amount of ephemeral storage available, beyond the default amount, for tasks hosted on AWS Fargate. See [Ephemeral Storage](#ephemeral_storage). * `requires_compatibilities` - (Optional) Set of launch types required by the task. The valid values are `EC2` and `FARGATE`. * `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. * `task_role_arn` - (Optional) ARN of IAM role that allows your Amazon ECS container task to make calls to other AWS services. @@ -280,6 +281,10 @@ For more information, see [Specifying an FSX Windows File Server volume in your * `properties` - (Required) Set of network configuration parameters to provide the Container Network Interface (CNI) plugin, specified a key-value mapping. * `type` - (Optional) Proxy type. The default value is `APPMESH`. The only supported value is `APPMESH`. +### ephemeral_storage + +* `size_in_gib` - (Required) The total amount, in GiB, of ephemeral storage to set for the task. The minimum supported value is `21` GiB and the maximum supported value is `200` GiB. + ### inference_accelerator * `device_name` - (Required) Elastic Inference accelerator device name. The deviceName must also be referenced in a container definition as a ResourceRequirement. From 9fffe79c65818538ea837b377eb391d3f7cf83eb Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 15:23:00 +0300 Subject: [PATCH 0274/1208] tests --- aws/resource_aws_ecs_task_definition_test.go | 63 ++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index bf0159411352..6574fb341595 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -725,6 +725,38 @@ func TestAccAWSEcsTaskDefinition_Fargate(t *testing.T) { }) } +func TestAccAWSEcsTaskDefinition_Fargate_ephemeralStorage(t *testing.T) { + var conf ecs.TaskDefinition + + tdName := acctest.RandomWithPrefix("tf-acc-td-fargate") + resourceName := "aws_ecs_task_definition.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ecs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEcsTaskDefinitionFargateEphemeralStorage(tdName, `[{"protocol": "tcp", "containerPort": 8000}]`), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcsTaskDefinitionExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "requires_compatibilities.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cpu", "256"), + resource.TestCheckResourceAttr(resourceName, "memory", "512"), + resource.TestCheckResourceAttr(resourceName, "ephemeral_storage.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ephemeral_storage.0.size_in_gib", "30"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAWSEcsTaskDefinitionImportStateIdFunc(resourceName), + ImportStateVerify: true, + }, + }, + }) +} func TestAccAWSEcsTaskDefinition_ExecutionRole(t *testing.T) { var conf ecs.TaskDefinition @@ -1401,6 +1433,37 @@ TASK_DEFINITION `, tdName, portMappings) } +func testAccAWSEcsTaskDefinitionFargateEphemeralStorage(tdName, portMappings string) string { + return fmt.Sprintf(` +resource "aws_ecs_task_definition" "test" { + family = "%s" + network_mode = "awsvpc" + requires_compatibilities = ["FARGATE"] + cpu = "256" + memory = "512" + + ephemeral_storage { + size_in_gib = 30 + } + + container_definitions = < Date: Mon, 7 Jun 2021 15:26:30 +0300 Subject: [PATCH 0275/1208] changelog --- .changelog/19694.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19694.txt diff --git a/.changelog/19694.txt b/.changelog/19694.txt new file mode 100644 index 000000000000..1bc3a085782d --- /dev/null +++ b/.changelog/19694.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_ecs_task_definition: Add support for `ephemeral_storage`. +``` \ No newline at end of file From 1048fbc65d658b05bfbdb76db52c47de6322d01d Mon Sep 17 00:00:00 2001 From: nikhil-goenka <70277861+nikhil-goenka@users.noreply.github.com> Date: Mon, 7 Jun 2021 18:43:53 +0530 Subject: [PATCH 0276/1208] F/aws acmpca certificate authority (#19681) * Support for s3_object_acl * Add CHANGELOG entry. Co-authored-by: Kit Ewbank --- .changelog/19681.txt | 3 + ...source_aws_acmpca_certificate_authority.go | 4 ++ ...e_aws_acmpca_certificate_authority_test.go | 71 +++++++++++++++++++ ...acmpca_certificate_authority.html.markdown | 1 + 4 files changed, 79 insertions(+) create mode 100644 .changelog/19681.txt diff --git a/.changelog/19681.txt b/.changelog/19681.txt new file mode 100644 index 000000000000..20b49f868039 --- /dev/null +++ b/.changelog/19681.txt @@ -0,0 +1,3 @@ +```release-note:bug +data-source/aws_acmpca_certificate_authority: Fix `error setting tags` +``` \ No newline at end of file diff --git a/aws/data_source_aws_acmpca_certificate_authority.go b/aws/data_source_aws_acmpca_certificate_authority.go index aaf324a18dc5..7caf8ca0a6e8 100644 --- a/aws/data_source_aws_acmpca_certificate_authority.go +++ b/aws/data_source_aws_acmpca_certificate_authority.go @@ -71,6 +71,10 @@ func dataSourceAwsAcmpcaCertificateAuthority() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "s3_object_acl": { + Type: schema.TypeString, + Computed: true, + }, }, }, }, diff --git a/aws/data_source_aws_acmpca_certificate_authority_test.go b/aws/data_source_aws_acmpca_certificate_authority_test.go index f57803c9c891..8cf446889fc8 100644 --- a/aws/data_source_aws_acmpca_certificate_authority_test.go +++ b/aws/data_source_aws_acmpca_certificate_authority_test.go @@ -43,6 +43,45 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_basic(t *testing.T) { }) } +func TestAccDataSourceAwsAcmpcaCertificateAuthority_S3ObjectAcl(t *testing.T) { + resourceName := "aws_acmpca_certificate_authority.test" + datasourceName := "data.aws_acmpca_certificate_authority.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_NonExistent, + ExpectError: regexp.MustCompile(`(AccessDeniedException|ResourceNotFoundException)`), + }, + { + Config: testAccDataSourceAwsAcmpcaCertificateAuthorityConfigS3ObjectAcl_ARN, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(datasourceName, "certificate", resourceName, "certificate"), + resource.TestCheckResourceAttrPair(datasourceName, "certificate_chain", resourceName, "certificate_chain"), + resource.TestCheckResourceAttrPair(datasourceName, "certificate_signing_request", resourceName, "certificate_signing_request"), + resource.TestCheckResourceAttrPair(datasourceName, "not_after", resourceName, "not_after"), + resource.TestCheckResourceAttrPair(datasourceName, "not_before", resourceName, "not_before"), + resource.TestCheckResourceAttrPair(datasourceName, "revocation_configuration.#", resourceName, "revocation_configuration.#"), + resource.TestCheckResourceAttrPair(datasourceName, "revocation_configuration.0.crl_configuration.#", resourceName, "revocation_configuration.0.crl_configuration.#"), + resource.TestCheckResourceAttrPair(datasourceName, "revocation_configuration.0.crl_configuration.0.enabled", resourceName, "revocation_configuration.0.crl_configuration.0.enabled"), + resource.TestCheckResourceAttrPair(datasourceName, "revocation_configuration.0.crl_configuration.0.custom_cname", resourceName, "revocation_configuration.0.crl_configuration.0.custom_cname"), + resource.TestCheckResourceAttrPair(datasourceName, "revocation_configuration.0.crl_configuration.0.expiration_in_days", resourceName, "revocation_configuration.0.crl_configuration.0.expiration_in_days"), + resource.TestCheckResourceAttrPair(datasourceName, "revocation_configuration.0.crl_configuration.0.s3_bucket_name", resourceName, "revocation_configuration.0.crl_configuration.0.s3_bucket_name"), + resource.TestCheckResourceAttrPair(datasourceName, "revocation_configuration.0.crl_configuration.0.s3_object_acl", resourceName, "revocation_configuration.0.crl_configuration.0.s3_object_acl"), + resource.TestCheckResourceAttrPair(datasourceName, "serial", resourceName, "serial"), + resource.TestCheckResourceAttrPair(datasourceName, "status", resourceName, "status"), + resource.TestCheckResourceAttrPair(datasourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(datasourceName, "type", resourceName, "type"), + ), + }, + }, + }) +} + const testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_ARN = ` resource "aws_acmpca_certificate_authority" "wrong" { permanent_deletion_time_in_days = 7 @@ -75,6 +114,38 @@ data "aws_acmpca_certificate_authority" "test" { } ` +const testAccDataSourceAwsAcmpcaCertificateAuthorityConfigS3ObjectAcl_ARN = ` +resource "aws_acmpca_certificate_authority" "wrong" { + permanent_deletion_time_in_days = 7 + + certificate_authority_configuration { + key_algorithm = "RSA_4096" + signing_algorithm = "SHA512WITHRSA" + + subject { + common_name = "terraformtesting.com" + } + } +} + +resource "aws_acmpca_certificate_authority" "test" { + permanent_deletion_time_in_days = 7 + + certificate_authority_configuration { + key_algorithm = "RSA_4096" + signing_algorithm = "SHA512WITHRSA" + + subject { + common_name = "terraformtesting.com" + } + } +} + +data "aws_acmpca_certificate_authority" "test" { + arn = aws_acmpca_certificate_authority.test.arn +} +` + //lintignore:AWSAT003,AWSAT005 const testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_NonExistent = ` data "aws_acmpca_certificate_authority" "test" { diff --git a/website/docs/d/acmpca_certificate_authority.html.markdown b/website/docs/d/acmpca_certificate_authority.html.markdown index 1b456f10e1ee..d65d632d7f07 100644 --- a/website/docs/d/acmpca_certificate_authority.html.markdown +++ b/website/docs/d/acmpca_certificate_authority.html.markdown @@ -40,6 +40,7 @@ In addition to all arguments above, the following attributes are exported: * `revocation_configuration.0.crl_configuration.0.enabled` - Boolean value that specifies whether certificate revocation lists (CRLs) are enabled. * `revocation_configuration.0.crl_configuration.0.expiration_in_days` - Number of days until a certificate expires. * `revocation_configuration.0.crl_configuration.0.s3_bucket_name` - Name of the S3 bucket that contains the CRL. + * `revocation_configuration.0.crl_configuration.0.s3_object_acl` - Whether the CRL is publicly readable or privately held in the CRL Amazon S3 bucket. * `serial` - Serial number of the certificate authority. Only available after the certificate authority certificate has been imported. * `status` - Status of the certificate authority. * `tags` - Specifies a key-value map of user-defined tags that are attached to the certificate authority. From 72a54fd68aaea0d8117169f87d84dd7846f86f45 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 7 Jun 2021 10:44:16 -0400 Subject: [PATCH 0277/1208] r/aws_sqs_queue_policy: Add 'waiter.QueueAttributesPropagated'. --- aws/internal/service/sqs/finder/finder.go | 38 ++++++ aws/internal/service/sqs/waiter/waiter.go | 70 ++++++++++ aws/resource_aws_sqs_queue_policy.go | 150 ++++++++-------------- aws/resource_aws_sqs_queue_policy_test.go | 103 +++++++++++---- 4 files changed, 244 insertions(+), 117 deletions(-) diff --git a/aws/internal/service/sqs/finder/finder.go b/aws/internal/service/sqs/finder/finder.go index 545a97d81492..4c8c5892c5c1 100644 --- a/aws/internal/service/sqs/finder/finder.go +++ b/aws/internal/service/sqs/finder/finder.go @@ -35,3 +35,41 @@ func QueueAttributesByURL(conn *sqs.SQS, url string) (map[string]string, error) return aws.StringValueMap(output.Attributes), nil } + +func QueuePolicyByURL(conn *sqs.SQS, url string) (string, error) { + input := &sqs.GetQueueAttributesInput{ + AttributeNames: aws.StringSlice([]string{sqs.QueueAttributeNamePolicy}), + QueueUrl: aws.String(url), + } + + output, err := conn.GetQueueAttributes(input) + + if tfawserr.ErrCodeEquals(err, sqs.ErrCodeQueueDoesNotExist) { + return "", &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return "", err + } + + if output == nil || output.Attributes == nil { + return "", &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + v, ok := output.Attributes[sqs.QueueAttributeNamePolicy] + + if !ok || aws.StringValue(v) == "" { + return "", &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return aws.StringValue(v), nil +} diff --git a/aws/internal/service/sqs/waiter/waiter.go b/aws/internal/service/sqs/waiter/waiter.go index b859970dc619..ad245a736220 100644 --- a/aws/internal/service/sqs/waiter/waiter.go +++ b/aws/internal/service/sqs/waiter/waiter.go @@ -1,10 +1,14 @@ package waiter import ( + "fmt" "time" "github.com/aws/aws-sdk-go/service/sqs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + awspolicy "github.com/jen20/awspolicyequivalence" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -24,6 +28,72 @@ const ( queueStateExists = "exists" ) +func QueueAttributesPropagated(conn *sqs.SQS, url string, expected map[string]string) error { + attributesMatch := func(got map[string]string) error { + for k, e := range expected { + g, ok := got[k] + + if !ok { + return fmt.Errorf("SQS Queue attribute (%s) not available", k) + } + + switch k { + case sqs.QueueAttributeNamePolicy: + equivalent, err := awspolicy.PoliciesAreEquivalent(g, e) + + if err != nil { + return nil + } + + if !equivalent { + return fmt.Errorf("SQS Queue policies are not equivalent") + } + default: + if g != e { + return fmt.Errorf("SQS Queue attribute (%s) got: %s, expected: %s", k, g, e) + } + } + } + + return nil + } + + var got map[string]string + err := resource.Retry(QueueAttributePropagationTimeout, func() *resource.RetryError { + var err error + + got, err = finder.QueueAttributesByURL(conn, url) + + if err != nil { + return resource.NonRetryableError(err) + } + + err = attributesMatch(got) + + if err != nil { + return resource.RetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + got, err = finder.QueueAttributesByURL(conn, url) + + if err != nil { + return err + } + + err = attributesMatch(got) + + if err != nil { + return err + } + } + + return nil +} + func QueueDeleted(conn *sqs.SQS, url string) error { stateConf := &resource.StateChangeConf{ Pending: []string{queueStateExists}, diff --git a/aws/resource_aws_sqs_queue_policy.go b/aws/resource_aws_sqs_queue_policy.go index 5c8442122864..7e7c9736c776 100644 --- a/aws/resource_aws_sqs_queue_policy.go +++ b/aws/resource_aws_sqs_queue_policy.go @@ -3,14 +3,21 @@ package aws import ( "fmt" "log" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/sqs" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "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" - awspolicy "github.com/jen20/awspolicyequivalence" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +var ( + sqsQueueEmptyPolicyAttributes = map[string]string{ + sqs.QueueAttributeNamePolicy: "", + } ) func resourceAwsSqsQueuePolicy() *schema.Resource { @@ -27,121 +34,68 @@ func resourceAwsSqsQueuePolicy() *schema.Resource { SchemaVersion: 1, Schema: map[string]*schema.Schema{ - "queue_url": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "policy": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs, }, + + "queue_url": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, }, } } func resourceAwsSqsQueuePolicyUpsert(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).sqsconn - policy := d.Get("policy").(string) - url := d.Get("queue_url").(string) - sqaInput := &sqs.SetQueueAttributesInput{ - QueueUrl: aws.String(url), - Attributes: aws.StringMap(map[string]string{ - sqs.QueueAttributeNamePolicy: policy, - }), + policyAttributes := map[string]string{ + sqs.QueueAttributeNamePolicy: d.Get("policy").(string), } - log.Printf("[DEBUG] Updating SQS attributes: %s", sqaInput) - _, err := conn.SetQueueAttributes(sqaInput) - if err != nil { - return fmt.Errorf("Error updating SQS attributes: %s", err) + url := d.Get("queue_url").(string) + input := &sqs.SetQueueAttributesInput{ + Attributes: aws.StringMap(policyAttributes), + QueueUrl: aws.String(url), } - // https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SetQueueAttributes.html - // When you change a queue's attributes, the change can take up to 60 seconds - // for most of the attributes to propagate throughout the Amazon SQS system. - gqaInput := &sqs.GetQueueAttributesInput{ - QueueUrl: aws.String(url), - AttributeNames: []*string{aws.String(sqs.QueueAttributeNamePolicy)}, - } - notUpdatedError := fmt.Errorf("SQS attribute %s not updated", sqs.QueueAttributeNamePolicy) - var out *sqs.GetQueueAttributesOutput - err = resource.Retry(1*time.Minute, func() *resource.RetryError { - log.Printf("[DEBUG] Reading SQS attributes: %s", gqaInput) - var err error - out, err = conn.GetQueueAttributes(gqaInput) - if err != nil { - return resource.NonRetryableError(err) - } - queuePolicy, ok := out.Attributes[sqs.QueueAttributeNamePolicy] - if !ok { - log.Printf("[DEBUG] SQS attribute %s not found - retrying", sqs.QueueAttributeNamePolicy) - return resource.RetryableError(notUpdatedError) - } - - equivalent, err := awspolicy.PoliciesAreEquivalent(aws.StringValue(queuePolicy), policy) - if err != nil { - return resource.NonRetryableError(err) - } - if !equivalent { - log.Printf("[DEBUG] SQS attribute %s not updated - retrying", sqs.QueueAttributeNamePolicy) - return resource.RetryableError(notUpdatedError) - } - return nil - }) - if isResourceTimeoutError(err) { - out, err = conn.GetQueueAttributes(gqaInput) - if err == nil { - queuePolicy, ok := out.Attributes[sqs.QueueAttributeNamePolicy] - if !ok { - return notUpdatedError - } - - var equivalent bool - equivalent, err = awspolicy.PoliciesAreEquivalent(aws.StringValue(queuePolicy), policy) - if !equivalent { - return notUpdatedError - } - } - } + log.Printf("[DEBUG] Setting SQS Queue Policy: %s", input) + _, err := conn.SetQueueAttributes(input) + if err != nil { - return fmt.Errorf("Error updating SQS queue attributes: %s", err) + return fmt.Errorf("error setting SQS Queue Policy (%s): %w", url, err) } d.SetId(url) + err = waiter.QueueAttributesPropagated(conn, d.Id(), policyAttributes) + + if err != nil { + return fmt.Errorf("error waiting for SQS Queue Policy (%s) to be set: %w", d.Id(), err) + } + return resourceAwsSqsQueuePolicyRead(d, meta) } func resourceAwsSqsQueuePolicyRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).sqsconn - out, err := conn.GetQueueAttributes(&sqs.GetQueueAttributesInput{ - QueueUrl: aws.String(d.Id()), - AttributeNames: []*string{aws.String(sqs.QueueAttributeNamePolicy)}, - }) - if err != nil { - if isAWSErr(err, sqs.ErrCodeQueueDoesNotExist, "") { - log.Printf("[WARN] SQS Queue (%s) not found", d.Id()) - d.SetId("") - return nil - } - return err - } - if out == nil { - return fmt.Errorf("Received empty response for SQS queue %s", d.Id()) + policy, err := finder.QueuePolicyByURL(conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] SQS Queue Policy (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil } - policy, ok := out.Attributes[sqs.QueueAttributeNamePolicy] - if ok { - d.Set("policy", policy) - } else { - d.Set("policy", "") + if err != nil { + return fmt.Errorf("error reading SQS Queue Policy (%s): %w", d.Id(), err) } + d.Set("policy", policy) d.Set("queue_url", d.Id()) return nil @@ -150,15 +104,25 @@ func resourceAwsSqsQueuePolicyRead(d *schema.ResourceData, meta interface{}) err func resourceAwsSqsQueuePolicyDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).sqsconn - log.Printf("[DEBUG] Deleting SQS Queue Policy of %s", d.Id()) + log.Printf("[DEBUG] Deleting SQS Queue Policy: %s", d.Id()) _, err := conn.SetQueueAttributes(&sqs.SetQueueAttributesInput{ - QueueUrl: aws.String(d.Id()), - Attributes: aws.StringMap(map[string]string{ - sqs.QueueAttributeNamePolicy: "", - }), + Attributes: aws.StringMap(sqsQueueEmptyPolicyAttributes), + QueueUrl: aws.String(d.Id()), }) + + if tfawserr.ErrCodeEquals(err, sqs.ErrCodeQueueDoesNotExist) { + return nil + } + if err != nil { - return fmt.Errorf("Error deleting SQS Queue policy: %s", err) + return fmt.Errorf("error deleting SQS Queue Policy (%s): %w", d.Id(), err) } + + err = waiter.QueueAttributesPropagated(conn, d.Id(), sqsQueueEmptyPolicyAttributes) + + if err != nil { + return fmt.Errorf("error waiting for SQS Queue Policy (%s) to delete: %w", d.Id(), err) + } + return nil } diff --git a/aws/resource_aws_sqs_queue_policy_test.go b/aws/resource_aws_sqs_queue_policy_test.go index 727fefc61855..1f24a156b266 100644 --- a/aws/resource_aws_sqs_queue_policy_test.go +++ b/aws/resource_aws_sqs_queue_policy_test.go @@ -2,7 +2,6 @@ package aws import ( "fmt" - "regexp" "testing" "github.com/aws/aws-sdk-go/service/sqs" @@ -23,11 +22,10 @@ func TestAccAWSSQSQueuePolicy_basic(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSPolicyConfigBasic(rName), + Config: testAccAWSSQSPolicyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(queueResourceName, &queueAttributes), - resource.TestMatchResourceAttr(resourceName, "policy", - regexp.MustCompile("^{\"Version\":\"2012-10-17\".+")), + resource.TestCheckResourceAttrSet(resourceName, "policy"), ), }, { @@ -36,7 +34,7 @@ func TestAccAWSSQSQueuePolicy_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSSQSPolicyConfigBasic(rName), + Config: testAccAWSSQSPolicyConfig(rName), PlanOnly: true, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "policy", queueResourceName, "policy"), @@ -46,6 +44,30 @@ func TestAccAWSSQSQueuePolicy_basic(t *testing.T) { }) } +func TestAccAWSSQSQueuePolicy_disappears(t *testing.T) { + var queueAttributes map[string]string + resourceName := "aws_sqs_queue_policy.test" + queueResourceName := "aws_sqs_queue.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSQSQueueDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSQSPolicyConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSQSQueueExists(queueResourceName, &queueAttributes), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueuePolicy(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func TestAccAWSSQSQueuePolicy_disappears_queue(t *testing.T) { var queueAttributes map[string]string queueResourceName := "aws_sqs_queue.test" @@ -58,7 +80,7 @@ func TestAccAWSSQSQueuePolicy_disappears_queue(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSPolicyConfigBasic(rName), + Config: testAccAWSSQSPolicyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(queueResourceName, &queueAttributes), testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueue(), queueResourceName), @@ -69,7 +91,7 @@ func TestAccAWSSQSQueuePolicy_disappears_queue(t *testing.T) { }) } -func TestAccAWSSQSQueuePolicy_disappears(t *testing.T) { +func TestAccAWSSQSQueuePolicy_Update(t *testing.T) { var queueAttributes map[string]string resourceName := "aws_sqs_queue_policy.test" queueResourceName := "aws_sqs_queue.test" @@ -82,18 +104,28 @@ func TestAccAWSSQSQueuePolicy_disappears(t *testing.T) { CheckDestroy: testAccCheckAWSSQSQueueDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSQSPolicyConfigBasic(rName), + Config: testAccAWSSQSPolicyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSQSQueueExists(queueResourceName, &queueAttributes), - testAccCheckResourceDisappears(testAccProvider, resourceAwsSqsQueuePolicy(), resourceName), + resource.TestCheckResourceAttrSet(resourceName, "policy"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSSQSPolicyConfigUpdated(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(resourceName, "policy"), ), - ExpectNonEmptyPlan: true, }, }, }) } -func testAccAWSSQSPolicyConfigBasic(rName string) string { +func testAccAWSSQSPolicyConfig(rName string) string { return fmt.Sprintf(` resource "aws_sqs_queue" "test" { name = %[1]q @@ -105,21 +137,44 @@ resource "aws_sqs_queue_policy" "test" { policy = < Date: Mon, 7 Jun 2021 11:13:53 -0400 Subject: [PATCH 0278/1208] r/aws_sqs_queue: Use 'waiter.QueueAttributesPropagated'. --- aws/internal/json/equivalence.go | 37 +++++++++++++ aws/internal/json/equivalence_test.go | 65 +++++++++++++++++++++++ aws/internal/service/sqs/waiter/waiter.go | 5 ++ aws/resource_aws_sqs_queue.go | 12 +++++ 4 files changed, 119 insertions(+) create mode 100644 aws/internal/json/equivalence.go create mode 100644 aws/internal/json/equivalence_test.go diff --git a/aws/internal/json/equivalence.go b/aws/internal/json/equivalence.go new file mode 100644 index 000000000000..4cc8dd249ae1 --- /dev/null +++ b/aws/internal/json/equivalence.go @@ -0,0 +1,37 @@ +package json + +import ( + "bytes" + "encoding/json" + "reflect" +) + +// BytesEqual compares two arrays of JSON bytes and returns true if the unmarshaled objects represented by the bytes +// are equal according to `reflect.DeepEqual`. +func BytesEqual(b1, b2 []byte) bool { + var o1 interface{} + if err := json.Unmarshal(b1, &o1); err != nil { + return false + } + + var o2 interface{} + if err := json.Unmarshal(b2, &o2); err != nil { + return false + } + + return reflect.DeepEqual(o1, o2) +} + +func StringsEquivalent(s1, s2 string) bool { + b1 := bytes.NewBufferString("") + if err := json.Compact(b1, []byte(s1)); err != nil { + return false + } + + b2 := bytes.NewBufferString("") + if err := json.Compact(b2, []byte(s2)); err != nil { + return false + } + + return BytesEqual(b1.Bytes(), b2.Bytes()) +} diff --git a/aws/internal/json/equivalence_test.go b/aws/internal/json/equivalence_test.go new file mode 100644 index 000000000000..15a863ee8b39 --- /dev/null +++ b/aws/internal/json/equivalence_test.go @@ -0,0 +1,65 @@ +package json + +import ( + "testing" +) + +func TestBytesEqualQuotedAndUnquoted(t *testing.T) { + unquoted := `{"test": "test"}` + quoted := "{\"test\": \"test\"}" + + if !BytesEqual([]byte(unquoted), []byte(quoted)) { + t.Errorf("Expected BytesEqual to return true for %s == %s", unquoted, quoted) + } + + unquotedDiff := `{"test": "test"}` + quotedDiff := "{\"test\": \"tested\"}" + + if BytesEqual([]byte(unquotedDiff), []byte(quotedDiff)) { + t.Errorf("Expected BytesEqual to return false for %s == %s", unquotedDiff, quotedDiff) + } +} + +func TestBytesEqualWhitespaceAndNoWhitespace(t *testing.T) { + noWhitespace := `{"test":"test"}` + whitespace := ` +{ + "test": "test" +}` + + if !BytesEqual([]byte(noWhitespace), []byte(whitespace)) { + t.Errorf("Expected BytesEqual to return true for %s == %s", noWhitespace, whitespace) + } + + noWhitespaceDiff := `{"test":"test"}` + whitespaceDiff := ` +{ + "test": "tested" +}` + + if BytesEqual([]byte(noWhitespaceDiff), []byte(whitespaceDiff)) { + t.Errorf("Expected BytesEqual to return false for %s == %s", noWhitespaceDiff, whitespaceDiff) + } +} + +func TestStringsEquivalentWhitespaceAndNoWhitespace(t *testing.T) { + noWhitespace := `{"test":"test"}` + whitespace := ` +{ + "test": "test" +}` + + if !StringsEquivalent(noWhitespace, whitespace) { + t.Errorf("Expected StringsEquivalent to return true for %s == %s", noWhitespace, whitespace) + } + + noWhitespaceDiff := `{"test":"test"}` + whitespaceDiff := ` +{ + "test": "tested" +}` + + if StringsEquivalent(noWhitespaceDiff, whitespaceDiff) { + t.Errorf("Expected StringsEquivalent to return false for %s == %s", noWhitespaceDiff, whitespaceDiff) + } +} diff --git a/aws/internal/service/sqs/waiter/waiter.go b/aws/internal/service/sqs/waiter/waiter.go index ad245a736220..97249d0353f1 100644 --- a/aws/internal/service/sqs/waiter/waiter.go +++ b/aws/internal/service/sqs/waiter/waiter.go @@ -7,6 +7,7 @@ import ( "github.com/aws/aws-sdk-go/service/sqs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" awspolicy "github.com/jen20/awspolicyequivalence" + tfjson "github.com/terraform-providers/terraform-provider-aws/aws/internal/json" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -48,6 +49,10 @@ func QueueAttributesPropagated(conn *sqs.SQS, url string, expected map[string]st if !equivalent { return fmt.Errorf("SQS Queue policies are not equivalent") } + case sqs.QueueAttributeNameRedrivePolicy: + if !tfjson.StringsEquivalent(g, e) { + return fmt.Errorf("SQS Queue redrive policies are not equivalent") + } default: if g != e { return fmt.Errorf("SQS Queue attribute (%s) got: %s, expected: %s", k, g, e) diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index c321ffb1ecb3..74e0746eee99 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -240,6 +240,12 @@ func resourceAwsSqsQueueCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(aws.StringValue(output.QueueUrl)) + err = waiter.QueueAttributesPropagated(conn, d.Id(), attributes) + + if err != nil { + return fmt.Errorf("error waiting for SQS Queue (%s) attributes to create: %w", d.Id(), err) + } + // Tag-on-create is currently only supported in AWS Commercial if len(tags) > 0 && meta.(*AWSClient).partition != endpoints.AwsPartitionID { if err := keyvaluetags.SqsUpdateTags(conn, d.Id(), nil, tags); err != nil { @@ -332,6 +338,12 @@ func resourceAwsSqsQueueUpdate(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("error updating SQS Queue (%s) attributes: %w", d.Id(), err) } + + err = waiter.QueueAttributesPropagated(conn, d.Id(), attributes) + + if err != nil { + return fmt.Errorf("error waiting for SQS Queue (%s) attributes to update: %w", d.Id(), err) + } } if d.HasChange("tags_all") { From e1ef845dd82982fe81e27b464083a0ead7e89327 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 7 Jun 2021 11:48:03 -0400 Subject: [PATCH 0279/1208] r/aws_sqs_queue: Allow 'visibility_timeout_seconds = 0' on creation (#14166). --- aws/internal/attrmap/attrmap.go | 40 +++++++++++++++++++----------- aws/resource_aws_sqs_queue.go | 2 +- aws/resource_aws_sqs_queue_test.go | 36 +++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/aws/internal/attrmap/attrmap.go b/aws/internal/attrmap/attrmap.go index b339742c93c0..094f0e7ff45f 100644 --- a/aws/internal/attrmap/attrmap.go +++ b/aws/internal/attrmap/attrmap.go @@ -11,8 +11,9 @@ import ( // AttributeMap represents a map of Terraform resource attribute name to AWS API attribute name. // Useful for SQS Queue or SNS Topic attribute handling. type attributeInfo struct { - apiAttributeName string - tfType schema.ValueType + apiAttributeName string + tfType schema.ValueType + tfOptionalComputed bool } type AttributeMap map[string]attributeInfo @@ -23,10 +24,16 @@ func New(attrMap map[string]string, schemaMap map[string]*schema.Schema) Attribu for tfAttributeName, apiAttributeName := range attrMap { if s, ok := schemaMap[tfAttributeName]; ok { - attributeMap[tfAttributeName] = attributeInfo{ + attributeInfo := attributeInfo{ apiAttributeName: apiAttributeName, tfType: s.Type, } + + if s.Optional && s.Computed { + attributeInfo.tfOptionalComputed = true + } + + attributeMap[tfAttributeName] = attributeInfo } else { log.Printf("[ERROR] Unknown attribute: %s", tfAttributeName) } @@ -78,20 +85,25 @@ func (m AttributeMap) ResourceDataToApiAttributesCreate(d *schema.ResourceData) apiAttributes := map[string]string{} for tfAttributeName, attributeInfo := range m { - if v, ok := d.GetOk(tfAttributeName); ok { - var apiAttributeValue string + var apiAttributeValue string - switch t := attributeInfo.tfType; t { - case schema.TypeBool: - apiAttributeValue = strconv.FormatBool(v.(bool)) - case schema.TypeInt: - apiAttributeValue = strconv.Itoa(v.(int)) - case schema.TypeString: - apiAttributeValue = v.(string) - default: - return nil, fmt.Errorf("attribute %s is of unsupported type: %d", tfAttributeName, t) + switch v, t := d.Get(tfAttributeName), attributeInfo.tfType; t { + case schema.TypeBool: + if v := v.(bool); v { + apiAttributeValue = strconv.FormatBool(v) + } + case schema.TypeInt: + // On creation don't specify any zero Optional/Computed attribute integer values. + if v := v.(int); !attributeInfo.tfOptionalComputed || v != 0 { + apiAttributeValue = strconv.Itoa(v) } + case schema.TypeString: + apiAttributeValue = v.(string) + default: + return nil, fmt.Errorf("attribute %s is of unsupported type: %d", tfAttributeName, t) + } + if apiAttributeValue != "" { apiAttributes[attributeInfo.apiAttributeName] = apiAttributeValue } } diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index 74e0746eee99..a61a8a36f4d8 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -67,8 +67,8 @@ var ( "kms_data_key_reuse_period_seconds": { Type: schema.TypeInt, - Computed: true, Optional: true, + Computed: true, ValidateFunc: validation.IntBetween(60, 86_400), }, diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index f12a1da6058f..84646d136bb2 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -622,6 +622,33 @@ func TestAccAWSSQSQueue_Encryption(t *testing.T) { }) } +func TestAccAWSSQSQueue_ZeroVisibilityTimeoutSeconds(t *testing.T) { + var queueAttributes map[string]string + resourceName := "aws_sqs_queue.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSQSQueueDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSQSConfigZeroVisibilityTimeoutSeconds(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]string, rName string) resource.TestCheckFunc { return func(s *terraform.State) error { expectedPolicyText := fmt.Sprintf( @@ -915,3 +942,12 @@ resource "aws_sqs_queue" "test" { } `, rName, kmsDataKeyReusePeriodSeconds) } + +func testAccAWSSQSConfigZeroVisibilityTimeoutSeconds(rName string) string { + return fmt.Sprintf(` +resource "aws_sqs_queue" "test" { + name = %[1]q + visibility_timeout_seconds = 0 +} +`, rName) +} From 31b7d390dab2c77b02e24d35702762da2a886aaa Mon Sep 17 00:00:00 2001 From: what's for dinner Date: Sat, 3 Oct 2020 20:12:31 +1000 Subject: [PATCH 0280/1208] adding 'url' attribute to resource_aws_sqs_queue --- aws/resource_aws_sqs_queue.go | 6 ++++++ aws/resource_aws_sqs_queue_test.go | 1 + website/docs/r/sqs_queue.html.markdown | 1 + 3 files changed, 8 insertions(+) diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index a61a8a36f4d8..ad2a664b2718 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -131,6 +131,11 @@ var ( }, }, + "url": { + Type: schema.TypeString, + Computed: true, + }, + "visibility_timeout_seconds": { Type: schema.TypeInt, Optional: true, @@ -291,6 +296,7 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { } else { d.Set("name_prefix", naming.NamePrefixFromName(name)) } + d.Set("url", d.Id()) tags, err := keyvaluetags.SqsListTags(conn, d.Id()) diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index 84646d136bb2..9b5fa8f4b483 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -109,6 +109,7 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "receive_wait_time_seconds", strconv.Itoa(tfsqs.DefaultQueueReceiveMessageWaitTimeSeconds)), resource.TestCheckResourceAttr(resourceName, "redrive_policy", ""), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttrPair(resourceName, "url", resourceName, "id"), resource.TestCheckResourceAttr(resourceName, "visibility_timeout_seconds", strconv.Itoa(tfsqs.DefaultQueueVisibilityTimeout)), ), }, diff --git a/website/docs/r/sqs_queue.html.markdown b/website/docs/r/sqs_queue.html.markdown index 5e2fc90b0393..238144899bd0 100644 --- a/website/docs/r/sqs_queue.html.markdown +++ b/website/docs/r/sqs_queue.html.markdown @@ -87,6 +87,7 @@ In addition to all arguments above, the following attributes are exported: * `id` - The URL for the created Amazon SQS queue. * `arn` - The ARN of the SQS queue * `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). +* `url` - Same as `id`: The URL for the created Amazon SQS queue. ## Import From 0be4aa56ca2f2ac43bd51c04edf466727c7b2038 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 7 Jun 2021 12:11:49 -0400 Subject: [PATCH 0281/1208] Additional CHANGELOG entries. --- .changelog/19639.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.changelog/19639.txt b/.changelog/19639.txt index 91679dea7d09..607d7deb3671 100644 --- a/.changelog/19639.txt +++ b/.changelog/19639.txt @@ -1,3 +1,15 @@ ```release-note:enhancement resource/aws_sqs_queue: Add `deduplication_scope` and `fifo_throughput_limit` arguments ``` + +```release-note:enhancement +resource/aws_sqs_queue: Add `url` attribute +``` + +```release-note:bug +resource/aws_sqs_queue: Allow `visibility_timeout_seconds` to be `0` when creating queue +``` + +```release-note:bug +resource/aws_sqs_queue: Ensure that queue attributes propagate completely during Create and Update +``` \ No newline at end of file From 2514771c4197bdee1208a4fa42f8370a09998b60 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 7 Jun 2021 12:21:01 -0400 Subject: [PATCH 0282/1208] Fix golangci-lint error. --- aws/internal/service/sqs/waiter/waiter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/internal/service/sqs/waiter/waiter.go b/aws/internal/service/sqs/waiter/waiter.go index 97249d0353f1..a4a93e35a6de 100644 --- a/aws/internal/service/sqs/waiter/waiter.go +++ b/aws/internal/service/sqs/waiter/waiter.go @@ -43,7 +43,7 @@ func QueueAttributesPropagated(conn *sqs.SQS, url string, expected map[string]st equivalent, err := awspolicy.PoliciesAreEquivalent(g, e) if err != nil { - return nil + return err } if !equivalent { From 17065760a6156b9973f59cfc1c4cb6bbfd138560 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 1 Dec 2020 00:36:23 +0200 Subject: [PATCH 0283/1208] move all cognito user pool structs from structure --- aws/resource_aws_cognito_user_pool.go | 844 ++++++++++++++++++++++++++ aws/structure.go | 788 ------------------------ 2 files changed, 844 insertions(+), 788 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index cee7bfb9d51d..9c9179955d83 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -3,7 +3,9 @@ package aws import ( "fmt" "log" + "reflect" "regexp" + "strings" "time" "github.com/aws/aws-sdk-go/aws" @@ -66,6 +68,11 @@ func resourceAwsCognitoUserPool() *schema.Resource { Type: schema.TypeBool, Optional: true, }, + "unused_account_validity_days": { + Type: schema.TypeInt, + Optional: true, + Default: 7, + }, "invite_message_template": { Type: schema.TypeList, Optional: true, @@ -249,6 +256,51 @@ func resourceAwsCognitoUserPool() *schema.Resource { Optional: true, ValidateFunc: validateArn, }, + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + }, + "custom_email_sender": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "lambda_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + "email_sending_account": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.CustomEmailSenderLambdaVersionType_Values(), false), + }, + }, + }, + }, + "custom_sms_sender": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "lambda_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + "email_sending_account": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.CustomSMSSenderLambdaVersionType_Values(), false), + }, + }, + }, + }, }, }, }, @@ -1313,3 +1365,795 @@ func flattenCognitoUserPoolAccountRecoverySettingConfig(config *cognitoidentityp return []interface{}{settings} } + +func flattenCognitoUserPoolEmailConfiguration(s *cognitoidentityprovider.EmailConfigurationType) []map[string]interface{} { + m := make(map[string]interface{}) + + if s == nil { + return nil + } + + if s.ReplyToEmailAddress != nil { + m["reply_to_email_address"] = aws.StringValue(s.ReplyToEmailAddress) + } + + if s.From != nil { + m["from_email_address"] = aws.StringValue(s.From) + } + + if s.SourceArn != nil { + m["source_arn"] = aws.StringValue(s.SourceArn) + } + + if s.EmailSendingAccount != nil { + m["email_sending_account"] = aws.StringValue(s.EmailSendingAccount) + } + + if len(m) > 0 { + return []map[string]interface{}{m} + } + + return []map[string]interface{}{} +} + +func expandCognitoUserPoolAdminCreateUserConfig(config map[string]interface{}) *cognitoidentityprovider.AdminCreateUserConfigType { + configs := &cognitoidentityprovider.AdminCreateUserConfigType{} + + if v, ok := config["allow_admin_create_user_only"]; ok { + configs.AllowAdminCreateUserOnly = aws.Bool(v.(bool)) + } + + if v, ok := config["unused_account_validity_days"]; ok { + configs.UnusedAccountValidityDays = aws.Int64(int64(v.(int))) + } + + if v, ok := config["invite_message_template"]; ok { + data := v.([]interface{}) + + if len(data) > 0 { + m, ok := data[0].(map[string]interface{}) + + if ok { + imt := &cognitoidentityprovider.MessageTemplateType{} + + if v, ok := m["email_message"]; ok { + imt.EmailMessage = aws.String(v.(string)) + } + + if v, ok := m["email_subject"]; ok { + imt.EmailSubject = aws.String(v.(string)) + } + + if v, ok := m["sms_message"]; ok { + imt.SMSMessage = aws.String(v.(string)) + } + + configs.InviteMessageTemplate = imt + } + } + } + + return configs +} + +func flattenCognitoUserPoolAdminCreateUserConfig(s *cognitoidentityprovider.AdminCreateUserConfigType) []map[string]interface{} { + config := map[string]interface{}{} + + if s == nil { + return nil + } + + if s.AllowAdminCreateUserOnly != nil { + config["allow_admin_create_user_only"] = aws.BoolValue(s.AllowAdminCreateUserOnly) + } + + if s.UnusedAccountValidityDays != nil { + config["unused_account_validity_days"] = aws.Int64Value(s.UnusedAccountValidityDays) + } + + if s.InviteMessageTemplate != nil { + subconfig := map[string]interface{}{} + + if s.InviteMessageTemplate.EmailMessage != nil { + subconfig["email_message"] = aws.StringValue(s.InviteMessageTemplate.EmailMessage) + } + + if s.InviteMessageTemplate.EmailSubject != nil { + subconfig["email_subject"] = aws.StringValue(s.InviteMessageTemplate.EmailSubject) + } + + if s.InviteMessageTemplate.SMSMessage != nil { + subconfig["sms_message"] = aws.StringValue(s.InviteMessageTemplate.SMSMessage) + } + + if len(subconfig) > 0 { + config["invite_message_template"] = []map[string]interface{}{subconfig} + } + } + + return []map[string]interface{}{config} +} + +func expandCognitoUserPoolDeviceConfiguration(config map[string]interface{}) *cognitoidentityprovider.DeviceConfigurationType { + configs := &cognitoidentityprovider.DeviceConfigurationType{} + + if v, ok := config["challenge_required_on_new_device"]; ok { + configs.ChallengeRequiredOnNewDevice = aws.Bool(v.(bool)) + } + + if v, ok := config["device_only_remembered_on_user_prompt"]; ok { + configs.DeviceOnlyRememberedOnUserPrompt = aws.Bool(v.(bool)) + } + + return configs +} + +func expandCognitoUserPoolLambdaConfig(config map[string]interface{}) *cognitoidentityprovider.LambdaConfigType { + configs := &cognitoidentityprovider.LambdaConfigType{} + + if v, ok := config["create_auth_challenge"]; ok && v.(string) != "" { + configs.CreateAuthChallenge = aws.String(v.(string)) + } + + if v, ok := config["custom_message"]; ok && v.(string) != "" { + configs.CustomMessage = aws.String(v.(string)) + } + + if v, ok := config["define_auth_challenge"]; ok && v.(string) != "" { + configs.DefineAuthChallenge = aws.String(v.(string)) + } + + if v, ok := config["post_authentication"]; ok && v.(string) != "" { + configs.PostAuthentication = aws.String(v.(string)) + } + + if v, ok := config["post_confirmation"]; ok && v.(string) != "" { + configs.PostConfirmation = aws.String(v.(string)) + } + + if v, ok := config["pre_authentication"]; ok && v.(string) != "" { + configs.PreAuthentication = aws.String(v.(string)) + } + + if v, ok := config["pre_sign_up"]; ok && v.(string) != "" { + configs.PreSignUp = aws.String(v.(string)) + } + + if v, ok := config["pre_token_generation"]; ok && v.(string) != "" { + configs.PreTokenGeneration = aws.String(v.(string)) + } + + if v, ok := config["user_migration"]; ok && v.(string) != "" { + configs.UserMigration = aws.String(v.(string)) + } + + if v, ok := config["verify_auth_challenge_response"]; ok && v.(string) != "" { + configs.VerifyAuthChallengeResponse = aws.String(v.(string)) + } + + return configs +} + +func flattenCognitoUserPoolLambdaConfig(s *cognitoidentityprovider.LambdaConfigType) []map[string]interface{} { + m := map[string]interface{}{} + + if s == nil { + return nil + } + + if s.CreateAuthChallenge != nil { + m["create_auth_challenge"] = aws.StringValue(s.CreateAuthChallenge) + } + + if s.CustomMessage != nil { + m["custom_message"] = aws.StringValue(s.CustomMessage) + } + + if s.DefineAuthChallenge != nil { + m["define_auth_challenge"] = aws.StringValue(s.DefineAuthChallenge) + } + + if s.PostAuthentication != nil { + m["post_authentication"] = aws.StringValue(s.PostAuthentication) + } + + if s.PostConfirmation != nil { + m["post_confirmation"] = aws.StringValue(s.PostConfirmation) + } + + if s.PreAuthentication != nil { + m["pre_authentication"] = aws.StringValue(s.PreAuthentication) + } + + if s.PreSignUp != nil { + m["pre_sign_up"] = aws.StringValue(s.PreSignUp) + } + + if s.PreTokenGeneration != nil { + m["pre_token_generation"] = aws.StringValue(s.PreTokenGeneration) + } + + if s.UserMigration != nil { + m["user_migration"] = aws.StringValue(s.UserMigration) + } + + if s.VerifyAuthChallengeResponse != nil { + m["verify_auth_challenge_response"] = aws.StringValue(s.VerifyAuthChallengeResponse) + } + + if len(m) > 0 { + return []map[string]interface{}{m} + } + + return []map[string]interface{}{} +} + +func expandCognitoUserPoolPasswordPolicy(config map[string]interface{}) *cognitoidentityprovider.PasswordPolicyType { + configs := &cognitoidentityprovider.PasswordPolicyType{} + + if v, ok := config["minimum_length"]; ok { + configs.MinimumLength = aws.Int64(int64(v.(int))) + } + + if v, ok := config["require_lowercase"]; ok { + configs.RequireLowercase = aws.Bool(v.(bool)) + } + + if v, ok := config["require_numbers"]; ok { + configs.RequireNumbers = aws.Bool(v.(bool)) + } + + if v, ok := config["require_symbols"]; ok { + configs.RequireSymbols = aws.Bool(v.(bool)) + } + + if v, ok := config["require_uppercase"]; ok { + configs.RequireUppercase = aws.Bool(v.(bool)) + } + + if v, ok := config["temporary_password_validity_days"]; ok { + configs.TemporaryPasswordValidityDays = aws.Int64(int64(v.(int))) + } + + return configs +} + +func flattenCognitoUserPoolUserPoolAddOns(s *cognitoidentityprovider.UserPoolAddOnsType) []map[string]interface{} { + config := make(map[string]interface{}) + + if s == nil { + return []map[string]interface{}{} + } + + if s.AdvancedSecurityMode != nil { + config["advanced_security_mode"] = aws.StringValue(s.AdvancedSecurityMode) + } + + return []map[string]interface{}{config} +} + +func expandCognitoUserPoolSchema(inputs []interface{}) []*cognitoidentityprovider.SchemaAttributeType { + configs := make([]*cognitoidentityprovider.SchemaAttributeType, len(inputs)) + + for i, input := range inputs { + param := input.(map[string]interface{}) + config := &cognitoidentityprovider.SchemaAttributeType{} + + if v, ok := param["attribute_data_type"]; ok { + config.AttributeDataType = aws.String(v.(string)) + } + + if v, ok := param["developer_only_attribute"]; ok { + config.DeveloperOnlyAttribute = aws.Bool(v.(bool)) + } + + if v, ok := param["mutable"]; ok { + config.Mutable = aws.Bool(v.(bool)) + } + + if v, ok := param["name"]; ok { + config.Name = aws.String(v.(string)) + } + + if v, ok := param["required"]; ok { + config.Required = aws.Bool(v.(bool)) + } + + if v, ok := param["number_attribute_constraints"]; ok { + data := v.([]interface{}) + + if len(data) > 0 { + m, ok := data[0].(map[string]interface{}) + if ok { + numberAttributeConstraintsType := &cognitoidentityprovider.NumberAttributeConstraintsType{} + + if v, ok := m["min_value"]; ok && v.(string) != "" { + numberAttributeConstraintsType.MinValue = aws.String(v.(string)) + } + + if v, ok := m["max_value"]; ok && v.(string) != "" { + numberAttributeConstraintsType.MaxValue = aws.String(v.(string)) + } + + config.NumberAttributeConstraints = numberAttributeConstraintsType + } + } + } + + if v, ok := param["string_attribute_constraints"]; ok { + data := v.([]interface{}) + + if len(data) > 0 { + m, _ := data[0].(map[string]interface{}) + if ok { + stringAttributeConstraintsType := &cognitoidentityprovider.StringAttributeConstraintsType{} + + if l, ok := m["min_length"]; ok && l.(string) != "" { + stringAttributeConstraintsType.MinLength = aws.String(l.(string)) + } + + if l, ok := m["max_length"]; ok && l.(string) != "" { + stringAttributeConstraintsType.MaxLength = aws.String(l.(string)) + } + + config.StringAttributeConstraints = stringAttributeConstraintsType + } + } + } + + configs[i] = config + } + + return configs +} + +func flattenCognitoUserPoolSchema(configuredAttributes, inputs []*cognitoidentityprovider.SchemaAttributeType) []map[string]interface{} { + values := make([]map[string]interface{}, 0) + + for _, input := range inputs { + if input == nil { + continue + } + + // The API returns all standard attributes + // https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#cognito-user-pools-standard-attributes + // Ignore setting them in state if they are unconfigured to prevent a huge and unexpected diff + configured := false + + for _, configuredAttribute := range configuredAttributes { + if reflect.DeepEqual(input, configuredAttribute) { + configured = true + } + } + + if !configured { + if cognitoUserPoolSchemaAttributeMatchesStandardAttribute(input) { + continue + } + // When adding a Cognito Identity Provider, the API will automatically add an "identities" attribute + identitiesAttribute := cognitoidentityprovider.SchemaAttributeType{ + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("identities"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{}, + } + if reflect.DeepEqual(*input, identitiesAttribute) { + continue + } + } + + var value = map[string]interface{}{ + "attribute_data_type": aws.StringValue(input.AttributeDataType), + "developer_only_attribute": aws.BoolValue(input.DeveloperOnlyAttribute), + "mutable": aws.BoolValue(input.Mutable), + "name": strings.TrimPrefix(strings.TrimPrefix(aws.StringValue(input.Name), "dev:"), "custom:"), + "required": aws.BoolValue(input.Required), + } + + if input.NumberAttributeConstraints != nil { + subvalue := make(map[string]interface{}) + + if input.NumberAttributeConstraints.MinValue != nil { + subvalue["min_value"] = aws.StringValue(input.NumberAttributeConstraints.MinValue) + } + + if input.NumberAttributeConstraints.MaxValue != nil { + subvalue["max_value"] = aws.StringValue(input.NumberAttributeConstraints.MaxValue) + } + + value["number_attribute_constraints"] = []map[string]interface{}{subvalue} + } + + if input.StringAttributeConstraints != nil { + subvalue := make(map[string]interface{}) + + if input.StringAttributeConstraints.MinLength != nil { + subvalue["min_length"] = aws.StringValue(input.StringAttributeConstraints.MinLength) + } + + if input.StringAttributeConstraints.MaxLength != nil { + subvalue["max_length"] = aws.StringValue(input.StringAttributeConstraints.MaxLength) + } + + value["string_attribute_constraints"] = []map[string]interface{}{subvalue} + } + + values = append(values, value) + } + + return values +} + +func expandCognitoUserPoolUsernameConfiguration(config map[string]interface{}) *cognitoidentityprovider.UsernameConfigurationType { + usernameConfigurationType := &cognitoidentityprovider.UsernameConfigurationType{ + CaseSensitive: aws.Bool(config["case_sensitive"].(bool)), + } + + return usernameConfigurationType +} + +func flattenCognitoUserPoolUsernameConfiguration(u *cognitoidentityprovider.UsernameConfigurationType) []map[string]interface{} { + m := map[string]interface{}{} + + if u == nil { + return nil + } + + m["case_sensitive"] = aws.BoolValue(u.CaseSensitive) + + return []map[string]interface{}{m} +} + +func expandCognitoUserPoolVerificationMessageTemplate(config map[string]interface{}) *cognitoidentityprovider.VerificationMessageTemplateType { + verificationMessageTemplateType := &cognitoidentityprovider.VerificationMessageTemplateType{} + + if v, ok := config["default_email_option"]; ok && v.(string) != "" { + verificationMessageTemplateType.DefaultEmailOption = aws.String(v.(string)) + } + + if v, ok := config["email_message"]; ok && v.(string) != "" { + verificationMessageTemplateType.EmailMessage = aws.String(v.(string)) + } + + if v, ok := config["email_message_by_link"]; ok && v.(string) != "" { + verificationMessageTemplateType.EmailMessageByLink = aws.String(v.(string)) + } + + if v, ok := config["email_subject"]; ok && v.(string) != "" { + verificationMessageTemplateType.EmailSubject = aws.String(v.(string)) + } + + if v, ok := config["email_subject_by_link"]; ok && v.(string) != "" { + verificationMessageTemplateType.EmailSubjectByLink = aws.String(v.(string)) + } + + if v, ok := config["sms_message"]; ok && v.(string) != "" { + verificationMessageTemplateType.SmsMessage = aws.String(v.(string)) + } + + return verificationMessageTemplateType +} + +func flattenCognitoUserPoolVerificationMessageTemplate(s *cognitoidentityprovider.VerificationMessageTemplateType) []map[string]interface{} { + m := map[string]interface{}{} + + if s == nil { + return nil + } + + if s.DefaultEmailOption != nil { + m["default_email_option"] = aws.StringValue(s.DefaultEmailOption) + } + + if s.EmailMessage != nil { + m["email_message"] = aws.StringValue(s.EmailMessage) + } + + if s.EmailMessageByLink != nil { + m["email_message_by_link"] = aws.StringValue(s.EmailMessageByLink) + } + + if s.EmailSubject != nil { + m["email_subject"] = aws.StringValue(s.EmailSubject) + } + + if s.EmailSubjectByLink != nil { + m["email_subject_by_link"] = aws.StringValue(s.EmailSubjectByLink) + } + + if s.SmsMessage != nil { + m["sms_message"] = aws.StringValue(s.SmsMessage) + } + + if len(m) > 0 { + return []map[string]interface{}{m} + } + + return []map[string]interface{}{} +} + +func flattenCognitoUserPoolDeviceConfiguration(s *cognitoidentityprovider.DeviceConfigurationType) []map[string]interface{} { + config := map[string]interface{}{} + + if s == nil { + return nil + } + + if s.ChallengeRequiredOnNewDevice != nil { + config["challenge_required_on_new_device"] = aws.BoolValue(s.ChallengeRequiredOnNewDevice) + } + + if s.DeviceOnlyRememberedOnUserPrompt != nil { + config["device_only_remembered_on_user_prompt"] = aws.BoolValue(s.DeviceOnlyRememberedOnUserPrompt) + } + + return []map[string]interface{}{config} +} + +func flattenCognitoUserPoolPasswordPolicy(s *cognitoidentityprovider.PasswordPolicyType) []map[string]interface{} { + m := map[string]interface{}{} + + if s == nil { + return nil + } + + if s.MinimumLength != nil { + m["minimum_length"] = aws.Int64Value(s.MinimumLength) + } + + if s.RequireLowercase != nil { + m["require_lowercase"] = aws.BoolValue(s.RequireLowercase) + } + + if s.RequireNumbers != nil { + m["require_numbers"] = aws.BoolValue(s.RequireNumbers) + } + + if s.RequireSymbols != nil { + m["require_symbols"] = aws.BoolValue(s.RequireSymbols) + } + + if s.RequireUppercase != nil { + m["require_uppercase"] = aws.BoolValue(s.RequireUppercase) + } + + if s.TemporaryPasswordValidityDays != nil { + m["temporary_password_validity_days"] = aws.Int64Value(s.TemporaryPasswordValidityDays) + } + + if len(m) > 0 { + return []map[string]interface{}{m} + } + + return []map[string]interface{}{} +} + +func cognitoUserPoolSchemaAttributeMatchesStandardAttribute(input *cognitoidentityprovider.SchemaAttributeType) bool { + if input == nil { + return false + } + + // All standard attributes always returned by API + // https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#cognito-user-pools-standard-attributes + var standardAttributes = []cognitoidentityprovider.SchemaAttributeType{ + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("address"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("birthdate"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("10"), + MinLength: aws.String("10"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("email"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeBoolean), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("email_verified"), + Required: aws.Bool(false), + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("gender"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("given_name"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("family_name"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("locale"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("middle_name"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("name"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("nickname"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("phone_number"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeBoolean), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("phone_number_verified"), + Required: aws.Bool(false), + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("picture"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("preferred_username"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("profile"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(false), + Name: aws.String("sub"), + Required: aws.Bool(true), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("1"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeNumber), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("updated_at"), + NumberAttributeConstraints: &cognitoidentityprovider.NumberAttributeConstraintsType{ + MinValue: aws.String("0"), + }, + Required: aws.Bool(false), + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("website"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + { + AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), + DeveloperOnlyAttribute: aws.Bool(false), + Mutable: aws.Bool(true), + Name: aws.String("zoneinfo"), + Required: aws.Bool(false), + StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ + MaxLength: aws.String("2048"), + MinLength: aws.String("0"), + }, + }, + } + for _, standardAttribute := range standardAttributes { + if reflect.DeepEqual(*input, standardAttribute) { + return true + } + } + return false +} diff --git a/aws/structure.go b/aws/structure.go index abaaf21ca6f2..debbd6f345aa 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -2145,324 +2145,6 @@ func flattenCognitoIdentityProviders(ips []*cognitoidentity.Provider) []map[stri return values } -func flattenCognitoUserPoolEmailConfiguration(s *cognitoidentityprovider.EmailConfigurationType) []map[string]interface{} { - m := make(map[string]interface{}) - - if s == nil { - return nil - } - - if s.ReplyToEmailAddress != nil { - m["reply_to_email_address"] = *s.ReplyToEmailAddress - } - - if s.From != nil { - m["from_email_address"] = *s.From - } - - if s.SourceArn != nil { - m["source_arn"] = *s.SourceArn - } - - if s.EmailSendingAccount != nil { - m["email_sending_account"] = *s.EmailSendingAccount - } - - if s.ConfigurationSet != nil { - m["configuration_set"] = *s.ConfigurationSet - } - - if len(m) > 0 { - return []map[string]interface{}{m} - } - - return []map[string]interface{}{} -} - -func expandCognitoUserPoolAdminCreateUserConfig(config map[string]interface{}) *cognitoidentityprovider.AdminCreateUserConfigType { - configs := &cognitoidentityprovider.AdminCreateUserConfigType{} - - if v, ok := config["allow_admin_create_user_only"]; ok { - configs.AllowAdminCreateUserOnly = aws.Bool(v.(bool)) - } - - if v, ok := config["invite_message_template"]; ok { - data := v.([]interface{}) - - if len(data) > 0 { - m, ok := data[0].(map[string]interface{}) - - if ok { - imt := &cognitoidentityprovider.MessageTemplateType{} - - if v, ok := m["email_message"]; ok { - imt.EmailMessage = aws.String(v.(string)) - } - - if v, ok := m["email_subject"]; ok { - imt.EmailSubject = aws.String(v.(string)) - } - - if v, ok := m["sms_message"]; ok { - imt.SMSMessage = aws.String(v.(string)) - } - - configs.InviteMessageTemplate = imt - } - } - } - - return configs -} - -func flattenCognitoUserPoolAdminCreateUserConfig(s *cognitoidentityprovider.AdminCreateUserConfigType) []map[string]interface{} { - config := map[string]interface{}{} - - if s == nil { - return nil - } - - if s.AllowAdminCreateUserOnly != nil { - config["allow_admin_create_user_only"] = *s.AllowAdminCreateUserOnly - } - - if s.InviteMessageTemplate != nil { - subconfig := map[string]interface{}{} - - if s.InviteMessageTemplate.EmailMessage != nil { - subconfig["email_message"] = *s.InviteMessageTemplate.EmailMessage - } - - if s.InviteMessageTemplate.EmailSubject != nil { - subconfig["email_subject"] = *s.InviteMessageTemplate.EmailSubject - } - - if s.InviteMessageTemplate.SMSMessage != nil { - subconfig["sms_message"] = *s.InviteMessageTemplate.SMSMessage - } - - if len(subconfig) > 0 { - config["invite_message_template"] = []map[string]interface{}{subconfig} - } - } - - return []map[string]interface{}{config} -} - -func expandCognitoUserPoolDeviceConfiguration(config map[string]interface{}) *cognitoidentityprovider.DeviceConfigurationType { - configs := &cognitoidentityprovider.DeviceConfigurationType{} - - if v, ok := config["challenge_required_on_new_device"]; ok { - configs.ChallengeRequiredOnNewDevice = aws.Bool(v.(bool)) - } - - if v, ok := config["device_only_remembered_on_user_prompt"]; ok { - configs.DeviceOnlyRememberedOnUserPrompt = aws.Bool(v.(bool)) - } - - return configs -} - -func flattenCognitoUserPoolDeviceConfiguration(s *cognitoidentityprovider.DeviceConfigurationType) []map[string]interface{} { - config := map[string]interface{}{} - - if s == nil { - return nil - } - - if s.ChallengeRequiredOnNewDevice != nil { - config["challenge_required_on_new_device"] = *s.ChallengeRequiredOnNewDevice - } - - if s.DeviceOnlyRememberedOnUserPrompt != nil { - config["device_only_remembered_on_user_prompt"] = *s.DeviceOnlyRememberedOnUserPrompt - } - - return []map[string]interface{}{config} -} - -func expandCognitoUserPoolLambdaConfig(config map[string]interface{}) *cognitoidentityprovider.LambdaConfigType { - configs := &cognitoidentityprovider.LambdaConfigType{} - - if v, ok := config["create_auth_challenge"]; ok && v.(string) != "" { - configs.CreateAuthChallenge = aws.String(v.(string)) - } - - if v, ok := config["custom_message"]; ok && v.(string) != "" { - configs.CustomMessage = aws.String(v.(string)) - } - - if v, ok := config["define_auth_challenge"]; ok && v.(string) != "" { - configs.DefineAuthChallenge = aws.String(v.(string)) - } - - if v, ok := config["post_authentication"]; ok && v.(string) != "" { - configs.PostAuthentication = aws.String(v.(string)) - } - - if v, ok := config["post_confirmation"]; ok && v.(string) != "" { - configs.PostConfirmation = aws.String(v.(string)) - } - - if v, ok := config["pre_authentication"]; ok && v.(string) != "" { - configs.PreAuthentication = aws.String(v.(string)) - } - - if v, ok := config["pre_sign_up"]; ok && v.(string) != "" { - configs.PreSignUp = aws.String(v.(string)) - } - - if v, ok := config["pre_token_generation"]; ok && v.(string) != "" { - configs.PreTokenGeneration = aws.String(v.(string)) - } - - if v, ok := config["user_migration"]; ok && v.(string) != "" { - configs.UserMigration = aws.String(v.(string)) - } - - if v, ok := config["verify_auth_challenge_response"]; ok && v.(string) != "" { - configs.VerifyAuthChallengeResponse = aws.String(v.(string)) - } - - return configs -} - -func flattenCognitoUserPoolLambdaConfig(s *cognitoidentityprovider.LambdaConfigType) []map[string]interface{} { - m := map[string]interface{}{} - - if s == nil { - return nil - } - - if s.CreateAuthChallenge != nil { - m["create_auth_challenge"] = *s.CreateAuthChallenge - } - - if s.CustomMessage != nil { - m["custom_message"] = *s.CustomMessage - } - - if s.DefineAuthChallenge != nil { - m["define_auth_challenge"] = *s.DefineAuthChallenge - } - - if s.PostAuthentication != nil { - m["post_authentication"] = *s.PostAuthentication - } - - if s.PostConfirmation != nil { - m["post_confirmation"] = *s.PostConfirmation - } - - if s.PreAuthentication != nil { - m["pre_authentication"] = *s.PreAuthentication - } - - if s.PreSignUp != nil { - m["pre_sign_up"] = *s.PreSignUp - } - - if s.PreTokenGeneration != nil { - m["pre_token_generation"] = *s.PreTokenGeneration - } - - if s.UserMigration != nil { - m["user_migration"] = *s.UserMigration - } - - if s.VerifyAuthChallengeResponse != nil { - m["verify_auth_challenge_response"] = *s.VerifyAuthChallengeResponse - } - - if len(m) > 0 { - return []map[string]interface{}{m} - } - - return []map[string]interface{}{} -} - -func expandCognitoUserPoolPasswordPolicy(config map[string]interface{}) *cognitoidentityprovider.PasswordPolicyType { - configs := &cognitoidentityprovider.PasswordPolicyType{} - - if v, ok := config["minimum_length"]; ok { - configs.MinimumLength = aws.Int64(int64(v.(int))) - } - - if v, ok := config["require_lowercase"]; ok { - configs.RequireLowercase = aws.Bool(v.(bool)) - } - - if v, ok := config["require_numbers"]; ok { - configs.RequireNumbers = aws.Bool(v.(bool)) - } - - if v, ok := config["require_symbols"]; ok { - configs.RequireSymbols = aws.Bool(v.(bool)) - } - - if v, ok := config["require_uppercase"]; ok { - configs.RequireUppercase = aws.Bool(v.(bool)) - } - - if v, ok := config["temporary_password_validity_days"]; ok { - configs.TemporaryPasswordValidityDays = aws.Int64(int64(v.(int))) - } - - return configs -} - -func flattenCognitoUserPoolUserPoolAddOns(s *cognitoidentityprovider.UserPoolAddOnsType) []map[string]interface{} { - config := make(map[string]interface{}) - - if s == nil { - return []map[string]interface{}{} - } - - if s.AdvancedSecurityMode != nil { - config["advanced_security_mode"] = *s.AdvancedSecurityMode - } - - return []map[string]interface{}{config} -} - -func flattenCognitoUserPoolPasswordPolicy(s *cognitoidentityprovider.PasswordPolicyType) []map[string]interface{} { - m := map[string]interface{}{} - - if s == nil { - return nil - } - - if s.MinimumLength != nil { - m["minimum_length"] = *s.MinimumLength - } - - if s.RequireLowercase != nil { - m["require_lowercase"] = *s.RequireLowercase - } - - if s.RequireNumbers != nil { - m["require_numbers"] = *s.RequireNumbers - } - - if s.RequireSymbols != nil { - m["require_symbols"] = *s.RequireSymbols - } - - if s.RequireUppercase != nil { - m["require_uppercase"] = *s.RequireUppercase - } - - if s.TemporaryPasswordValidityDays != nil { - m["temporary_password_validity_days"] = *s.TemporaryPasswordValidityDays - } - - if len(m) > 0 { - return []map[string]interface{}{m} - } - - return []map[string]interface{}{} -} - func expandCognitoResourceServerScope(inputs []interface{}) []*cognitoidentityprovider.ResourceServerScopeType { configs := make([]*cognitoidentityprovider.ResourceServerScopeType, len(inputs)) for i, input := range inputs { @@ -2499,476 +2181,6 @@ func flattenCognitoResourceServerScope(inputs []*cognitoidentityprovider.Resourc return values } -func expandCognitoUserPoolSchema(inputs []interface{}) []*cognitoidentityprovider.SchemaAttributeType { - configs := make([]*cognitoidentityprovider.SchemaAttributeType, len(inputs)) - - for i, input := range inputs { - param := input.(map[string]interface{}) - config := &cognitoidentityprovider.SchemaAttributeType{} - - if v, ok := param["attribute_data_type"]; ok { - config.AttributeDataType = aws.String(v.(string)) - } - - if v, ok := param["developer_only_attribute"]; ok { - config.DeveloperOnlyAttribute = aws.Bool(v.(bool)) - } - - if v, ok := param["mutable"]; ok { - config.Mutable = aws.Bool(v.(bool)) - } - - if v, ok := param["name"]; ok { - config.Name = aws.String(v.(string)) - } - - if v, ok := param["required"]; ok { - config.Required = aws.Bool(v.(bool)) - } - - if v, ok := param["number_attribute_constraints"]; ok { - data := v.([]interface{}) - - if len(data) > 0 { - m, ok := data[0].(map[string]interface{}) - if ok { - numberAttributeConstraintsType := &cognitoidentityprovider.NumberAttributeConstraintsType{} - - if v, ok := m["min_value"]; ok && v.(string) != "" { - numberAttributeConstraintsType.MinValue = aws.String(v.(string)) - } - - if v, ok := m["max_value"]; ok && v.(string) != "" { - numberAttributeConstraintsType.MaxValue = aws.String(v.(string)) - } - - config.NumberAttributeConstraints = numberAttributeConstraintsType - } - } - } - - if v, ok := param["string_attribute_constraints"]; ok { - data := v.([]interface{}) - - if len(data) > 0 { - m, _ := data[0].(map[string]interface{}) - if ok { - stringAttributeConstraintsType := &cognitoidentityprovider.StringAttributeConstraintsType{} - - if l, ok := m["min_length"]; ok && l.(string) != "" { - stringAttributeConstraintsType.MinLength = aws.String(l.(string)) - } - - if l, ok := m["max_length"]; ok && l.(string) != "" { - stringAttributeConstraintsType.MaxLength = aws.String(l.(string)) - } - - config.StringAttributeConstraints = stringAttributeConstraintsType - } - } - } - - configs[i] = config - } - - return configs -} - -func cognitoUserPoolSchemaAttributeMatchesStandardAttribute(input *cognitoidentityprovider.SchemaAttributeType) bool { - if input == nil { - return false - } - - // All standard attributes always returned by API - // https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#cognito-user-pools-standard-attributes - var standardAttributes = []cognitoidentityprovider.SchemaAttributeType{ - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("address"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("birthdate"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("10"), - MinLength: aws.String("10"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("email"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeBoolean), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("email_verified"), - Required: aws.Bool(false), - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("gender"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("given_name"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("family_name"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("locale"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("middle_name"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("name"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("nickname"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("phone_number"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeBoolean), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("phone_number_verified"), - Required: aws.Bool(false), - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("picture"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("preferred_username"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("profile"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(false), - Name: aws.String("sub"), - Required: aws.Bool(true), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("1"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeNumber), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("updated_at"), - NumberAttributeConstraints: &cognitoidentityprovider.NumberAttributeConstraintsType{ - MinValue: aws.String("0"), - }, - Required: aws.Bool(false), - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("website"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - { - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("zoneinfo"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{ - MaxLength: aws.String("2048"), - MinLength: aws.String("0"), - }, - }, - } - for _, standardAttribute := range standardAttributes { - if reflect.DeepEqual(*input, standardAttribute) { - return true - } - } - return false -} - -func flattenCognitoUserPoolSchema(configuredAttributes, inputs []*cognitoidentityprovider.SchemaAttributeType) []map[string]interface{} { - values := make([]map[string]interface{}, 0) - - for _, input := range inputs { - if input == nil { - continue - } - - // The API returns all standard attributes - // https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#cognito-user-pools-standard-attributes - // Ignore setting them in state if they are unconfigured to prevent a huge and unexpected diff - configured := false - - for _, configuredAttribute := range configuredAttributes { - if reflect.DeepEqual(input, configuredAttribute) { - configured = true - } - } - - if !configured { - if cognitoUserPoolSchemaAttributeMatchesStandardAttribute(input) { - continue - } - // When adding a Cognito Identity Provider, the API will automatically add an "identities" attribute - identitiesAttribute := cognitoidentityprovider.SchemaAttributeType{ - AttributeDataType: aws.String(cognitoidentityprovider.AttributeDataTypeString), - DeveloperOnlyAttribute: aws.Bool(false), - Mutable: aws.Bool(true), - Name: aws.String("identities"), - Required: aws.Bool(false), - StringAttributeConstraints: &cognitoidentityprovider.StringAttributeConstraintsType{}, - } - if reflect.DeepEqual(*input, identitiesAttribute) { - continue - } - } - - var value = map[string]interface{}{ - "attribute_data_type": aws.StringValue(input.AttributeDataType), - "developer_only_attribute": aws.BoolValue(input.DeveloperOnlyAttribute), - "mutable": aws.BoolValue(input.Mutable), - "name": strings.TrimPrefix(strings.TrimPrefix(aws.StringValue(input.Name), "dev:"), "custom:"), - "required": aws.BoolValue(input.Required), - } - - if input.NumberAttributeConstraints != nil { - subvalue := make(map[string]interface{}) - - if input.NumberAttributeConstraints.MinValue != nil { - subvalue["min_value"] = aws.StringValue(input.NumberAttributeConstraints.MinValue) - } - - if input.NumberAttributeConstraints.MaxValue != nil { - subvalue["max_value"] = aws.StringValue(input.NumberAttributeConstraints.MaxValue) - } - - value["number_attribute_constraints"] = []map[string]interface{}{subvalue} - } - - if input.StringAttributeConstraints != nil { - subvalue := make(map[string]interface{}) - - if input.StringAttributeConstraints.MinLength != nil { - subvalue["min_length"] = aws.StringValue(input.StringAttributeConstraints.MinLength) - } - - if input.StringAttributeConstraints.MaxLength != nil { - subvalue["max_length"] = aws.StringValue(input.StringAttributeConstraints.MaxLength) - } - - value["string_attribute_constraints"] = []map[string]interface{}{subvalue} - } - - values = append(values, value) - } - - return values -} - -func expandCognitoUserPoolUsernameConfiguration(config map[string]interface{}) *cognitoidentityprovider.UsernameConfigurationType { - usernameConfigurationType := &cognitoidentityprovider.UsernameConfigurationType{ - CaseSensitive: aws.Bool(config["case_sensitive"].(bool)), - } - - return usernameConfigurationType -} - -func flattenCognitoUserPoolUsernameConfiguration(u *cognitoidentityprovider.UsernameConfigurationType) []map[string]interface{} { - m := map[string]interface{}{} - - if u == nil { - return nil - } - - m["case_sensitive"] = *u.CaseSensitive - - return []map[string]interface{}{m} -} - -func expandCognitoUserPoolVerificationMessageTemplate(config map[string]interface{}) *cognitoidentityprovider.VerificationMessageTemplateType { - verificationMessageTemplateType := &cognitoidentityprovider.VerificationMessageTemplateType{} - - if v, ok := config["default_email_option"]; ok && v.(string) != "" { - verificationMessageTemplateType.DefaultEmailOption = aws.String(v.(string)) - } - - if v, ok := config["email_message"]; ok && v.(string) != "" { - verificationMessageTemplateType.EmailMessage = aws.String(v.(string)) - } - - if v, ok := config["email_message_by_link"]; ok && v.(string) != "" { - verificationMessageTemplateType.EmailMessageByLink = aws.String(v.(string)) - } - - if v, ok := config["email_subject"]; ok && v.(string) != "" { - verificationMessageTemplateType.EmailSubject = aws.String(v.(string)) - } - - if v, ok := config["email_subject_by_link"]; ok && v.(string) != "" { - verificationMessageTemplateType.EmailSubjectByLink = aws.String(v.(string)) - } - - if v, ok := config["sms_message"]; ok && v.(string) != "" { - verificationMessageTemplateType.SmsMessage = aws.String(v.(string)) - } - - return verificationMessageTemplateType -} - -func flattenCognitoUserPoolVerificationMessageTemplate(s *cognitoidentityprovider.VerificationMessageTemplateType) []map[string]interface{} { - m := map[string]interface{}{} - - if s == nil { - return nil - } - - if s.DefaultEmailOption != nil { - m["default_email_option"] = *s.DefaultEmailOption - } - - if s.EmailMessage != nil { - m["email_message"] = *s.EmailMessage - } - - if s.EmailMessageByLink != nil { - m["email_message_by_link"] = *s.EmailMessageByLink - } - - if s.EmailSubject != nil { - m["email_subject"] = *s.EmailSubject - } - - if s.EmailSubjectByLink != nil { - m["email_subject_by_link"] = *s.EmailSubjectByLink - } - - if s.SmsMessage != nil { - m["sms_message"] = *s.SmsMessage - } - - if len(m) > 0 { - return []map[string]interface{}{m} - } - - return []map[string]interface{}{} -} - func sliceContainsMap(l []interface{}, m map[string]interface{}) (int, bool) { for i, t := range l { if reflect.DeepEqual(m, t.(map[string]interface{})) { From 156c3b0fa0e1b5ad681d527a6cc52350c3458aa3 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 1 Dec 2020 01:23:36 +0200 Subject: [PATCH 0284/1208] add attributes --- aws/resource_aws_cognito_user_pool.go | 100 +++++++++++++++++++-- aws/resource_aws_cognito_user_pool_test.go | 17 ++++ 2 files changed, 112 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index 9c9179955d83..b7a147d40fb0 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -114,6 +114,19 @@ func resourceAwsCognitoUserPool() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "custom_domain": { + Type: schema.TypeString, + Computed: true, + }, + "domain": { + Type: schema.TypeString, + Computed: true, + }, + "estimated_number_of_users": { + Type: schema.TypeInt, + Computed: true, + }, + "auto_verified_attributes": { Type: schema.TypeSet, Optional: true, @@ -318,6 +331,11 @@ func resourceAwsCognitoUserPool() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + ValidateFunc: validation.Any( + validation.StringLenBetween(1, 128), + validation.StringMatch(regexp.MustCompile(`[\w\s+=,.@-]+`), + `must satisfy regular expression pattern: [\w\s+=,.@-]+`), + ), }, "password_policy": { Type: schema.TypeList, @@ -840,6 +858,9 @@ func resourceAwsCognitoUserPoolRead(d *schema.ResourceData, meta interface{}) er } d.Set("arn", resp.UserPool.Arn) + d.Set("custom_domain", resp.UserPool.CustomDomain) + d.Set("domain", resp.UserPool.Domain) + d.Set("estimated_number_of_users", resp.UserPool.EstimatedNumberOfUsers) d.Set("endpoint", fmt.Sprintf("%s/%s", meta.(*AWSClient).RegionalHostname("cognito-idp"), d.Id())) d.Set("auto_verified_attributes", flattenStringSet(resp.UserPool.AutoVerifiedAttributes)) @@ -1245,11 +1266,6 @@ func resourceAwsCognitoUserPoolDelete(d *schema.ResourceData, meta interface{}) } return nil -} - -func expandCognitoSmsConfiguration(tfList []interface{}) *cognitoidentityprovider.SmsConfigurationType { - if len(tfList) == 0 || tfList[0] == nil { - return nil } tfMap := tfList[0].(map[string]interface{}) @@ -1531,6 +1547,24 @@ func expandCognitoUserPoolLambdaConfig(config map[string]interface{}) *cognitoid configs.VerifyAuthChallengeResponse = aws.String(v.(string)) } + if v, ok := config["kms_key_id"]; ok && v.(string) != "" { + configs.KMSKeyID = aws.String(v.(string)) + } + + if v, ok := config["custom_sms_sender"].([]interface{}); ok && len(v) > 0 { + s, sok := v[0].(map[string]interface{}) + if sok && s != nil { + configs.CustomSMSSender = expandCognitoUserPoolCustomSMSSender(s) + } + } + + if v, ok := config["custom_email_sender"].([]interface{}); ok && len(v) > 0 { + s, sok := v[0].(map[string]interface{}) + if sok && s != nil { + configs.CustomEmailSender = expandCognitoUserPoolCustomEmailSender(s) + } + } + return configs } @@ -1581,6 +1615,18 @@ func flattenCognitoUserPoolLambdaConfig(s *cognitoidentityprovider.LambdaConfigT m["verify_auth_challenge_response"] = aws.StringValue(s.VerifyAuthChallengeResponse) } + if s.KMSKeyID != nil { + m["kms_key_id"] = aws.StringValue(s.KMSKeyID) + } + + if s.CustomSMSSender != nil { + m["custom_sms_sender"] = flattenCognitoUserPoolCustomSMSSender(s.CustomSMSSender) + } + + if s.CustomEmailSender != nil { + m["custom_email_sender"] = flattenCognitoUserPoolCustomEmailSender(s.CustomEmailSender) + } + if len(m) > 0 { return []map[string]interface{}{m} } @@ -2157,3 +2203,47 @@ func cognitoUserPoolSchemaAttributeMatchesStandardAttribute(input *cognitoidenti } return false } + +func expandCognitoUserPoolCustomSMSSender(config map[string]interface{}) *cognitoidentityprovider.CustomSMSLambdaVersionConfigType { + usernameConfigurationType := &cognitoidentityprovider.CustomSMSLambdaVersionConfigType{ + LambdaArn: aws.String(config["lambda_arn"].(string)), + LambdaVersion: aws.String(config["lambda_version"].(string)), + } + + return usernameConfigurationType +} + +func flattenCognitoUserPoolCustomSMSSender(u *cognitoidentityprovider.CustomSMSLambdaVersionConfigType) []map[string]interface{} { + m := map[string]interface{}{} + + if u == nil { + return nil + } + + m["lambda_arn"] = aws.StringValue(u.LambdaArn) + m["lambda_version"] = aws.StringValue(u.LambdaArn) + + return []map[string]interface{}{m} +} + +func expandCognitoUserPoolCustomEmailSender(config map[string]interface{}) *cognitoidentityprovider.CustomEmailLambdaVersionConfigType { + usernameConfigurationType := &cognitoidentityprovider.CustomEmailLambdaVersionConfigType{ + LambdaArn: aws.String(config["lambda_arn"].(string)), + LambdaVersion: aws.String(config["lambda_version"].(string)), + } + + return usernameConfigurationType +} + +func flattenCognitoUserPoolCustomEmailSender(u *cognitoidentityprovider.CustomEmailLambdaVersionConfigType) []map[string]interface{} { + m := map[string]interface{}{} + + if u == nil { + return nil + } + + m["lambda_arn"] = aws.StringValue(u.LambdaArn) + m["lambda_version"] = aws.StringValue(u.LambdaArn) + + return []map[string]interface{}{m} +} diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index 1b276fbdcb3b..471ba4047b72 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -91,6 +91,23 @@ func TestAccAWSCognitoUserPool_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "sms_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "software_token_mfa_configuration.#", "0"), resource.TestCheckResourceAttr(resourceName, "account_recovery_setting.#", "0"), + resource.TestCheckResourceAttr(resourceName, "admin_create_user_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "admin_create_user_config.0.allow_admin_create_user_only", "false"), + resource.TestCheckResourceAttr(resourceName, "admin_create_user_config.0.unused_account_validity_days", "7"), + resource.TestCheckResourceAttr(resourceName, "email_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "email_configuration.0.email_sending_account", "COGNITO_DEFAULT"), + resource.TestCheckResourceAttr(resourceName, "password_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "password_policy.0.minimum_length", "8"), + resource.TestCheckResourceAttr(resourceName, "password_policy.0.require_lowercase", "true"), + resource.TestCheckResourceAttr(resourceName, "password_policy.0.require_numbers", "true"), + resource.TestCheckResourceAttr(resourceName, "password_policy.0.require_symbols", "true"), + resource.TestCheckResourceAttr(resourceName, "password_policy.0.require_uppercase", "true"), + resource.TestCheckResourceAttr(resourceName, "password_policy.0.temporary_password_validity_days", "7"), + resource.TestCheckResourceAttr(resourceName, "verification_message_template.#", "1"), + resource.TestCheckResourceAttr(resourceName, "verification_message_template.0.default_email_option", "CONFIRM_WITH_CODE"), + resource.TestCheckResourceAttr(resourceName, "lambda_config.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "estimated_number_of_users", "0"), ), }, { From eef2905fa1d5f2fc5414a80d7663843efa488905 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 1 Dec 2020 11:21:51 +0200 Subject: [PATCH 0285/1208] add tests for username attributes + change to set --- aws/resource_aws_cognito_user_pool.go | 21 ++++---- aws/resource_aws_cognito_user_pool_test.go | 58 ++++++++++++++++++++++ 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index b7a147d40fb0..6a605657eafb 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -69,9 +69,10 @@ func resourceAwsCognitoUserPool() *schema.Resource { Optional: true, }, "unused_account_validity_days": { - Type: schema.TypeInt, - Optional: true, - Default: 7, + Type: schema.TypeInt, + Optional: true, + Default: 7, + ValidateFunc: validation.IntBetween(0, 365), }, "invite_message_template": { Type: schema.TypeList, @@ -487,7 +488,7 @@ func resourceAwsCognitoUserPool() *schema.Resource { "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), "username_attributes": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, ForceNew: true, Elem: &schema.Schema{ @@ -709,7 +710,7 @@ func resourceAwsCognitoUserPoolCreate(d *schema.ResourceData, meta interface{}) } if v, ok := d.GetOk("username_attributes"); ok { - params.UsernameAttributes = expandStringList(v.([]interface{})) + params.UsernameAttributes = expandStringSet(v.(*schema.Set)) } if v, ok := d.GetOk("username_configuration"); ok { @@ -913,7 +914,7 @@ func resourceAwsCognitoUserPoolRead(d *schema.ResourceData, meta interface{}) er } if resp.UserPool.UsernameAttributes != nil { - d.Set("username_attributes", flattenStringList(resp.UserPool.UsernameAttributes)) + d.Set("username_attributes", flattenStringSet(resp.UserPool.UsernameAttributes)) } if err := d.Set("username_configuration", flattenCognitoUserPoolUsernameConfiguration(resp.UserPool.UsernameConfiguration)); err != nil { @@ -1413,16 +1414,14 @@ func flattenCognitoUserPoolEmailConfiguration(s *cognitoidentityprovider.EmailCo } func expandCognitoUserPoolAdminCreateUserConfig(config map[string]interface{}) *cognitoidentityprovider.AdminCreateUserConfigType { - configs := &cognitoidentityprovider.AdminCreateUserConfigType{} + configs := &cognitoidentityprovider.AdminCreateUserConfigType{ + UnusedAccountValidityDays: aws.Int64(int64(config["unused_account_validity_days"].(int))), + } if v, ok := config["allow_admin_create_user_only"]; ok { configs.AllowAdminCreateUserOnly = aws.Bool(v.(bool)) } - if v, ok := config["unused_account_validity_days"]; ok { - configs.UnusedAccountValidityDays = aws.Int64(int64(v.(int))) - } - if v, ok := config["invite_message_template"]; ok { data := v.([]interface{}) diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index 471ba4047b72..f2151a60594a 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -895,6 +895,43 @@ func TestAccAWSCognitoUserPool_withAliasAttributes(t *testing.T) { }) } +func TestAccAWSCognitoUserPool_withUsernameAttributes(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cognito_user_pool.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolConfig_withUsernameAttributes(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "username_attributes.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "username_attributes.*", "phone_number"), + resource.TestCheckResourceAttr(resourceName, "auto_verified_attributes.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCognitoUserPoolConfig_withUsernameAttributesUpdated(rName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "username_attributes.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "username_attributes.*", "email"), + resource.TestCheckTypeSetElemAttr(resourceName, "username_attributes.*", "phone_number"), + resource.TestCheckResourceAttr(resourceName, "auto_verified_attributes.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "auto_verified_attributes.*", "email"), + ), + }, + }, + }) +} + func TestAccAWSCognitoUserPool_withPasswordPolicy(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool.test" @@ -1765,6 +1802,27 @@ resource "aws_cognito_user_pool" "test" { `, rName) } +func testAccAWSCognitoUserPoolConfig_withUsernameAttributes(rName string) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "test" { + name = %[1]q + + username_attributes = ["phone_number"] +} +`, rName) +} + +func testAccAWSCognitoUserPoolConfig_withUsernameAttributesUpdated(rName string) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "test" { + name = %[1]q + + username_attributes = ["email", "phone_number"] + auto_verified_attributes = ["email"] +} +`, rName) +} + func testAccAWSCognitoUserPoolConfig_withAdminCreateUserConfigAndPasswordPolicy(rName string) string { return fmt.Sprintf(` resource "aws_cognito_user_pool" "test" { From ee2734b8910f1c1236d6f6c8a01466f2bb9f77f1 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 1 Dec 2020 12:16:36 +0200 Subject: [PATCH 0286/1208] lambda test more specific --- aws/resource_aws_cognito_user_pool_test.go | 42 +++++++++++----------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index f2151a60594a..23d10f9d6f62 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -1014,6 +1014,8 @@ func TestAccAWSCognitoUserPool_withUsernameConfiguration(t *testing.T) { func TestAccAWSCognitoUserPool_withLambdaConfig(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool.test" + lambdaResourceName := "aws_lambda_function.test" + lambdaUpdatedResourceName := "aws_lambda_function.second" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, @@ -1026,16 +1028,16 @@ func TestAccAWSCognitoUserPool_withLambdaConfig(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolExists(resourceName, nil), resource.TestCheckResourceAttr(resourceName, "lambda_config.#", "1"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.create_auth_challenge"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.custom_message"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.define_auth_challenge"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.post_authentication"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.post_confirmation"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.pre_authentication"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.pre_sign_up"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.pre_token_generation"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.user_migration"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.verify_auth_challenge_response"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.create_auth_challenge", lambdaResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.custom_message", lambdaResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.define_auth_challenge", lambdaResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.post_authentication", lambdaResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.post_confirmation", lambdaResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.pre_authentication", lambdaResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.pre_sign_up", lambdaResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.pre_token_generation", lambdaResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.user_migration", lambdaResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.verify_auth_challenge_response", lambdaResourceName, "arn"), ), }, { @@ -1047,16 +1049,16 @@ func TestAccAWSCognitoUserPool_withLambdaConfig(t *testing.T) { Config: testAccAWSCognitoUserPoolConfig_withLambdaConfigUpdated(rName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "lambda_config.#", "1"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.create_auth_challenge"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.custom_message"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.define_auth_challenge"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.post_authentication"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.post_confirmation"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.pre_authentication"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.pre_sign_up"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.pre_token_generation"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.user_migration"), - resource.TestCheckResourceAttrSet(resourceName, "lambda_config.0.verify_auth_challenge_response"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.create_auth_challenge", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.custom_message", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.define_auth_challenge", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.post_authentication", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.post_confirmation", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.pre_authentication", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.pre_sign_up", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.pre_token_generation", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.user_migration", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.verify_auth_challenge_response", lambdaUpdatedResourceName, "arn"), ), }, }, From 7b397a2a87edffa02dde0e20e052571d0da74fae Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 1 Dec 2020 17:05:51 +0200 Subject: [PATCH 0287/1208] add tests for lambda config senders --- aws/resource_aws_cognito_user_pool.go | 26 +-- aws/resource_aws_cognito_user_pool_test.go | 221 ++++++++++++++++++--- 2 files changed, 205 insertions(+), 42 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index 6a605657eafb..adc0cf3d65da 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -276,10 +276,11 @@ func resourceAwsCognitoUserPool() *schema.Resource { ValidateFunc: validateArn, }, "custom_email_sender": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + RequiredWith: []string{"lambda_config.0.kms_key_id"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "lambda_arn": { @@ -287,7 +288,7 @@ func resourceAwsCognitoUserPool() *schema.Resource { Required: true, ValidateFunc: validateArn, }, - "email_sending_account": { + "lambda_version": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice(cognitoidentityprovider.CustomEmailSenderLambdaVersionType_Values(), false), @@ -296,10 +297,11 @@ func resourceAwsCognitoUserPool() *schema.Resource { }, }, "custom_sms_sender": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + RequiredWith: []string{"lambda_config.0.kms_key_id"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "lambda_arn": { @@ -307,7 +309,7 @@ func resourceAwsCognitoUserPool() *schema.Resource { Required: true, ValidateFunc: validateArn, }, - "email_sending_account": { + "lambda_version": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice(cognitoidentityprovider.CustomSMSSenderLambdaVersionType_Values(), false), @@ -2220,7 +2222,7 @@ func flattenCognitoUserPoolCustomSMSSender(u *cognitoidentityprovider.CustomSMSL } m["lambda_arn"] = aws.StringValue(u.LambdaArn) - m["lambda_version"] = aws.StringValue(u.LambdaArn) + m["lambda_version"] = aws.StringValue(u.LambdaVersion) return []map[string]interface{}{m} } @@ -2242,7 +2244,7 @@ func flattenCognitoUserPoolCustomEmailSender(u *cognitoidentityprovider.CustomEm } m["lambda_arn"] = aws.StringValue(u.LambdaArn) - m["lambda_version"] = aws.StringValue(u.LambdaArn) + m["lambda_version"] = aws.StringValue(u.LambdaVersion) return []map[string]interface{}{m} } diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index 23d10f9d6f62..59f72973ba10 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -907,7 +907,7 @@ func TestAccAWSCognitoUserPool_withUsernameAttributes(t *testing.T) { { Config: testAccAWSCognitoUserPoolConfig_withUsernameAttributes(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSCognitoUserPoolExists(resourceName), + testAccCheckAWSCognitoUserPoolExists(resourceName, nil), resource.TestCheckResourceAttr(resourceName, "username_attributes.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName, "username_attributes.*", "phone_number"), resource.TestCheckResourceAttr(resourceName, "auto_verified_attributes.#", "0"), @@ -1074,6 +1074,84 @@ func testAccCheckAWSCognitoUserPoolNotRecreated(pool1, pool2 *cognitoidentitypro } } +func TestAccAWSCognitoUserPool_withLambdaConfig_emailConfig(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cognito_user_pool.test" + lambdaResourceName := "aws_lambda_function.test" + lambdaUpdatedResourceName := "aws_lambda_function.second" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolLambdaConfigEmailSenderConfig(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolExists(resourceName, nil), + resource.TestCheckResourceAttr(resourceName, "lambda_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "lambda_config.0.custom_email_sender.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.custom_email_sender.0.lambda_arn", lambdaResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "lambda_config.0.custom_email_sender.0.lambda_version", "V1_0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCognitoUserPoolLambdaConfigEmailSenderConfigUpdated(rName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "lambda_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "lambda_config.0.custom_email_sender.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.custom_email_sender.0.lambda_arn", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "lambda_config.0.custom_email_sender.0.lambda_version", "V1_0"), + ), + }, + }, + }) +} + +func TestAccAWSCognitoUserPool_withLambdaConfig_smsConfig(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cognito_user_pool.test" + lambdaResourceName := "aws_lambda_function.test" + lambdaUpdatedResourceName := "aws_lambda_function.second" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolLambdaConfigSMSSenderConfig(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolExists(resourceName, nil), + resource.TestCheckResourceAttr(resourceName, "lambda_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "lambda_config.0.custom_sms_sender.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.custom_sms_sender.0.lambda_arn", lambdaResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "lambda_config.0.custom_sms_sender.0.lambda_version", "V1_0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCognitoUserPoolLambdaConfigSMSSenderConfigUpdated(rName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "lambda_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "lambda_config.0.custom_sms_sender.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "lambda_config.0.custom_sms_sender.0.lambda_arn", lambdaUpdatedResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "lambda_config.0.custom_sms_sender.0.lambda_version", "V1_0"), + ), + }, + }, + }) +} + func TestAccAWSCognitoUserPool_schemaAttributes(t *testing.T) { var pool1, pool2 cognitoidentityprovider.DescribeUserPoolOutput rName := acctest.RandomWithPrefix("tf-acc-test") @@ -1904,7 +1982,7 @@ resource "aws_cognito_user_pool" "test" { `, name) } -func testAccAWSCognitoUserPoolConfig_withLambdaConfig(name string) string { +func testAccAWSCognitoUserPoolConfigLambdaConfigBase(name string) string { return fmt.Sprintf(` resource "aws_iam_role" "test" { name = %[1]q @@ -1934,6 +2012,33 @@ resource "aws_lambda_function" "test" { runtime = "nodejs12.x" } +resource "aws_kms_key" "test" { + description = "Terraform acc test %[1]s" + deletion_window_in_days = 7 + + policy = < Date: Tue, 1 Dec 2020 17:12:00 +0200 Subject: [PATCH 0288/1208] revert unused_account_validity_days --- aws/resource_aws_cognito_user_pool.go | 14 +------------- aws/resource_aws_cognito_user_pool_test.go | 1 - 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index adc0cf3d65da..52e611552fa6 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -68,12 +68,6 @@ func resourceAwsCognitoUserPool() *schema.Resource { Type: schema.TypeBool, Optional: true, }, - "unused_account_validity_days": { - Type: schema.TypeInt, - Optional: true, - Default: 7, - ValidateFunc: validation.IntBetween(0, 365), - }, "invite_message_template": { Type: schema.TypeList, Optional: true, @@ -1416,9 +1410,7 @@ func flattenCognitoUserPoolEmailConfiguration(s *cognitoidentityprovider.EmailCo } func expandCognitoUserPoolAdminCreateUserConfig(config map[string]interface{}) *cognitoidentityprovider.AdminCreateUserConfigType { - configs := &cognitoidentityprovider.AdminCreateUserConfigType{ - UnusedAccountValidityDays: aws.Int64(int64(config["unused_account_validity_days"].(int))), - } + configs := &cognitoidentityprovider.AdminCreateUserConfigType{} if v, ok := config["allow_admin_create_user_only"]; ok { configs.AllowAdminCreateUserOnly = aws.Bool(v.(bool)) @@ -1464,10 +1456,6 @@ func flattenCognitoUserPoolAdminCreateUserConfig(s *cognitoidentityprovider.Admi config["allow_admin_create_user_only"] = aws.BoolValue(s.AllowAdminCreateUserOnly) } - if s.UnusedAccountValidityDays != nil { - config["unused_account_validity_days"] = aws.Int64Value(s.UnusedAccountValidityDays) - } - if s.InviteMessageTemplate != nil { subconfig := map[string]interface{}{} diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index 59f72973ba10..ad6aa358904a 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -93,7 +93,6 @@ func TestAccAWSCognitoUserPool_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "account_recovery_setting.#", "0"), resource.TestCheckResourceAttr(resourceName, "admin_create_user_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "admin_create_user_config.0.allow_admin_create_user_only", "false"), - resource.TestCheckResourceAttr(resourceName, "admin_create_user_config.0.unused_account_validity_days", "7"), resource.TestCheckResourceAttr(resourceName, "email_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "email_configuration.0.email_sending_account", "COGNITO_DEFAULT"), resource.TestCheckResourceAttr(resourceName, "password_policy.#", "1"), From 9939102359645b0d975230adab58bab879b2ebb0 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 1 Dec 2020 17:23:54 +0200 Subject: [PATCH 0289/1208] fmt --- aws/resource_aws_cognito_user_pool_test.go | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index ad6aa358904a..ffbbf34ab4f9 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -1896,8 +1896,8 @@ func testAccAWSCognitoUserPoolConfig_withUsernameAttributesUpdated(rName string) resource "aws_cognito_user_pool" "test" { name = %[1]q - username_attributes = ["email", "phone_number"] - auto_verified_attributes = ["email"] + username_attributes = ["email", "phone_number"] + auto_verified_attributes = ["email"] } `, rName) } @@ -2092,11 +2092,11 @@ resource "aws_cognito_user_pool" "test" { name = %[1]q lambda_config { - kms_key_id = aws_kms_key.test.arn + kms_key_id = aws_kms_key.test.arn custom_email_sender { - lambda_arn = aws_lambda_function.test.arn - lambda_version = "V1_0" + lambda_arn = aws_lambda_function.test.arn + lambda_version = "V1_0" } } } @@ -2117,11 +2117,11 @@ resource "aws_cognito_user_pool" "test" { name = %[1]q lambda_config { - kms_key_id = aws_kms_key.test.arn + kms_key_id = aws_kms_key.test.arn custom_email_sender { - lambda_arn = aws_lambda_function.second.arn - lambda_version = "V1_0" + lambda_arn = aws_lambda_function.second.arn + lambda_version = "V1_0" } } } @@ -2134,11 +2134,11 @@ resource "aws_cognito_user_pool" "test" { name = %[1]q lambda_config { - kms_key_id = aws_kms_key.test.arn + kms_key_id = aws_kms_key.test.arn custom_sms_sender { - lambda_arn = aws_lambda_function.test.arn - lambda_version = "V1_0" + lambda_arn = aws_lambda_function.test.arn + lambda_version = "V1_0" } } } @@ -2159,11 +2159,11 @@ resource "aws_cognito_user_pool" "test" { name = %[1]q lambda_config { - kms_key_id = aws_kms_key.test.arn + kms_key_id = aws_kms_key.test.arn custom_sms_sender { - lambda_arn = aws_lambda_function.second.arn - lambda_version = "V1_0" + lambda_arn = aws_lambda_function.second.arn + lambda_version = "V1_0" } } } From 2388a45d8b7b8df30443c0f14dfd0cd2f8e6b261 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 1 Dec 2020 19:49:53 +0200 Subject: [PATCH 0290/1208] attribute docs --- website/docs/r/cognito_user_pool.markdown | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/docs/r/cognito_user_pool.markdown b/website/docs/r/cognito_user_pool.markdown index 39c38db602f8..2a36032df23f 100644 --- a/website/docs/r/cognito_user_pool.markdown +++ b/website/docs/r/cognito_user_pool.markdown @@ -221,7 +221,10 @@ In addition to all arguments above, the following attributes are exported: * `arn` - ARN of the user pool. * `creation_date` - Date the user pool was created. +* `custom_domain` - A custom domain name that you provide to Amazon Cognito. This parameter applies only if you use a custom domain to host the sign-up and sign-in pages for your application. For example: `auth.example.com`. +* `domain` - Holds the domain prefix if the user pool has a domain associated with it. * `endpoint` - Endpoint name of the user pool. Example format: `cognito-idp.REGION.amazonaws.com/xxxx_yyyyy` +* `estimated_number_of_users` - A number estimating the size of the user pool. * `id` - ID of the user pool. * `last_modified_date` - Date the user pool was last modified. * `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). From 56543bbc3f5a886d010d17ea386150d5d8967d2f Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 1 Dec 2020 20:03:22 +0200 Subject: [PATCH 0291/1208] fmt --- aws/resource_aws_cognito_user_pool.go | 73 +++++++++++----------- aws/resource_aws_cognito_user_pool_test.go | 8 +-- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index 52e611552fa6..884b671cb552 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -847,52 +847,54 @@ func resourceAwsCognitoUserPoolRead(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("error describing Cognito User Pool (%s): %w", d.Id(), err) } - if err := d.Set("admin_create_user_config", flattenCognitoUserPoolAdminCreateUserConfig(resp.UserPool.AdminCreateUserConfig)); err != nil { + userPool := resp.UserPool + + if err := d.Set("admin_create_user_config", flattenCognitoUserPoolAdminCreateUserConfig(userPool.AdminCreateUserConfig)); err != nil { return fmt.Errorf("failed setting admin_create_user_config: %w", err) } - if resp.UserPool.AliasAttributes != nil { - d.Set("alias_attributes", flattenStringSet(resp.UserPool.AliasAttributes)) + if userPool.AliasAttributes != nil { + d.Set("alias_attributes", flattenStringSet(userPool.AliasAttributes)) } - d.Set("arn", resp.UserPool.Arn) - d.Set("custom_domain", resp.UserPool.CustomDomain) - d.Set("domain", resp.UserPool.Domain) - d.Set("estimated_number_of_users", resp.UserPool.EstimatedNumberOfUsers) + d.Set("arn", userPool.Arn) + d.Set("custom_domain", userPool.CustomDomain) + d.Set("domain", userPool.Domain) + d.Set("estimated_number_of_users", userPool.EstimatedNumberOfUsers) d.Set("endpoint", fmt.Sprintf("%s/%s", meta.(*AWSClient).RegionalHostname("cognito-idp"), d.Id())) - d.Set("auto_verified_attributes", flattenStringSet(resp.UserPool.AutoVerifiedAttributes)) + d.Set("auto_verified_attributes", flattenStringSet(userPool.AutoVerifiedAttributes)) - if resp.UserPool.EmailVerificationSubject != nil { - d.Set("email_verification_subject", resp.UserPool.EmailVerificationSubject) + if userPool.EmailVerificationSubject != nil { + d.Set("email_verification_subject", userPool.EmailVerificationSubject) } - if resp.UserPool.EmailVerificationMessage != nil { - d.Set("email_verification_message", resp.UserPool.EmailVerificationMessage) + if userPool.EmailVerificationMessage != nil { + d.Set("email_verification_message", userPool.EmailVerificationMessage) } - if err := d.Set("lambda_config", flattenCognitoUserPoolLambdaConfig(resp.UserPool.LambdaConfig)); err != nil { + if err := d.Set("lambda_config", flattenCognitoUserPoolLambdaConfig(userPool.LambdaConfig)); err != nil { return fmt.Errorf("failed setting lambda_config: %w", err) } - if resp.UserPool.SmsVerificationMessage != nil { - d.Set("sms_verification_message", resp.UserPool.SmsVerificationMessage) + if userPool.SmsVerificationMessage != nil { + d.Set("sms_verification_message", userPool.SmsVerificationMessage) } - if resp.UserPool.SmsAuthenticationMessage != nil { - d.Set("sms_authentication_message", resp.UserPool.SmsAuthenticationMessage) + if userPool.SmsAuthenticationMessage != nil { + d.Set("sms_authentication_message", userPool.SmsAuthenticationMessage) } - if err := d.Set("device_configuration", flattenCognitoUserPoolDeviceConfiguration(resp.UserPool.DeviceConfiguration)); err != nil { + if err := d.Set("device_configuration", flattenCognitoUserPoolDeviceConfiguration(userPool.DeviceConfiguration)); err != nil { return fmt.Errorf("failed setting device_configuration: %w", err) } - if err := d.Set("account_recovery_setting", flattenCognitoUserPoolAccountRecoverySettingConfig(resp.UserPool.AccountRecoverySetting)); err != nil { + if err := d.Set("account_recovery_setting", flattenCognitoUserPoolAccountRecoverySettingConfig(userPool.AccountRecoverySetting)); err != nil { return fmt.Errorf("failed setting account_recovery_setting: %w", err) } - if resp.UserPool.EmailConfiguration != nil { - if err := d.Set("email_configuration", flattenCognitoUserPoolEmailConfiguration(resp.UserPool.EmailConfiguration)); err != nil { + if userPool.EmailConfiguration != nil { + if err := d.Set("email_configuration", flattenCognitoUserPoolEmailConfiguration(userPool.EmailConfiguration)); err != nil { return fmt.Errorf("failed setting email_configuration: %w", err) } } - if resp.UserPool.Policies != nil && resp.UserPool.Policies.PasswordPolicy != nil { - if err := d.Set("password_policy", flattenCognitoUserPoolPasswordPolicy(resp.UserPool.Policies.PasswordPolicy)); err != nil { + if userPool.Policies != nil && userPool.Policies.PasswordPolicy != nil { + if err := d.Set("password_policy", flattenCognitoUserPoolPasswordPolicy(userPool.Policies.PasswordPolicy)); err != nil { return fmt.Errorf("failed setting password_policy: %w", err) } } @@ -901,34 +903,34 @@ func resourceAwsCognitoUserPoolRead(d *schema.ResourceData, meta interface{}) er if v, ok := d.GetOk("schema"); ok { configuredSchema = v.(*schema.Set).List() } - if err := d.Set("schema", flattenCognitoUserPoolSchema(expandCognitoUserPoolSchema(configuredSchema), resp.UserPool.SchemaAttributes)); err != nil { + if err := d.Set("schema", flattenCognitoUserPoolSchema(expandCognitoUserPoolSchema(configuredSchema), userPool.SchemaAttributes)); err != nil { return fmt.Errorf("failed setting schema: %w", err) } - if err := d.Set("sms_configuration", flattenCognitoSmsConfiguration(resp.UserPool.SmsConfiguration)); err != nil { + if err := d.Set("sms_configuration", flattenCognitoSmsConfiguration(userPool.SmsConfiguration)); err != nil { return fmt.Errorf("failed setting sms_configuration: %w", err) } - if resp.UserPool.UsernameAttributes != nil { - d.Set("username_attributes", flattenStringSet(resp.UserPool.UsernameAttributes)) + if userPool.UsernameAttributes != nil { + d.Set("username_attributes", flattenStringSet(userPool.UsernameAttributes)) } - if err := d.Set("username_configuration", flattenCognitoUserPoolUsernameConfiguration(resp.UserPool.UsernameConfiguration)); err != nil { + if err := d.Set("username_configuration", flattenCognitoUserPoolUsernameConfiguration(userPool.UsernameConfiguration)); err != nil { return fmt.Errorf("failed setting username_configuration: %w", err) } - if err := d.Set("user_pool_add_ons", flattenCognitoUserPoolUserPoolAddOns(resp.UserPool.UserPoolAddOns)); err != nil { + if err := d.Set("user_pool_add_ons", flattenCognitoUserPoolUserPoolAddOns(userPool.UserPoolAddOns)); err != nil { return fmt.Errorf("failed setting user_pool_add_ons: %w", err) } - if err := d.Set("verification_message_template", flattenCognitoUserPoolVerificationMessageTemplate(resp.UserPool.VerificationMessageTemplate)); err != nil { + if err := d.Set("verification_message_template", flattenCognitoUserPoolVerificationMessageTemplate(userPool.VerificationMessageTemplate)); err != nil { return fmt.Errorf("failed setting verification_message_template: %w", err) } - d.Set("creation_date", resp.UserPool.CreationDate.Format(time.RFC3339)) - d.Set("last_modified_date", resp.UserPool.LastModifiedDate.Format(time.RFC3339)) - d.Set("name", resp.UserPool.Name) - tags := keyvaluetags.CognitoidentityKeyValueTags(resp.UserPool.UserPoolTags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + d.Set("creation_date", userPool.CreationDate.Format(time.RFC3339)) + d.Set("last_modified_date", userPool.LastModifiedDate.Format(time.RFC3339)) + d.Set("name", userPool.Name) + tags := keyvaluetags.CognitoidentityKeyValueTags(userPool.UserPoolTags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { @@ -1263,8 +1265,9 @@ func resourceAwsCognitoUserPoolDelete(d *schema.ResourceData, meta interface{}) } return nil - } +} +func expandCognitoSmsConfiguration(tfList []interface{}) *cognitoidentityprovider.SmsConfigurationType { tfMap := tfList[0].(map[string]interface{}) apiObject := &cognitoidentityprovider.SmsConfigurationType{} diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index ffbbf34ab4f9..cbfcd065237b 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -2097,7 +2097,7 @@ resource "aws_cognito_user_pool" "test" { custom_email_sender { lambda_arn = aws_lambda_function.test.arn lambda_version = "V1_0" - } + } } } `, name) @@ -2122,7 +2122,7 @@ resource "aws_cognito_user_pool" "test" { custom_email_sender { lambda_arn = aws_lambda_function.second.arn lambda_version = "V1_0" - } + } } } `, name) @@ -2139,7 +2139,7 @@ resource "aws_cognito_user_pool" "test" { custom_sms_sender { lambda_arn = aws_lambda_function.test.arn lambda_version = "V1_0" - } + } } } `, name) @@ -2164,7 +2164,7 @@ resource "aws_cognito_user_pool" "test" { custom_sms_sender { lambda_arn = aws_lambda_function.second.arn lambda_version = "V1_0" - } + } } } `, name) From bee17bbae97e431b0603ad4d9de85a82aedd4797 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 11 Mar 2021 11:21:56 +0200 Subject: [PATCH 0292/1208] rebase --- aws/resource_aws_cognito_user_pool.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index 884b671cb552..0846b0fda25e 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -1268,6 +1268,10 @@ func resourceAwsCognitoUserPoolDelete(d *schema.ResourceData, meta interface{}) } func expandCognitoSmsConfiguration(tfList []interface{}) *cognitoidentityprovider.SmsConfigurationType { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + tfMap := tfList[0].(map[string]interface{}) apiObject := &cognitoidentityprovider.SmsConfigurationType{} From deb240e6aae721a1146a20b75d2dcd56786714cb Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 11 Mar 2021 12:18:44 +0200 Subject: [PATCH 0293/1208] changelog --- .changelog/16502.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changelog/16502.txt diff --git a/.changelog/16502.txt b/.changelog/16502.txt new file mode 100644 index 000000000000..ec92efd940cb --- /dev/null +++ b/.changelog/16502.txt @@ -0,0 +1,11 @@ +```release-note:enhancement +resource/aws_cognito_user_pool: Add `custom_domain`, `domain`, and `estimated_number_of_users` attributes +``` + +```release-note:enhancement +resource/aws_cognito_user_pool: Add plan time validation for `name` +``` + +```release-note:enhancement +resource/aws_cognito_user_pool: Add `custom_email_sender`, `custom_sms_sender`, and `kms_key_id` to `lambda_config` +``` \ No newline at end of file From f420288d05ffd1be3b2ea74640ed5950ce052cca Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 27 Mar 2021 19:33:15 +0300 Subject: [PATCH 0294/1208] error check --- aws/resource_aws_cognito_user_pool_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index cbfcd065237b..23dfdf1a309c 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -236,7 +236,7 @@ func TestAccAWSCognitoUserPool_withAdvancedSecurityMode(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, - ErrorCheck: testAccErrorCheckSkipCognito(t), + ErrorCheck: testAccErrorCheck(t, cognitoidentityprovider.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, Steps: []resource.TestStep{ @@ -900,6 +900,7 @@ func TestAccAWSCognitoUserPool_withUsernameAttributes(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + ErrorCheck: testAccErrorCheck(t, cognitoidentityprovider.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, Steps: []resource.TestStep{ @@ -1081,6 +1082,7 @@ func TestAccAWSCognitoUserPool_withLambdaConfig_emailConfig(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + ErrorCheck: testAccErrorCheck(t, cognitoidentityprovider.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, Steps: []resource.TestStep{ @@ -1120,6 +1122,7 @@ func TestAccAWSCognitoUserPool_withLambdaConfig_smsConfig(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + ErrorCheck: testAccErrorCheck(t, cognitoidentityprovider.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCognitoUserPoolDestroy, Steps: []resource.TestStep{ From 80f84426199933baacada609ecfa1f23227c29d7 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 20:40:56 +0300 Subject: [PATCH 0295/1208] docs --- website/docs/r/cognito_user_pool.markdown | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/website/docs/r/cognito_user_pool.markdown b/website/docs/r/cognito_user_pool.markdown index 2a36032df23f..dc5de4fef7a3 100644 --- a/website/docs/r/cognito_user_pool.markdown +++ b/website/docs/r/cognito_user_pool.markdown @@ -132,6 +132,17 @@ The following arguments are optional: * `pre_token_generation` - (Optional) Allow to customize identity token claims before token generation. * `user_migration` - (Optional) User migration Lambda config type. * `verify_auth_challenge_response` - (Optional) Verifies the authentication challenge response. +* `kms_key_id` - (Optional) The Amazon Resource Name of Key Management Service Customer master keys. Amazon Cognito uses the key to encrypt codes and temporary passwords sent to CustomEmailSender and CustomSMSSender. +* `custom_email_sender` - (Optional) A custom email sender AWS Lambda trigger. See [custom_email_sender](#custom_email_sender) Below. +* `custom_sms_sender` - (Optional) A custom SMS sender AWS Lambda trigger. See [custom_sms_sender](#custom_sms_sender) Below. + +#### custom_email_sender +* `lambda_arn` - (Required) The Lambda Amazon Resource Name of the Lambda function that Amazon Cognito triggers to send email notifications to users. +* `lambda_version` - (Required) The Lambda version represents the signature of the "request" attribute in the "event" information Amazon Cognito passes to your custom email Lambda function. The only supported value is `V1_0`. + +#### custom_sms_sender +* `lambda_arn` - (Required) he Lambda Amazon Resource Name of the Lambda function that Amazon Cognito triggers to send SMS notifications to users. +* `lambda_version` - (Required) The Lambda version represents the signature of the "request" attribute in the "event" information Amazon Cognito passes to your custom SMS Lambda function. The only supported value is `V1_0`. ### password_policy From ca3e652cd9850278233602dafdd446eef33e8a9d Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 20:44:42 +0300 Subject: [PATCH 0296/1208] fmt --- website/docs/r/cognito_user_pool.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/r/cognito_user_pool.markdown b/website/docs/r/cognito_user_pool.markdown index dc5de4fef7a3..76eeb7c48bfb 100644 --- a/website/docs/r/cognito_user_pool.markdown +++ b/website/docs/r/cognito_user_pool.markdown @@ -137,10 +137,12 @@ The following arguments are optional: * `custom_sms_sender` - (Optional) A custom SMS sender AWS Lambda trigger. See [custom_sms_sender](#custom_sms_sender) Below. #### custom_email_sender + * `lambda_arn` - (Required) The Lambda Amazon Resource Name of the Lambda function that Amazon Cognito triggers to send email notifications to users. * `lambda_version` - (Required) The Lambda version represents the signature of the "request" attribute in the "event" information Amazon Cognito passes to your custom email Lambda function. The only supported value is `V1_0`. #### custom_sms_sender + * `lambda_arn` - (Required) he Lambda Amazon Resource Name of the Lambda function that Amazon Cognito triggers to send SMS notifications to users. * `lambda_version` - (Required) The Lambda version represents the signature of the "request" attribute in the "event" information Amazon Cognito passes to your custom SMS Lambda function. The only supported value is `V1_0`. From 0f31a4b2c02537ac2a492c8845c8824d180c1935 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 7 Jun 2021 13:52:01 -0400 Subject: [PATCH 0297/1208] Suppress Cognito User Pool GovCloud acceptance test errors. --- aws/resource_aws_cognito_user_pool_client_test.go | 10 ++-------- aws/resource_aws_cognito_user_pool_test.go | 8 ++++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool_client_test.go b/aws/resource_aws_cognito_user_pool_client_test.go index 20b0d914838a..237e5f5cb2e6 100644 --- a/aws/resource_aws_cognito_user_pool_client_test.go +++ b/aws/resource_aws_cognito_user_pool_client_test.go @@ -399,7 +399,7 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfig(t *testing.T) { testAccPreCheckAWSCognitoIdentityProvider(t) testAccPreCheckAWSPinpointApp(t) }, - ErrorCheck: testAccErrorCheckSkipCognito(t), + ErrorCheck: testAccErrorCheck(t, cognitoidentityprovider.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ @@ -452,7 +452,7 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfigWithArn(t *testing.T) { testAccPreCheckAWSCognitoIdentityProvider(t) testAccPreCheckAWSPinpointApp(t) }, - ErrorCheck: testAccErrorCheckSkipCognito(t), + ErrorCheck: testAccErrorCheck(t, cognitoidentityprovider.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ @@ -524,12 +524,6 @@ func TestAccAWSCognitoUserPoolClient_disappears_userPool(t *testing.T) { }) } -func testAccErrorCheckSkipCognito(t *testing.T) resource.ErrorCheckFunc { - return testAccErrorCheckSkipMessagesContaining(t, - "not supported in this region", - ) -} - func testAccAWSCognitoUserPoolClientImportStateIDFunc(resourceName string) resource.ImportStateIdFunc { return func(s *terraform.State) (string, error) { rs, ok := s.RootModule().Resources[resourceName] diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index 23dfdf1a309c..126e59e74795 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -17,6 +17,8 @@ import ( ) func init() { + RegisterServiceErrorCheckFunc(cognitoidentityprovider.EndpointsID, testAccErrorCheckSkipCognitoIdentityProvider) + resource.AddTestSweepers("aws_cognito_user_pool", &resource.Sweeper{ Name: "aws_cognito_user_pool", F: testSweepCognitoUserPools, @@ -68,6 +70,12 @@ func testSweepCognitoUserPools(region string) error { return nil } +func testAccErrorCheckSkipCognitoIdentityProvider(t *testing.T) resource.ErrorCheckFunc { + return testAccErrorCheckSkipMessagesContaining(t, + "not supported in this region", + ) +} + func TestAccAWSCognitoUserPool_basic(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool.test" From be4c57c25805fc48bd61252f9e893444544b960f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 7 Jun 2021 14:44:10 -0400 Subject: [PATCH 0298/1208] Handle already deleted aws_cognito_user_pool and aws_cognito_user_pool_client resources. --- aws/resource_aws_cognito_user_pool.go | 5 +++++ aws/resource_aws_cognito_user_pool_client.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index 0846b0fda25e..61a9bf67471e 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -10,6 +10,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -1260,6 +1261,10 @@ func resourceAwsCognitoUserPoolDelete(d *schema.ResourceData, meta interface{}) _, err := conn.DeleteUserPool(params) + if tfawserr.ErrCodeEquals(err, cognitoidentityprovider.ErrCodeResourceNotFoundException) { + return nil + } + if err != nil { return fmt.Errorf("error deleting Cognito user pool (%s): %w", d.Id(), err) } diff --git a/aws/resource_aws_cognito_user_pool_client.go b/aws/resource_aws_cognito_user_pool_client.go index 49a98fc2b7ca..8ec84e4bf163 100644 --- a/aws/resource_aws_cognito_user_pool_client.go +++ b/aws/resource_aws_cognito_user_pool_client.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" + "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" ) @@ -470,6 +471,10 @@ func resourceAwsCognitoUserPoolClientDelete(d *schema.ResourceData, meta interfa _, err := conn.DeleteUserPoolClient(params) + if tfawserr.ErrCodeEquals(err, cognitoidentityprovider.ErrCodeResourceNotFoundException) { + return nil + } + if err != nil { return fmt.Errorf("error deleting Cognito User Pool Client (%s): %w", d.Id(), err) } From 3ce7153a9c6ba54099bd2a661f6f53a813d796ef Mon Sep 17 00:00:00 2001 From: changelogbot Date: Mon, 7 Jun 2021 19:07:24 +0000 Subject: [PATCH 0299/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a6a4fbe89ce..dd369eb6415e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,21 @@ ENHANCEMENTS: +* resource/aws_cognito_user_pool: Add `custom_domain`, `domain`, and `estimated_number_of_users` attributes ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) +* resource/aws_cognito_user_pool: Add `custom_email_sender`, `custom_sms_sender`, and `kms_key_id` to `lambda_config` ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) +* resource/aws_cognito_user_pool: Add plan time validation for `name` ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) * resource/aws_ecs_task_definition: Add plan time validation for `family` and `requires_compatibilities`. ([#19670](https://github.com/hashicorp/terraform-provider-aws/issues/19670)) * resource/aws_ecs_task_definition: Add support for `fsx_windows_file_server_volume_configuration`. ([#19670](https://github.com/hashicorp/terraform-provider-aws/issues/19670)) * resource/aws_fsx_lustre_filesystem: Add `data_compression_type` argument. ([#19664](https://github.com/hashicorp/terraform-provider-aws/issues/19664)) +* resource/aws_sqs_queue: Add `deduplication_scope` and `fifo_throughput_limit` arguments ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) +* resource/aws_sqs_queue: Add `url` attribute ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) BUG FIXES: +* data-source/aws_acmpca_certificate_authority: Fix `error setting tags` ([#19681](https://github.com/hashicorp/terraform-provider-aws/issues/19681)) * resource/aws_lambda_function: Prevents perpetual diff in `vpc_config` ([#17610](https://github.com/hashicorp/terraform-provider-aws/issues/17610)) +* resource/aws_sqs_queue: Allow `visibility_timeout_seconds` to be `0` when creating queue ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) +* resource/aws_sqs_queue: Ensure that queue attributes propagate completely during Create and Update ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) ## 3.44.0 (June 03, 2021) From 6866fa1c3889c9985f29f193422c45ea81d88bce Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 23:19:16 +0300 Subject: [PATCH 0300/1208] update validation --- aws/resource_aws_cognito_user_pool_client.go | 12 +++++++----- ...source_aws_cognito_user_pool_client_test.go | 18 +++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool_client.go b/aws/resource_aws_cognito_user_pool_client.go index 49a98fc2b7ca..02938c6bcb4f 100644 --- a/aws/resource_aws_cognito_user_pool_client.go +++ b/aws/resource_aws_cognito_user_pool_client.go @@ -26,8 +26,9 @@ func resourceAwsCognitoUserPoolClient() *schema.Resource { // https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPoolClient.html Schema: map[string]*schema.Schema{ "access_token_validity": { - Type: schema.TypeInt, - Optional: true, + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 86400), }, "allowed_oauth_flows": { Type: schema.TypeSet, @@ -133,8 +134,9 @@ func resourceAwsCognitoUserPoolClient() *schema.Resource { ForceNew: true, }, "id_token_validity": { - Type: schema.TypeInt, - Optional: true, + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 86400), }, "logout_urls": { Type: schema.TypeSet, @@ -175,7 +177,7 @@ func resourceAwsCognitoUserPoolClient() *schema.Resource { Type: schema.TypeInt, Optional: true, Default: 30, - ValidateFunc: validation.IntBetween(0, 3650), + ValidateFunc: validation.IntBetween(0, 315360000), }, "supported_identity_providers": { Type: schema.TypeSet, diff --git a/aws/resource_aws_cognito_user_pool_client_test.go b/aws/resource_aws_cognito_user_pool_client_test.go index 20b0d914838a..2b69f9d3e0f7 100644 --- a/aws/resource_aws_cognito_user_pool_client_test.go +++ b/aws/resource_aws_cognito_user_pool_client_test.go @@ -761,15 +761,15 @@ data "aws_caller_identity" "current" {} data "aws_partition" "current" {} resource "aws_cognito_user_pool" "test" { - name = "%[1]s" + name = %[1]q } resource "aws_pinpoint_app" "test" { - name = "%[2]s" + name = %[2]q } resource "aws_iam_role" "test" { - name = "%[2]s" + name = %[2]q assume_role_policy = < Date: Mon, 7 Jun 2021 23:25:08 +0300 Subject: [PATCH 0301/1208] changelog --- .changelog/19702.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/19702.txt diff --git a/.changelog/19702.txt b/.changelog/19702.txt new file mode 100644 index 000000000000..dedfe075e980 --- /dev/null +++ b/.changelog/19702.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_cognito_user_pool_client: Add plan time validation for `id_token_validity` and `access_token_validity`. +``` + +```release-note:bug +resource/aws_cognito_user_pool_client: Fix plan time validation for `refresh_token_validity` +``` \ No newline at end of file From 3d11373df0efab17ff29039d3731042a69a08a70 Mon Sep 17 00:00:00 2001 From: kromol Date: Mon, 7 Jun 2021 21:08:15 +0200 Subject: [PATCH 0302/1208] r/aws_cloudwatch_event_target - fix input transformer input paths validation Set max items to be 100 to match current [AWS Documentation][1] [1]: https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_InputTransformer.html#API_InputTransformer_Contents --- aws/resource_aws_cloudwatch_event_target.go | 2 +- ...source_aws_cloudwatch_event_target_test.go | 33 +++++-------------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index d4c60d91cb87..aa7e9ee8d8ec 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -261,7 +261,7 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource { Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, ValidateFunc: validation.All( - MapMaxItems(10), + MapMaxItems(100), MapKeysDoNotMatch(regexp.MustCompile(`^AWS.*$`), "input_path must not start with \"AWS\""), ), }, diff --git a/aws/resource_aws_cloudwatch_event_target_test.go b/aws/resource_aws_cloudwatch_event_target_test.go index 987a4b7eaf3e..601cd6e780c3 100644 --- a/aws/resource_aws_cloudwatch_event_target_test.go +++ b/aws/resource_aws_cloudwatch_event_target_test.go @@ -573,31 +573,16 @@ func TestAccAWSCloudWatchEventTarget_input_transformer(t *testing.T) { var v events.Target rName := acctest.RandomWithPrefix("tf_input_transformer") - tooManyInputPaths := []string{ - "account", - "count", - "eventFirstSeen", - "eventLastSeen", - "Finding_ID", - "Finding_Type", - "instanceId", - "port", - "region", - "severity", - "time", + tooManyInputPaths := make([]string, 101) + for i := range tooManyInputPaths { + tooManyInputPaths[i] = fmt.Sprintf("InvalidField_%d", i) } - validInputPaths := []string{ - "account", - "count", - "eventFirstSeen", - "eventLastSeen", - "Finding_ID", - "Finding_Type", - "instanceId", - "region", - "severity", - "time", + + validInputPaths := make([]string, 100) + for i := range validInputPaths { + validInputPaths[i] = fmt.Sprintf("ValidField_%d", i) } + var expectedInputTemplate strings.Builder fmt.Fprintf(&expectedInputTemplate, `{ "detail-type": "Scheduled Event", @@ -626,7 +611,7 @@ func TestAccAWSCloudWatchEventTarget_input_transformer(t *testing.T) { testAccCheckCloudWatchEventTargetExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "input_transformer.#", "1"), resource.TestCheckResourceAttr(resourceName, "input_transformer.0.input_paths.%", strconv.Itoa(len(validInputPaths))), - resource.TestCheckResourceAttr(resourceName, "input_transformer.0.input_paths.time", "$.time"), + resource.TestCheckResourceAttr(resourceName, "input_transformer.0.input_paths.ValidField_99", "$.ValidField_99"), resource.TestCheckResourceAttr(resourceName, "input_transformer.0.input_template", expectedInputTemplate.String()), ), }, From 32ea4d584c044391af0434e313042946824324e6 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 23:58:57 +0300 Subject: [PATCH 0303/1208] extract email config + supress diff --- aws/resource_aws_cognito_user_pool.go | 102 ++++++++++---------------- 1 file changed, 37 insertions(+), 65 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool.go b/aws/resource_aws_cognito_user_pool.go index 61a9bf67471e..a347a222c27d 100644 --- a/aws/resource_aws_cognito_user_pool.go +++ b/aws/resource_aws_cognito_user_pool.go @@ -32,9 +32,10 @@ func resourceAwsCognitoUserPool() *schema.Resource { // https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html Schema: map[string]*schema.Schema{ "account_recovery_setting": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "recovery_mechanism": { @@ -612,35 +613,8 @@ func resourceAwsCognitoUserPoolCreate(d *schema.ResourceData, meta interface{}) params.AutoVerifiedAttributes = expandStringSet(v.(*schema.Set)) } - if v, ok := d.GetOk("email_configuration"); ok { - configs := v.([]interface{}) - config, ok := configs[0].(map[string]interface{}) - - if ok && config != nil { - emailConfigurationType := &cognitoidentityprovider.EmailConfigurationType{} - - if v, ok := config["reply_to_email_address"]; ok && v.(string) != "" { - emailConfigurationType.ReplyToEmailAddress = aws.String(v.(string)) - } - - if v, ok := config["source_arn"]; ok && v.(string) != "" { - emailConfigurationType.SourceArn = aws.String(v.(string)) - } - - if v, ok := config["from_email_address"]; ok && v.(string) != "" { - emailConfigurationType.From = aws.String(v.(string)) - } - - if v, ok := config["email_sending_account"]; ok && v.(string) != "" { - emailConfigurationType.EmailSendingAccount = aws.String(v.(string)) - } - - if v, ok := config["configuration_set"]; ok && v.(string) != "" { - emailConfigurationType.ConfigurationSet = aws.String(v.(string)) - } - - params.EmailConfiguration = emailConfigurationType - } + if v, ok := d.GetOk("email_configuration"); ok && len(v.([]interface{})) > 0 { + params.EmailConfiguration = expandCognitoUserPoolEmailConfig(v.([]interface{})) } if v, ok := d.GetOk("admin_create_user_config"); ok { @@ -690,8 +664,7 @@ func resourceAwsCognitoUserPoolCreate(d *schema.ResourceData, meta interface{}) } if v, ok := d.GetOk("schema"); ok { - configs := v.(*schema.Set).List() - params.Schema = expandCognitoUserPoolSchema(configs) + params.Schema = expandCognitoUserPoolSchema(v.(*schema.Set).List()) } // For backwards compatibility, include this outside of MFA configuration @@ -1084,37 +1057,8 @@ func resourceAwsCognitoUserPoolUpdate(d *schema.ResourceData, meta interface{}) } } - if v, ok := d.GetOk("email_configuration"); ok { - - configs := v.([]interface{}) - config, ok := configs[0].(map[string]interface{}) - - if ok && config != nil { - log.Printf("[DEBUG] Set Values to update from configs") - emailConfigurationType := &cognitoidentityprovider.EmailConfigurationType{} - - if v, ok := config["reply_to_email_address"]; ok && v.(string) != "" { - emailConfigurationType.ReplyToEmailAddress = aws.String(v.(string)) - } - - if v, ok := config["source_arn"]; ok && v.(string) != "" { - emailConfigurationType.SourceArn = aws.String(v.(string)) - } - - if v, ok := config["email_sending_account"]; ok && v.(string) != "" { - emailConfigurationType.EmailSendingAccount = aws.String(v.(string)) - } - - if v, ok := config["from_email_address"]; ok && v.(string) != "" { - emailConfigurationType.From = aws.String(v.(string)) - } - - if v, ok := config["configuration_set"]; ok && v.(string) != "" { - emailConfigurationType.ConfigurationSet = aws.String(v.(string)) - } - - params.EmailConfiguration = emailConfigurationType - } + if v, ok := d.GetOk("email_configuration"); ok && len(v.([]interface{})) > 0 { + params.EmailConfiguration = expandCognitoUserPoolEmailConfig(v.([]interface{})) } if v, ok := d.GetOk("email_verification_subject"); ok { @@ -2248,3 +2192,31 @@ func flattenCognitoUserPoolCustomEmailSender(u *cognitoidentityprovider.CustomEm return []map[string]interface{}{m} } + +func expandCognitoUserPoolEmailConfig(emailConfig []interface{}) *cognitoidentityprovider.EmailConfigurationType { + config := emailConfig[0].(map[string]interface{}) + + emailConfigurationType := &cognitoidentityprovider.EmailConfigurationType{} + + if v, ok := config["reply_to_email_address"]; ok && v.(string) != "" { + emailConfigurationType.ReplyToEmailAddress = aws.String(v.(string)) + } + + if v, ok := config["source_arn"]; ok && v.(string) != "" { + emailConfigurationType.SourceArn = aws.String(v.(string)) + } + + if v, ok := config["from_email_address"]; ok && v.(string) != "" { + emailConfigurationType.From = aws.String(v.(string)) + } + + if v, ok := config["email_sending_account"]; ok && v.(string) != "" { + emailConfigurationType.EmailSendingAccount = aws.String(v.(string)) + } + + if v, ok := config["configuration_set"]; ok && v.(string) != "" { + emailConfigurationType.ConfigurationSet = aws.String(v.(string)) + } + + return emailConfigurationType +} From 6681af63c6abb8c7a153ca0772bc2d5718174aaf Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 8 Jun 2021 00:01:56 +0300 Subject: [PATCH 0304/1208] changelog --- .changelog/19704.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19704.txt diff --git a/.changelog/19704.txt b/.changelog/19704.txt new file mode 100644 index 000000000000..1f47903d762c --- /dev/null +++ b/.changelog/19704.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_cognito_user_pool: Suppress diff for empty `account_recovery_setting`. +``` \ No newline at end of file From 4bcd9e1686f8c2d22fc23350f2e1c830385f117d Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 8 Jun 2021 00:34:37 +0300 Subject: [PATCH 0305/1208] modify --- aws/resource_aws_cur_report_definition.go | 84 +++++++++++++++++-- ...resource_aws_cur_report_definition_test.go | 54 ++++++++++++ 2 files changed, 129 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_cur_report_definition.go b/aws/resource_aws_cur_report_definition.go index 9d5551c27e52..ae6fc1935b10 100644 --- a/aws/resource_aws_cur_report_definition.go +++ b/aws/resource_aws_cur_report_definition.go @@ -5,6 +5,7 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/costandusagereportservice" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -15,12 +16,17 @@ func resourceAwsCurReportDefinition() *schema.Resource { return &schema.Resource{ Create: resourceAwsCurReportDefinitionCreate, Read: resourceAwsCurReportDefinitionRead, + Update: resourceAwsCurReportDefinitionUpdate, Delete: resourceAwsCurReportDefinitionDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, "report_name": { Type: schema.TypeString, Required: true, @@ -39,7 +45,6 @@ func resourceAwsCurReportDefinition() *schema.Resource { "format": { Type: schema.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.StringInSlice( costandusagereportservice.ReportFormat_Values(), false, @@ -48,7 +53,6 @@ func resourceAwsCurReportDefinition() *schema.Resource { "compression": { Type: schema.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.StringInSlice( costandusagereportservice.CompressionFormat_Values(), false, @@ -70,18 +74,19 @@ func resourceAwsCurReportDefinition() *schema.Resource { "s3_bucket": { Type: schema.TypeString, Required: true, - ForceNew: true, }, "s3_prefix": { Type: schema.TypeString, Optional: true, - ForceNew: true, ValidateFunc: validation.StringLenBetween(0, 256), }, "s3_region": { Type: schema.TypeString, Required: true, - ForceNew: true, + ValidateFunc: validation.StringInSlice( + costandusagereportservice.AWSRegion_Values(), + false, + ), }, "additional_artifacts": { Type: schema.TypeSet, @@ -91,13 +96,10 @@ func resourceAwsCurReportDefinition() *schema.Resource { false, ), }, - Set: schema.HashString, Optional: true, - ForceNew: true, }, "refresh_closed_reports": { Type: schema.TypeBool, - ForceNew: true, Default: true, Optional: true, }, @@ -188,7 +190,18 @@ func resourceAwsCurReportDefinitionRead(d *schema.ResourceData, meta interface{} return nil } - d.SetId(aws.StringValue(reportDefinition.ReportName)) + reportName := aws.StringValue(reportDefinition.ReportName) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "cur", + Region: meta.(*AWSClient).region, + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("definition/%s", reportName), + }.String() + + d.Set("arn", arn) + + d.SetId(reportName) d.Set("report_name", reportDefinition.ReportName) d.Set("time_unit", reportDefinition.TimeUnit) d.Set("format", reportDefinition.Format) @@ -204,6 +217,59 @@ func resourceAwsCurReportDefinitionRead(d *schema.ResourceData, meta interface{} return nil } +func resourceAwsCurReportDefinitionUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).costandusagereportconn + + additionalArtifacts := expandStringSet(d.Get("additional_artifacts").(*schema.Set)) + compression := aws.String(d.Get("compression").(string)) + format := aws.String(d.Get("format").(string)) + prefix := aws.String(d.Get("s3_prefix").(string)) + reportVersioning := aws.String(d.Get("report_versioning").(string)) + + additionalArtifactsList := make([]string, 0) + for i := 0; i < len(additionalArtifacts); i++ { + additionalArtifactsList = append(additionalArtifactsList, *additionalArtifacts[i]) + } + + err := checkAwsCurReportDefinitionPropertyCombination( + additionalArtifactsList, + *compression, + *format, + *prefix, + *reportVersioning, + ) + + if err != nil { + return err + } + + reportName := d.Get("report_name").(string) + + reportDefinition := &costandusagereportservice.ReportDefinition{ + ReportName: aws.String(reportName), + TimeUnit: aws.String(d.Get("time_unit").(string)), + Format: format, + Compression: compression, + AdditionalSchemaElements: expandStringSet(d.Get("additional_schema_elements").(*schema.Set)), + S3Bucket: aws.String(d.Get("s3_bucket").(string)), + S3Prefix: prefix, + S3Region: aws.String(d.Get("s3_region").(string)), + AdditionalArtifacts: additionalArtifacts, + RefreshClosedReports: aws.Bool(d.Get("refresh_closed_reports").(bool)), + ReportVersioning: reportVersioning, + } + + reportDefinitionInput := &costandusagereportservice.ModifyReportDefinitionInput{ + ReportDefinition: reportDefinition, + } + + _, err = conn.ModifyReportDefinition(reportDefinitionInput) + if err != nil { + return fmt.Errorf("Error updating AWS Cost And Usage Report Definition: %w", err) + } + return resourceAwsCurReportDefinitionRead(d, meta) +} + func resourceAwsCurReportDefinitionDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).costandusagereportconn diff --git a/aws/resource_aws_cur_report_definition_test.go b/aws/resource_aws_cur_report_definition_test.go index 226ada470009..9e474c101c5a 100644 --- a/aws/resource_aws_cur_report_definition_test.go +++ b/aws/resource_aws_cur_report_definition_test.go @@ -28,6 +28,7 @@ func TestAccAwsCurReportDefinition_basic(t *testing.T) { Config: testAccAwsCurReportDefinitionConfig_basic(reportName, bucketName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsCurReportDefinitionExists(resourceName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "cur", fmt.Sprintf("definition/%s", reportName)), resource.TestCheckResourceAttr(resourceName, "report_name", reportName), resource.TestCheckResourceAttr(resourceName, "time_unit", "DAILY"), resource.TestCheckResourceAttr(resourceName, "compression", "GZIP"), @@ -38,6 +39,11 @@ func TestAccAwsCurReportDefinition_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "additional_artifacts.#", "2"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -77,6 +83,11 @@ func TestAccAwsCurReportDefinition_textOrCsv(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "report_versioning", reportVersioning), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -115,6 +126,11 @@ func TestAccAwsCurReportDefinition_parquet(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "report_versioning", reportVersioning), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -154,6 +170,11 @@ func TestAccAwsCurReportDefinition_athena(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "report_versioning", reportVersioning), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -193,6 +214,11 @@ func TestAccAwsCurReportDefinition_refresh(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "report_versioning", reportVersioning), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -232,6 +258,34 @@ func TestAccAwsCurReportDefinition_overwrite(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "report_versioning", reportVersioning), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsCurReportDefinition_disappears(t *testing.T) { + resourceName := "aws_cur_report_definition.test" + reportName := acctest.RandomWithPrefix("tf_acc_test") + bucketName := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, + ErrorCheck: testAccErrorCheck(t, costandusagereportservice.EndpointsID), + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsCurReportDefinitionConfig_basic(reportName, bucketName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsCurReportDefinitionExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCurReportDefinition(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, }, }) } From 55502d3b767372216afa8b3e92d34ec5ff77d1eb Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Mon, 7 Jun 2021 21:08:31 -0400 Subject: [PATCH 0306/1208] Update CHANGELOG for #19703 --- .changelog/19703.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19703.txt diff --git a/.changelog/19703.txt b/.changelog/19703.txt new file mode 100644 index 000000000000..99a61761500d --- /dev/null +++ b/.changelog/19703.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_cloudwatch_event_target: Increase the maximum allowed value for the `input_transformer` `input_paths` argument to 100 +``` \ No newline at end of file From 43192bb4575fcc6d75fdf8e519e63b24332b05d9 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Mon, 7 Jun 2021 21:55:00 -0400 Subject: [PATCH 0307/1208] update resource documentation for argument --- website/docs/r/cloudwatch_event_target.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cloudwatch_event_target.html.markdown b/website/docs/r/cloudwatch_event_target.html.markdown index 4bb47f3e22a1..cf4d62ce8cb3 100644 --- a/website/docs/r/cloudwatch_event_target.html.markdown +++ b/website/docs/r/cloudwatch_event_target.html.markdown @@ -390,7 +390,7 @@ For more information, see [Task Networking](https://docs.aws.amazon.com/AmazonEC `input_transformer` support the following: * `input_paths` - (Optional) Key value pairs specified in the form of JSONPath (for example, time = $.time) - * You can have as many as 10 key-value pairs. + * You can have as many as 100 key-value pairs. * You must use JSON dot notation, not bracket notation. * The keys can't start with "AWS". From 3efff3405ef65d980d5a09dc068262f6f7441af6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 05:40:17 +0000 Subject: [PATCH 0308/1208] build(deps): bump hashicorp/github in /infrastructure/repository Bumps [hashicorp/github](https://github.com/hashicorp/terraform-provider-github) from 4.10.1 to 4.11.0. - [Release notes](https://github.com/hashicorp/terraform-provider-github/releases) - [Changelog](https://github.com/hashicorp/terraform-provider-github/blob/master/CHANGELOG.md) - [Commits](https://github.com/hashicorp/terraform-provider-github/commits) --- updated-dependencies: - dependency-name: hashicorp/github dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- infrastructure/repository/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/repository/main.tf b/infrastructure/repository/main.tf index 6e3714578d51..826dcb169b7f 100644 --- a/infrastructure/repository/main.tf +++ b/infrastructure/repository/main.tf @@ -10,7 +10,7 @@ terraform { required_providers { github = { source = "hashicorp/github" - version = "4.10.1" + version = "4.11.0" } } From 0d8a7e041c542e4f696b81deee40694ccac317d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 05:46:47 +0000 Subject: [PATCH 0309/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.55 to 1.38.56 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.55 to 1.38.56. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.55...v1.38.56) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 10d25f67814d..13cd084bc81e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.55 + github.com/aws/aws-sdk-go v1.38.56 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index beed01024c1f..ccc0ffed975f 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.55 h1:1Wv5CE1Zy0hJ6MJUQ1ekFiCsNKBK5W69+towYQ1P4Vs= -github.com/aws/aws-sdk-go v1.38.55/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.56 h1:JI5bnuDfjVLgnBaDHeZO5btxGbYCQ5QA3P0maYtwPQw= +github.com/aws/aws-sdk-go v1.38.56/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From ac31c8310500f521371b8d500efbf21699acaaa4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 05:47:52 +0000 Subject: [PATCH 0310/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.55 to 1.38.56. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.55...v1.38.56) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index d7ef9205c62f..015c2da7b515 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.55 + github.com/aws/aws-sdk-go v1.38.56 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 8266381ef234..196bd6be5e86 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.55 h1:1Wv5CE1Zy0hJ6MJUQ1ekFiCsNKBK5W69+towYQ1P4Vs= -github.com/aws/aws-sdk-go v1.38.55/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.56 h1:JI5bnuDfjVLgnBaDHeZO5btxGbYCQ5QA3P0maYtwPQw= +github.com/aws/aws-sdk-go v1.38.56/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index ba613df59b20..e22e2afa6626 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.55" +const SDKVersion = "1.38.56" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 99bbc4679da0..d37080a0eaa9 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.55 +# github.com/aws/aws-sdk-go v1.38.56 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 789b040c9fc39f11b3101143980918b294bc7d44 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 8 Jun 2021 09:34:41 +0300 Subject: [PATCH 0311/1208] reduce verbose package name + arn test --- aws/resource_aws_cur_report_definition.go | 124 ++++++------- ...resource_aws_cur_report_definition_test.go | 167 +++++++++--------- 2 files changed, 137 insertions(+), 154 deletions(-) diff --git a/aws/resource_aws_cur_report_definition.go b/aws/resource_aws_cur_report_definition.go index ae6fc1935b10..77dbe1b3fa72 100644 --- a/aws/resource_aws_cur_report_definition.go +++ b/aws/resource_aws_cur_report_definition.go @@ -3,10 +3,11 @@ package aws import ( "fmt" "log" + "regexp" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/service/costandusagereportservice" + cur "github.com/aws/aws-sdk-go/service/costandusagereportservice" "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/service/costandusagereportservice/finder" @@ -28,46 +29,36 @@ func resourceAwsCurReportDefinition() *schema.Resource { Computed: true, }, "report_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 256), - }, - "time_unit": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validation.StringInSlice( - costandusagereportservice.TimeUnit_Values(), - false, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 256), + validation.StringMatch(regexp.MustCompile(`[0-9A-Za-z!\-_.*\'()]+`), "The name must be unique, is case sensitive, and can't include spaces."), ), }, + "time_unit": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(cur.TimeUnit_Values(), false), + }, "format": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice( - costandusagereportservice.ReportFormat_Values(), - false, - ), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cur.ReportFormat_Values(), false), }, "compression": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice( - costandusagereportservice.CompressionFormat_Values(), - false, - ), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cur.CompressionFormat_Values(), false), }, "additional_schema_elements": { Type: schema.TypeSet, Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice( - costandusagereportservice.SchemaElement_Values(), - false, - ), + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(cur.SchemaElement_Values(), false), }, - Set: schema.HashString, Required: true, ForceNew: true, }, @@ -81,20 +72,14 @@ func resourceAwsCurReportDefinition() *schema.Resource { ValidateFunc: validation.StringLenBetween(0, 256), }, "s3_region": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice( - costandusagereportservice.AWSRegion_Values(), - false, - ), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(cur.AWSRegion_Values(), false), }, "additional_artifacts": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString, - ValidateFunc: validation.StringInSlice( - costandusagereportservice.AdditionalArtifact_Values(), - false, - ), + ValidateFunc: validation.StringInSlice(cur.AdditionalArtifact_Values(), false), }, Optional: true, }, @@ -104,14 +89,11 @@ func resourceAwsCurReportDefinition() *schema.Resource { Optional: true, }, "report_versioning": { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - Default: costandusagereportservice.ReportVersioningCreateNewReport, - ValidateFunc: validation.StringInSlice( - costandusagereportservice.ReportVersioning_Values(), - false, - ), + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Default: cur.ReportVersioningCreateNewReport, + ValidateFunc: validation.StringInSlice(cur.ReportVersioning_Values(), false), }, }, } @@ -145,7 +127,7 @@ func resourceAwsCurReportDefinitionCreate(d *schema.ResourceData, meta interface reportName := d.Get("report_name").(string) - reportDefinition := &costandusagereportservice.ReportDefinition{ + reportDefinition := &cur.ReportDefinition{ ReportName: aws.String(reportName), TimeUnit: aws.String(d.Get("time_unit").(string)), Format: format, @@ -159,14 +141,14 @@ func resourceAwsCurReportDefinitionCreate(d *schema.ResourceData, meta interface ReportVersioning: reportVersioning, } - reportDefinitionInput := &costandusagereportservice.PutReportDefinitionInput{ + reportDefinitionInput := &cur.PutReportDefinitionInput{ ReportDefinition: reportDefinition, } log.Printf("[DEBUG] Creating AWS Cost and Usage Report Definition : %v", reportDefinitionInput) _, err = conn.PutReportDefinition(reportDefinitionInput) if err != nil { - return fmt.Errorf("Error creating AWS Cost And Usage Report Definition: %s", err) + return fmt.Errorf("Error creating AWS Cost And Usage Report Definition: %w", err) } d.SetId(reportName) return resourceAwsCurReportDefinitionRead(d, meta) @@ -245,7 +227,7 @@ func resourceAwsCurReportDefinitionUpdate(d *schema.ResourceData, meta interface reportName := d.Get("report_name").(string) - reportDefinition := &costandusagereportservice.ReportDefinition{ + reportDefinition := &cur.ReportDefinition{ ReportName: aws.String(reportName), TimeUnit: aws.String(d.Get("time_unit").(string)), Format: format, @@ -259,7 +241,7 @@ func resourceAwsCurReportDefinitionUpdate(d *schema.ResourceData, meta interface ReportVersioning: reportVersioning, } - reportDefinitionInput := &costandusagereportservice.ModifyReportDefinitionInput{ + reportDefinitionInput := &cur.ModifyReportDefinitionInput{ ReportDefinition: reportDefinition, } @@ -273,7 +255,7 @@ func resourceAwsCurReportDefinitionUpdate(d *schema.ResourceData, meta interface func resourceAwsCurReportDefinitionDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).costandusagereportconn - _, err := conn.DeleteReportDefinition(&costandusagereportservice.DeleteReportDefinitionInput{ + _, err := conn.DeleteReportDefinition(&cur.DeleteReportDefinitionInput{ ReportName: aws.String(d.Id()), }) @@ -291,7 +273,7 @@ func checkAwsCurReportDefinitionPropertyCombination(additionalArtifacts []string hasAthena := false for _, artifact := range additionalArtifacts { - if artifact == costandusagereportservice.AdditionalArtifactAthena { + if artifact == cur.AdditionalArtifactAthena { hasAthena = true break } @@ -301,55 +283,55 @@ func checkAwsCurReportDefinitionPropertyCombination(additionalArtifacts []string if len(additionalArtifacts) > 1 { return fmt.Errorf( "When %s exists within additional_artifacts, no other artifact type can be declared", - costandusagereportservice.AdditionalArtifactAthena, + cur.AdditionalArtifactAthena, ) } if len(prefix) == 0 { return fmt.Errorf( "When %s exists within additional_artifacts, prefix cannot be empty", - costandusagereportservice.AdditionalArtifactAthena, + cur.AdditionalArtifactAthena, ) } - if reportVersioning != costandusagereportservice.ReportVersioningOverwriteReport { + if reportVersioning != cur.ReportVersioningOverwriteReport { return fmt.Errorf( "When %s exists within additional_artifacts, report_versioning must be %s", - costandusagereportservice.AdditionalArtifactAthena, - costandusagereportservice.ReportVersioningOverwriteReport, + cur.AdditionalArtifactAthena, + cur.ReportVersioningOverwriteReport, ) } - if format != costandusagereportservice.ReportFormatParquet { + if format != cur.ReportFormatParquet { return fmt.Errorf( "When %s exists within additional_artifacts, both format and compression must be %s", - costandusagereportservice.AdditionalArtifactAthena, - costandusagereportservice.ReportFormatParquet, + cur.AdditionalArtifactAthena, + cur.ReportFormatParquet, ) } - } else if len(additionalArtifacts) > 0 && (format == costandusagereportservice.ReportFormatParquet) { + } else if len(additionalArtifacts) > 0 && (format == cur.ReportFormatParquet) { return fmt.Errorf( "When additional_artifacts includes %s and/or %s, format must not be %s", - costandusagereportservice.AdditionalArtifactQuicksight, - costandusagereportservice.AdditionalArtifactRedshift, - costandusagereportservice.ReportFormatParquet, + cur.AdditionalArtifactQuicksight, + cur.AdditionalArtifactRedshift, + cur.ReportFormatParquet, ) } - if format == costandusagereportservice.ReportFormatParquet { - if compression != costandusagereportservice.CompressionFormatParquet { + if format == cur.ReportFormatParquet { + if compression != cur.CompressionFormatParquet { return fmt.Errorf( "When format is %s, compression must also be %s", - costandusagereportservice.ReportFormatParquet, - costandusagereportservice.CompressionFormatParquet, + cur.ReportFormatParquet, + cur.CompressionFormatParquet, ) } } else { - if compression == costandusagereportservice.CompressionFormatParquet { + if compression == cur.CompressionFormatParquet { return fmt.Errorf( "When format is %s, compression must not be %s", format, - costandusagereportservice.CompressionFormatParquet, + cur.CompressionFormatParquet, ) } } diff --git a/aws/resource_aws_cur_report_definition_test.go b/aws/resource_aws_cur_report_definition_test.go index 9e474c101c5a..c3f11979ffbc 100644 --- a/aws/resource_aws_cur_report_definition_test.go +++ b/aws/resource_aws_cur_report_definition_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/aws/aws-sdk-go/service/costandusagereportservice" + cur "github.com/aws/aws-sdk-go/service/costandusagereportservice" "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" @@ -20,7 +20,7 @@ func TestAccAwsCurReportDefinition_basic(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, - ErrorCheck: testAccErrorCheck(t, costandusagereportservice.EndpointsID), + ErrorCheck: testAccErrorCheck(t, cur.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ @@ -28,7 +28,8 @@ func TestAccAwsCurReportDefinition_basic(t *testing.T) { Config: testAccAwsCurReportDefinitionConfig_basic(reportName, bucketName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsCurReportDefinitionExists(resourceName), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "cur", fmt.Sprintf("definition/%s", reportName)), + //workaround for region being based on s3 bucket region + testAccCheckResourceAttrRegionalARNIgnoreRegionAndAccount(resourceName, "arn", "cur", fmt.Sprintf("definition/%s", reportName)), resource.TestCheckResourceAttr(resourceName, "report_name", reportName), resource.TestCheckResourceAttr(resourceName, "time_unit", "DAILY"), resource.TestCheckResourceAttr(resourceName, "compression", "GZIP"), @@ -62,7 +63,7 @@ func TestAccAwsCurReportDefinition_textOrCsv(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, - ErrorCheck: testAccErrorCheck(t, costandusagereportservice.EndpointsID), + ErrorCheck: testAccErrorCheck(t, cur.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ @@ -106,7 +107,7 @@ func TestAccAwsCurReportDefinition_parquet(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, - ErrorCheck: testAccErrorCheck(t, costandusagereportservice.EndpointsID), + ErrorCheck: testAccErrorCheck(t, cur.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ @@ -149,7 +150,7 @@ func TestAccAwsCurReportDefinition_athena(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, - ErrorCheck: testAccErrorCheck(t, costandusagereportservice.EndpointsID), + ErrorCheck: testAccErrorCheck(t, cur.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ @@ -193,7 +194,7 @@ func TestAccAwsCurReportDefinition_refresh(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, - ErrorCheck: testAccErrorCheck(t, costandusagereportservice.EndpointsID), + ErrorCheck: testAccErrorCheck(t, cur.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ @@ -237,7 +238,7 @@ func TestAccAwsCurReportDefinition_overwrite(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, - ErrorCheck: testAccErrorCheck(t, costandusagereportservice.EndpointsID), + ErrorCheck: testAccErrorCheck(t, cur.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ @@ -274,7 +275,7 @@ func TestAccAwsCurReportDefinition_disappears(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, - ErrorCheck: testAccErrorCheck(t, costandusagereportservice.EndpointsID), + ErrorCheck: testAccErrorCheck(t, cur.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ @@ -482,184 +483,184 @@ func TestCheckAwsCurReportDefinitionPropertyCombination(t *testing.T) { testCases := map[string]propertyCombinationTestCase{ "TestAthenaAndAdditionalArtifacts": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactAthena, - costandusagereportservice.AdditionalArtifactRedshift, + cur.AdditionalArtifactAthena, + cur.AdditionalArtifactRedshift, }, - compression: costandusagereportservice.CompressionFormatZip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatZip, + format: cur.ReportFormatTextOrcsv, prefix: "prefix/", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: true, }, "TestAthenaAndEmptyPrefix": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactAthena, + cur.AdditionalArtifactAthena, }, - compression: costandusagereportservice.CompressionFormatZip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatZip, + format: cur.ReportFormatTextOrcsv, prefix: "", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: true, }, "TestAthenaAndOverrideReport": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactAthena, + cur.AdditionalArtifactAthena, }, - compression: costandusagereportservice.CompressionFormatZip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatZip, + format: cur.ReportFormatTextOrcsv, prefix: "prefix/", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: true, }, "TestAthenaWithNonParquetFormat": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactAthena, + cur.AdditionalArtifactAthena, }, - compression: costandusagereportservice.CompressionFormatParquet, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatParquet, + format: cur.ReportFormatTextOrcsv, prefix: "prefix/", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: true, }, "TestParquetFormatWithoutParquetCompression": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactAthena, + cur.AdditionalArtifactAthena, }, - compression: costandusagereportservice.CompressionFormatZip, - format: costandusagereportservice.ReportFormatParquet, + compression: cur.CompressionFormatZip, + format: cur.ReportFormatParquet, prefix: "prefix/", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: true, }, "TestCSVFormatWithParquetCompression": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactAthena, + cur.AdditionalArtifactAthena, }, - compression: costandusagereportservice.CompressionFormatParquet, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatParquet, + format: cur.ReportFormatTextOrcsv, prefix: "prefix/", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: true, }, "TestRedshiftWithParquetformat": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactRedshift, + cur.AdditionalArtifactRedshift, }, - compression: costandusagereportservice.CompressionFormatParquet, - format: costandusagereportservice.ReportFormatParquet, + compression: cur.CompressionFormatParquet, + format: cur.ReportFormatParquet, prefix: "prefix/", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: true, }, "TestQuicksightWithParquetformat": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactQuicksight, + cur.AdditionalArtifactQuicksight, }, - compression: costandusagereportservice.CompressionFormatParquet, - format: costandusagereportservice.ReportFormatParquet, + compression: cur.CompressionFormatParquet, + format: cur.ReportFormatParquet, prefix: "prefix/", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: true, }, "TestAthenaValidCombination": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactAthena, + cur.AdditionalArtifactAthena, }, - compression: costandusagereportservice.CompressionFormatParquet, - format: costandusagereportservice.ReportFormatParquet, + compression: cur.CompressionFormatParquet, + format: cur.ReportFormatParquet, prefix: "prefix/", - reportVersioning: costandusagereportservice.ReportVersioningOverwriteReport, + reportVersioning: cur.ReportVersioningOverwriteReport, shouldError: false, }, "TestRedshiftWithGzipedOverwrite": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactRedshift, + cur.AdditionalArtifactRedshift, }, - compression: costandusagereportservice.CompressionFormatGzip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatGzip, + format: cur.ReportFormatTextOrcsv, prefix: "prefix/", - reportVersioning: costandusagereportservice.ReportVersioningOverwriteReport, + reportVersioning: cur.ReportVersioningOverwriteReport, shouldError: false, }, "TestRedshiftWithZippedOverwrite": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactRedshift, + cur.AdditionalArtifactRedshift, }, - compression: costandusagereportservice.CompressionFormatZip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatZip, + format: cur.ReportFormatTextOrcsv, prefix: "", - reportVersioning: costandusagereportservice.ReportVersioningOverwriteReport, + reportVersioning: cur.ReportVersioningOverwriteReport, shouldError: false, }, "TestRedshiftWithGzipedCreateNew": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactRedshift, + cur.AdditionalArtifactRedshift, }, - compression: costandusagereportservice.CompressionFormatGzip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatGzip, + format: cur.ReportFormatTextOrcsv, prefix: "", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: false, }, "TestRedshiftWithZippedCreateNew": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactRedshift, + cur.AdditionalArtifactRedshift, }, - compression: costandusagereportservice.CompressionFormatZip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatZip, + format: cur.ReportFormatTextOrcsv, prefix: "", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: false, }, "TestQuicksightWithGzipedOverwrite": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactQuicksight, + cur.AdditionalArtifactQuicksight, }, - compression: costandusagereportservice.CompressionFormatGzip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatGzip, + format: cur.ReportFormatTextOrcsv, prefix: "", - reportVersioning: costandusagereportservice.ReportVersioningOverwriteReport, + reportVersioning: cur.ReportVersioningOverwriteReport, shouldError: false, }, "TestQuicksightWithZippedOverwrite": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactQuicksight, + cur.AdditionalArtifactQuicksight, }, - compression: costandusagereportservice.CompressionFormatZip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatZip, + format: cur.ReportFormatTextOrcsv, prefix: "", - reportVersioning: costandusagereportservice.ReportVersioningOverwriteReport, + reportVersioning: cur.ReportVersioningOverwriteReport, shouldError: false, }, "TestQuicksightWithGzipedCreateNew": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactQuicksight, + cur.AdditionalArtifactQuicksight, }, - compression: costandusagereportservice.CompressionFormatGzip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatGzip, + format: cur.ReportFormatTextOrcsv, prefix: "", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: false, }, "TestQuicksightWithZippedCreateNew": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactQuicksight, + cur.AdditionalArtifactQuicksight, }, - compression: costandusagereportservice.CompressionFormatZip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatZip, + format: cur.ReportFormatTextOrcsv, prefix: "", - reportVersioning: costandusagereportservice.ReportVersioningCreateNewReport, + reportVersioning: cur.ReportVersioningCreateNewReport, shouldError: false, }, "TestMultipleArtifacts": { additionalArtifacts: []string{ - costandusagereportservice.AdditionalArtifactRedshift, - costandusagereportservice.AdditionalArtifactQuicksight, + cur.AdditionalArtifactRedshift, + cur.AdditionalArtifactQuicksight, }, - compression: costandusagereportservice.CompressionFormatGzip, - format: costandusagereportservice.ReportFormatTextOrcsv, + compression: cur.CompressionFormatGzip, + format: cur.ReportFormatTextOrcsv, prefix: "prefix/", - reportVersioning: costandusagereportservice.ReportVersioningOverwriteReport, + reportVersioning: cur.ReportVersioningOverwriteReport, shouldError: false, }, } From 1432fde6f6819ef5f756fc58d76b34ce5d8af263 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 8 Jun 2021 09:37:27 +0300 Subject: [PATCH 0312/1208] docs --- website/docs/r/cur_report_definition.html.markdown | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/website/docs/r/cur_report_definition.html.markdown b/website/docs/r/cur_report_definition.html.markdown index eb89dea79e76..bee683c74d2d 100644 --- a/website/docs/r/cur_report_definition.html.markdown +++ b/website/docs/r/cur_report_definition.html.markdown @@ -34,20 +34,20 @@ resource "aws_cur_report_definition" "example_cur_report_definition" { The following arguments are supported: * `report_name` - (Required) Unique name for the report. Must start with a number/letter and is case sensitive. Limited to 256 characters. -* `time_unit` - (Required) The frequency on which report data are measured and displayed. Valid values are: HOURLY, DAILY. -* `format` - (Required) Format for report. Valid values are: textORcsv, Parquet. If Parquet is used, then Compression must also be Parquet. -* `compression` - (Required) Compression format for report. Valid values are: GZIP, ZIP, Parquet. If Parquet is used, then format must also be Parquet. -* `additional_schema_elements` - (Required) A list of schema elements. Valid values are: RESOURCES. +* `time_unit` - (Required) The frequency on which report data are measured and displayed. Valid values are: `HOURLY`, `DAILY`. +* `format` - (Required) Format for report. Valid values are: `textORcsv`, `Parquet`. If `Parquet` is used, then Compression must also be `Parquet`. +* `compression` - (Required) Compression format for report. Valid values are: `GZIP`, `ZIP`, `Parquet`. If `Parquet` is used, then format must also be `Parquet`. +* `additional_schema_elements` - (Required) A list of schema elements. Valid values are: `RESOURCES`. * `s3_bucket` - (Required) Name of the existing S3 bucket to hold generated reports. * `s3_prefix` - (Optional) Report path prefix. Limited to 256 characters. * `s3_region` - (Required) Region of the existing S3 bucket to hold generated reports. -* `additional_artifacts` - (Required) A list of additional artifacts. Valid values are: REDSHIFT, QUICKSIGHT, ATHENA. When ATHENA exists within additional_artifacts, no other artifact type can be declared and report_versioning must be OVERWRITE_REPORT. +* `additional_artifacts` - (Required) A list of additional artifacts. Valid values are: `REDSHIFT`, `QUICKSIGHT`, `ATHENA`. When ATHENA exists within additional_artifacts, no other artifact type can be declared and report_versioning must be `OVERWRITE_REPORT`. * `refresh_closed_reports` - (Optional) Set to true to update your reports after they have been finalized if AWS detects charges related to previous months. -* `report_versioning` - (Optional) Overwrite the previous version of each report or to deliver the report in addition to the previous versions. Valid values are: CREATE_NEW_REPORT, OVERWRITE_REPORT +* `report_versioning` - (Optional) Overwrite the previous version of each report or to deliver the report in addition to the previous versions. Valid values are: `CREATE_NEW_REPORT` and `OVERWRITE_REPORT`. ## Attributes Reference -No additional attributes are exported. +* `arn` - The Amazon Resource Name (ARN) specifying the cur report. ## Import From cef57beb6d880f785d563fd799300b1bd76d93df Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 8 Jun 2021 10:13:25 +0300 Subject: [PATCH 0313/1208] fix test --- aws/resource_aws_cur_report_definition.go | 53 ++++++++++--------- ...resource_aws_cur_report_definition_test.go | 30 ++++++++--- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/aws/resource_aws_cur_report_definition.go b/aws/resource_aws_cur_report_definition.go index 77dbe1b3fa72..1a4ca66cbefc 100644 --- a/aws/resource_aws_cur_report_definition.go +++ b/aws/resource_aws_cur_report_definition.go @@ -103,10 +103,10 @@ func resourceAwsCurReportDefinitionCreate(d *schema.ResourceData, meta interface conn := meta.(*AWSClient).costandusagereportconn additionalArtifacts := expandStringSet(d.Get("additional_artifacts").(*schema.Set)) - compression := aws.String(d.Get("compression").(string)) - format := aws.String(d.Get("format").(string)) - prefix := aws.String(d.Get("s3_prefix").(string)) - reportVersioning := aws.String(d.Get("report_versioning").(string)) + compression := d.Get("compression").(string) + format := d.Get("format").(string) + prefix := d.Get("s3_prefix").(string) + reportVersioning := d.Get("report_versioning").(string) additionalArtifactsList := make([]string, 0) for i := 0; i < len(additionalArtifacts); i++ { @@ -115,10 +115,10 @@ func resourceAwsCurReportDefinitionCreate(d *schema.ResourceData, meta interface err := checkAwsCurReportDefinitionPropertyCombination( additionalArtifactsList, - *compression, - *format, - *prefix, - *reportVersioning, + compression, + format, + prefix, + reportVersioning, ) if err != nil { @@ -130,15 +130,15 @@ func resourceAwsCurReportDefinitionCreate(d *schema.ResourceData, meta interface reportDefinition := &cur.ReportDefinition{ ReportName: aws.String(reportName), TimeUnit: aws.String(d.Get("time_unit").(string)), - Format: format, - Compression: compression, + Format: aws.String(format), + Compression: aws.String(compression), AdditionalSchemaElements: expandStringSet(d.Get("additional_schema_elements").(*schema.Set)), S3Bucket: aws.String(d.Get("s3_bucket").(string)), - S3Prefix: prefix, + S3Prefix: aws.String(prefix), S3Region: aws.String(d.Get("s3_region").(string)), AdditionalArtifacts: additionalArtifacts, RefreshClosedReports: aws.Bool(d.Get("refresh_closed_reports").(bool)), - ReportVersioning: reportVersioning, + ReportVersioning: aws.String(reportVersioning), } reportDefinitionInput := &cur.PutReportDefinitionInput{ @@ -203,10 +203,10 @@ func resourceAwsCurReportDefinitionUpdate(d *schema.ResourceData, meta interface conn := meta.(*AWSClient).costandusagereportconn additionalArtifacts := expandStringSet(d.Get("additional_artifacts").(*schema.Set)) - compression := aws.String(d.Get("compression").(string)) - format := aws.String(d.Get("format").(string)) - prefix := aws.String(d.Get("s3_prefix").(string)) - reportVersioning := aws.String(d.Get("report_versioning").(string)) + compression := d.Get("compression").(string) + format := d.Get("format").(string) + prefix := d.Get("s3_prefix").(string) + reportVersioning := d.Get("report_versioning").(string) additionalArtifactsList := make([]string, 0) for i := 0; i < len(additionalArtifacts); i++ { @@ -215,10 +215,10 @@ func resourceAwsCurReportDefinitionUpdate(d *schema.ResourceData, meta interface err := checkAwsCurReportDefinitionPropertyCombination( additionalArtifactsList, - *compression, - *format, - *prefix, - *reportVersioning, + compression, + format, + prefix, + reportVersioning, ) if err != nil { @@ -230,19 +230,24 @@ func resourceAwsCurReportDefinitionUpdate(d *schema.ResourceData, meta interface reportDefinition := &cur.ReportDefinition{ ReportName: aws.String(reportName), TimeUnit: aws.String(d.Get("time_unit").(string)), - Format: format, - Compression: compression, + Format: aws.String(format), + Compression: aws.String(compression), AdditionalSchemaElements: expandStringSet(d.Get("additional_schema_elements").(*schema.Set)), S3Bucket: aws.String(d.Get("s3_bucket").(string)), - S3Prefix: prefix, + S3Prefix: aws.String(prefix), S3Region: aws.String(d.Get("s3_region").(string)), AdditionalArtifacts: additionalArtifacts, RefreshClosedReports: aws.Bool(d.Get("refresh_closed_reports").(bool)), - ReportVersioning: reportVersioning, + ReportVersioning: aws.String(reportVersioning), + } + + if err != nil { + return err } reportDefinitionInput := &cur.ModifyReportDefinitionInput{ ReportDefinition: reportDefinition, + ReportName: aws.String(reportName), } _, err = conn.ModifyReportDefinition(reportDefinitionInput) diff --git a/aws/resource_aws_cur_report_definition_test.go b/aws/resource_aws_cur_report_definition_test.go index c3f11979ffbc..566c4206a247 100644 --- a/aws/resource_aws_cur_report_definition_test.go +++ b/aws/resource_aws_cur_report_definition_test.go @@ -25,7 +25,7 @@ func TestAccAwsCurReportDefinition_basic(t *testing.T) { CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsCurReportDefinitionConfig_basic(reportName, bucketName), + Config: testAccAwsCurReportDefinitionConfig_basic(reportName, bucketName, ""), Check: resource.ComposeTestCheckFunc( testAccCheckAwsCurReportDefinitionExists(resourceName), //workaround for region being based on s3 bucket region @@ -45,6 +45,22 @@ func TestAccAwsCurReportDefinition_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccAwsCurReportDefinitionConfig_basic(reportName, bucketName, "test"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsCurReportDefinitionExists(resourceName), + //workaround for region being based on s3 bucket region + testAccCheckResourceAttrRegionalARNIgnoreRegionAndAccount(resourceName, "arn", "cur", fmt.Sprintf("definition/%s", reportName)), + resource.TestCheckResourceAttr(resourceName, "report_name", reportName), + resource.TestCheckResourceAttr(resourceName, "time_unit", "DAILY"), + resource.TestCheckResourceAttr(resourceName, "compression", "GZIP"), + resource.TestCheckResourceAttr(resourceName, "additional_schema_elements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "s3_bucket", bucketName), + resource.TestCheckResourceAttr(resourceName, "s3_prefix", "test"), + resource.TestCheckResourceAttrPair(resourceName, "s3_region", s3BucketResourceName, "region"), + resource.TestCheckResourceAttr(resourceName, "additional_artifacts.#", "2"), + ), + }, }, }) } @@ -280,7 +296,7 @@ func TestAccAwsCurReportDefinition_disappears(t *testing.T) { CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsCurReportDefinitionConfig_basic(reportName, bucketName), + Config: testAccAwsCurReportDefinitionConfig_basic(reportName, bucketName, ""), Check: resource.ComposeTestCheckFunc( testAccCheckAwsCurReportDefinitionExists(resourceName), testAccCheckResourceDisappears(testAccProvider, resourceAwsCurReportDefinition(), resourceName), @@ -336,12 +352,12 @@ func testAccCheckAwsCurReportDefinitionExists(resourceName string) resource.Test } } -func testAccAwsCurReportDefinitionConfig_basic(reportName string, bucketName string) string { +func testAccAwsCurReportDefinitionConfig_basic(reportName, bucketName, prefix string) string { return composeConfig( testAccCurRegionProviderConfig(), fmt.Sprintf(` resource "aws_s3_bucket" "test" { - bucket = "%[2]s" + bucket = %[2]q acl = "private" force_destroy = true } @@ -385,17 +401,17 @@ POLICY resource "aws_cur_report_definition" "test" { depends_on = [aws_s3_bucket_policy.test] # needed to avoid "ValidationException: Failed to verify customer bucket permission." - report_name = "%[1]s" + report_name = %[1]q time_unit = "DAILY" format = "textORcsv" compression = "GZIP" additional_schema_elements = ["RESOURCES"] s3_bucket = aws_s3_bucket.test.id - s3_prefix = "" + s3_prefix = %[3]q s3_region = aws_s3_bucket.test.region additional_artifacts = ["REDSHIFT", "QUICKSIGHT"] } -`, reportName, bucketName)) +`, reportName, bucketName, prefix)) } func testAccAwsCurReportDefinitionConfig_additional(reportName string, bucketName string, bucketPrefix string, format string, compression string, additionalArtifacts []string, refreshClosedReports bool, reportVersioning string) string { From 598a0c8df87774dd5bd941884e716db84bec119a Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 8 Jun 2021 10:16:07 +0300 Subject: [PATCH 0314/1208] changelog --- .changelog/19705.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changelog/19705.txt diff --git a/.changelog/19705.txt b/.changelog/19705.txt new file mode 100644 index 000000000000..2471579cb3df --- /dev/null +++ b/.changelog/19705.txt @@ -0,0 +1,11 @@ +```release-note:enhancement +resource/aws_cur_report_definition: Add `arn` attribute. +``` + +```release-note:enhancement +resource/aws_cur_report_definition: Support updating definition. +``` + +```release-note:enhancement +resource/aws_cur_report_definition: Add plan time validation for `report_name`. +``` \ No newline at end of file From 92586c0546c0d70428df1ec6b7f3e4984215305c Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 8 Jun 2021 10:21:01 +0300 Subject: [PATCH 0315/1208] docs fmt --- website/docs/r/cur_report_definition.html.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/r/cur_report_definition.html.markdown b/website/docs/r/cur_report_definition.html.markdown index bee683c74d2d..9f105d7e3680 100644 --- a/website/docs/r/cur_report_definition.html.markdown +++ b/website/docs/r/cur_report_definition.html.markdown @@ -47,6 +47,8 @@ The following arguments are supported: ## Attributes Reference +In addition to all arguments above, the following attributes are exported: + * `arn` - The Amazon Resource Name (ARN) specifying the cur report. ## Import From 8f0e871353e802af0c411f88b7e9ccfc7532ce25 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 14:32:35 +0300 Subject: [PATCH 0316/1208] transfer server user - efs + refactor --- .../service/transfer/finder/finder.go | 29 ++ .../service/transfer/waiter/status.go | 16 + .../service/transfer/waiter/waiter.go | 18 + aws/resource_aws_transfer_user.go | 153 +++++--- aws/resource_aws_transfer_user_test.go | 350 ++++++++++++------ 5 files changed, 393 insertions(+), 173 deletions(-) diff --git a/aws/internal/service/transfer/finder/finder.go b/aws/internal/service/transfer/finder/finder.go index 5680e032ca24..50493ce74cff 100644 --- a/aws/internal/service/transfer/finder/finder.go +++ b/aws/internal/service/transfer/finder/finder.go @@ -34,3 +34,32 @@ func ServerByID(conn *transfer.Transfer, id string) (*transfer.DescribedServer, return output.Server, nil } + +func UserByID(conn *transfer.Transfer, serverId, userName string) (*transfer.DescribeUserOutput, error) { + input := &transfer.DescribeUserInput{ + ServerId: aws.String(serverId), + UserName: aws.String(userName), + } + + output, err := conn.DescribeUser(input) + + if tfawserr.ErrCodeEquals(err, transfer.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.User == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output, nil +} diff --git a/aws/internal/service/transfer/waiter/status.go b/aws/internal/service/transfer/waiter/status.go index b142972008d3..7f860ac0b8bb 100644 --- a/aws/internal/service/transfer/waiter/status.go +++ b/aws/internal/service/transfer/waiter/status.go @@ -23,3 +23,19 @@ func ServerState(conn *transfer.Transfer, id string) resource.StateRefreshFunc { return output, aws.StringValue(output.State), nil } } + +func UserState(conn *transfer.Transfer, serverId, userName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.UserByID(conn, serverId, userName) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, "Available", nil + } +} diff --git a/aws/internal/service/transfer/waiter/waiter.go b/aws/internal/service/transfer/waiter/waiter.go index a6d5000e2cf7..6ffaed93c522 100644 --- a/aws/internal/service/transfer/waiter/waiter.go +++ b/aws/internal/service/transfer/waiter/waiter.go @@ -9,6 +9,7 @@ import ( const ( ServerDeletedTimeout = 10 * time.Minute + UserDeletedTimeout = 10 * time.Minute ) func ServerCreated(conn *transfer.Transfer, id string, timeout time.Duration) (*transfer.DescribedServer, error) { @@ -78,3 +79,20 @@ func ServerStopped(conn *transfer.Transfer, id string, timeout time.Duration) (* return nil, err } + +func UserDeleted(conn *transfer.Transfer, serverId, userName string) (*transfer.DescribedUser, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"Available"}, + Target: []string{}, + Refresh: UserState(conn, serverId, userName), + Timeout: UserDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*transfer.DescribedUser); ok { + return output, err + } + + return nil, err +} diff --git a/aws/resource_aws_transfer_user.go b/aws/resource_aws_transfer_user.go index f65fddf80274..61f8fdc5fd3e 100644 --- a/aws/resource_aws_transfer_user.go +++ b/aws/resource_aws_transfer_user.go @@ -3,15 +3,16 @@ package aws import ( "fmt" "log" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/transfer" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" tftransfer "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsTransferUser() *schema.Resource { @@ -69,6 +70,28 @@ func resourceAwsTransferUser() *schema.Resource { ValidateFunc: validateIAMPolicyJson, DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs, }, + "posix_profile": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "gid": { + Type: schema.TypeInt, + Required: true, + }, + "uid": { + Type: schema.TypeInt, + Required: true, + }, + "secondary_gids": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeInt}, + Optional: true, + }, + }, + }, + }, "role": { Type: schema.TypeString, @@ -124,6 +147,10 @@ func resourceAwsTransferUserCreate(d *schema.ResourceData, meta interface{}) err createOpts.HomeDirectoryMappings = expandAwsTransferHomeDirectoryMappings(attr.([]interface{})) } + if attr, ok := d.GetOk("posix_profile"); ok { + createOpts.PosixProfile = expandTransferUserPosixUser(attr.([]interface{})) + } + if attr, ok := d.GetOk("policy"); ok { createOpts.Policy = aws.String(attr.(string)) } @@ -154,36 +181,34 @@ func resourceAwsTransferUserRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error parsing Transfer User ID: %s", err) } - descOpts := &transfer.DescribeUserInput{ - UserName: aws.String(userName), - ServerId: aws.String(serverID), + resp, err := finder.UserByID(conn, serverID, userName) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Transfer User (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil } - log.Printf("[DEBUG] Describe Transfer User Option: %#v", descOpts) - - resp, err := conn.DescribeUser(descOpts) if err != nil { - if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] Transfer User (%s) for Server (%s) not found, removing from state", userName, serverID) - d.SetId("") - return nil - } - return fmt.Errorf("error reading Transfer User (%s): %s", d.Id(), err) + return fmt.Errorf("error reading Transfer User (%s): %w", d.Id(), err) } + user := resp.User d.Set("server_id", resp.ServerId) - d.Set("user_name", resp.User.UserName) - d.Set("arn", resp.User.Arn) - d.Set("home_directory", resp.User.HomeDirectory) - d.Set("home_directory_type", resp.User.HomeDirectoryType) - d.Set("policy", resp.User.Policy) - d.Set("role", resp.User.Role) + d.Set("user_name", user.UserName) + d.Set("arn", user.Arn) + d.Set("home_directory", user.HomeDirectory) + d.Set("home_directory_type", user.HomeDirectoryType) + d.Set("policy", user.Policy) + d.Set("role", user.Role) - if err := d.Set("home_directory_mappings", flattenAwsTransferHomeDirectoryMappings(resp.User.HomeDirectoryMappings)); err != nil { - return fmt.Errorf("Error setting home_directory_mappings: %s", err) + if err := d.Set("home_directory_mappings", flattenAwsTransferHomeDirectoryMappings(user.HomeDirectoryMappings)); err != nil { + return fmt.Errorf("Error setting home_directory_mappings: %w", err) } - tags := keyvaluetags.TransferKeyValueTags(resp.User.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + if err := d.Set("posix_profile", flattenTransferUserPosixUser(user.PosixProfile)); err != nil { + return fmt.Errorf("Error setting posix_profile: %w", err) + } + tags := keyvaluetags.TransferKeyValueTags(user.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { @@ -219,6 +244,11 @@ func resourceAwsTransferUserUpdate(d *schema.ResourceData, meta interface{}) err updateFlag = true } + if d.HasChange("posix_profile") { + updateOpts.PosixProfile = expandTransferUserPosixUser(d.Get("posix_profile").([]interface{})) + updateFlag = true + } + if d.HasChange("home_directory_type") { updateOpts.HomeDirectoryType = aws.String(d.Get("home_directory_type").(string)) updateFlag = true @@ -242,14 +272,14 @@ func resourceAwsTransferUserUpdate(d *schema.ResourceData, meta interface{}) err d.SetId("") return nil } - return fmt.Errorf("error updating Transfer User (%s): %s", d.Id(), err) + return fmt.Errorf("error updating Transfer User (%s): %w", d.Id(), err) } } if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") if err := keyvaluetags.TransferUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating tags: %s", err) + return fmt.Errorf("error updating tags: %w", err) } } @@ -260,7 +290,7 @@ func resourceAwsTransferUserDelete(d *schema.ResourceData, meta interface{}) err conn := meta.(*AWSClient).transferconn serverID, userName, err := tftransfer.UserParseResourceID(d.Id()) if err != nil { - return fmt.Errorf("error parsing Transfer User ID: %s", err) + return fmt.Errorf("error parsing Transfer User ID: %w", err) } delOpts := &transfer.DeleteUserInput{ @@ -275,45 +305,15 @@ func resourceAwsTransferUserDelete(d *schema.ResourceData, meta interface{}) err if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { return nil } - return fmt.Errorf("error deleting Transfer User (%s) for Server(%s): %s", userName, serverID, err) + return fmt.Errorf("error deleting Transfer User (%s) for Server(%s): %w", userName, serverID, err) } - if err := waitForTransferUserDeletion(conn, serverID, userName); err != nil { - return fmt.Errorf("error waiting for Transfer User (%s) for Server (%s): %s", userName, serverID, err) - } - - return nil -} + _, err = waiter.UserDeleted(conn, serverID, userName) -func waitForTransferUserDeletion(conn *transfer.Transfer, serverID, userName string) error { - params := &transfer.DescribeUserInput{ - ServerId: aws.String(serverID), - UserName: aws.String(userName), - } - - err := resource.Retry(10*time.Minute, func() *resource.RetryError { - _, err := conn.DescribeUser(params) - - if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { - return nil - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return resource.RetryableError(fmt.Errorf("Transfer User (%s) for Server (%s) still exists", userName, serverID)) - }) - - if isResourceTimeoutError(err) { - _, err = conn.DescribeUser(params) - } - if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { - return nil - } if err != nil { - return fmt.Errorf("Error decoding transfer user ID: %s", err) + return fmt.Errorf("error waiting for Transfer User (%s) delete: %w", d.Id(), err) } + return nil } @@ -344,3 +344,36 @@ func flattenAwsTransferHomeDirectoryMappings(mappings []*transfer.HomeDirectoryM } return l } + +func expandTransferUserPosixUser(pUser []interface{}) *transfer.PosixProfile { + if len(pUser) < 1 || pUser[0] == nil { + return nil + } + + m := pUser[0].(map[string]interface{}) + + posixUser := &transfer.PosixProfile{ + Gid: aws.Int64(int64(m["gid"].(int))), + Uid: aws.Int64(int64(m["uid"].(int))), + } + + if v, ok := m["secondary_gids"].(*schema.Set); ok && len(v.List()) > 0 { + posixUser.SecondaryGids = expandInt64Set(v) + } + + return posixUser +} + +func flattenTransferUserPosixUser(posixUser *transfer.PosixProfile) []interface{} { + if posixUser == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "gid": aws.Int64Value(posixUser.Gid), + "uid": aws.Int64Value(posixUser.Uid), + "secondary_gids": aws.Int64ValueSlice(posixUser.SecondaryGids), + } + + return []interface{}{m} +} diff --git a/aws/resource_aws_transfer_user_test.go b/aws/resource_aws_transfer_user_test.go index ff5567706f4a..c92e735b503f 100644 --- a/aws/resource_aws_transfer_user_test.go +++ b/aws/resource_aws_transfer_user_test.go @@ -5,16 +5,17 @@ import ( "regexp" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/transfer" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestAccAWSTransferUser_basic(t *testing.T) { var conf transfer.DescribedUser - resourceName := "aws_transfer_user.foo" + resourceName := "aws_transfer_user.test" rName := acctest.RandString(10) resource.ParallelTest(t, resource.TestCase{ @@ -28,10 +29,9 @@ func TestAccAWSTransferUser_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferUserExists(resourceName, &conf), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "transfer", regexp.MustCompile(`user/.+`)), - resource.TestCheckResourceAttrPair( - resourceName, "server_id", "aws_transfer_server.foo", "id"), - resource.TestCheckResourceAttrPair( - resourceName, "role", "aws_iam_role.foo", "arn"), + resource.TestCheckResourceAttrPair(resourceName, "server_id", "aws_transfer_server.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "role", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.#", "0"), ), }, { @@ -43,9 +43,48 @@ func TestAccAWSTransferUser_basic(t *testing.T) { }) } +func TestAccAWSTransferUser_posix(t *testing.T) { + var conf transfer.DescribedUser + resourceName := "aws_transfer_user.test" + rName := acctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferUserDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferUserConfigPosix(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferUserExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "posix_profile.#", "1"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.0.gid", "1000"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.0.uid", "1000"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSTransferUserConfigPosixUpdated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferUserExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "posix_profile.#", "1"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.0.gid", "1001"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.0.uid", "1001"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.0.secondary_gids.#", "2"), + ), + }, + }, + }) +} + func TestAccAWSTransferUser_modifyWithOptions(t *testing.T) { var conf transfer.DescribedUser - resourceName := "aws_transfer_user.foo" + resourceName := "aws_transfer_user.test" rName := acctest.RandString(10) rName2 := acctest.RandString(10) @@ -59,44 +98,31 @@ func TestAccAWSTransferUser_modifyWithOptions(t *testing.T) { Config: testAccAWSTransferUserConfig_options(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferUserExists(resourceName, &conf), - resource.TestCheckResourceAttr( - resourceName, "home_directory", "/home/tftestuser"), - resource.TestCheckResourceAttr( - resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr( - resourceName, "tags.NAME", "tftestuser"), - resource.TestCheckResourceAttr( - resourceName, "tags.ENV", "test"), - resource.TestCheckResourceAttr( - resourceName, "tags.ADMIN", "test"), + resource.TestCheckResourceAttr(resourceName, "home_directory", "/home/tftestuser"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), + resource.TestCheckResourceAttr(resourceName, "tags.NAME", "tftestuser"), + resource.TestCheckResourceAttr(resourceName, "tags.ENV", "test"), + resource.TestCheckResourceAttr(resourceName, "tags.ADMIN", "test"), ), }, { Config: testAccAWSTransferUserConfig_modify(rName2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferUserExists(resourceName, &conf), - resource.TestCheckResourceAttrPair( - resourceName, "role", "aws_iam_role.foo", "arn"), - resource.TestCheckResourceAttr( - resourceName, "home_directory", "/test"), - resource.TestCheckResourceAttr( - resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr( - resourceName, "tags.NAME", "tf-test-user"), - resource.TestCheckResourceAttr( - resourceName, "tags.TEST", "test2"), + resource.TestCheckResourceAttrPair(resourceName, "role", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "home_directory", "/test"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.NAME", "tf-test-user"), + resource.TestCheckResourceAttr(resourceName, "tags.TEST", "test2"), ), }, { Config: testAccAWSTransferUserConfig_forceNew(rName2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferUserExists(resourceName, &conf), - resource.TestCheckResourceAttr( - resourceName, "user_name", "tftestuser2"), - resource.TestCheckResourceAttrPair( - resourceName, "role", "aws_iam_role.foo", "arn"), - resource.TestCheckResourceAttr( - resourceName, "home_directory", "/home/tftestuser2"), + resource.TestCheckResourceAttr(resourceName, "user_name", "tftestuser2"), + resource.TestCheckResourceAttrPair(resourceName, "role", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "home_directory", "/home/tftestuser2"), ), }, }, @@ -107,6 +133,7 @@ func TestAccAWSTransferUser_disappears(t *testing.T) { var serverConf transfer.DescribedServer var userConf transfer.DescribedUser rName := acctest.RandString(10) + resourceName := "aws_transfer_user.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, @@ -117,9 +144,9 @@ func TestAccAWSTransferUser_disappears(t *testing.T) { { Config: testAccAWSTransferUserConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSTransferServerExists("aws_transfer_server.foo", &serverConf), - testAccCheckAWSTransferUserExists("aws_transfer_user.foo", &userConf), - testAccCheckAWSTransferUserDisappears(&serverConf, &userConf), + testAccCheckAWSTransferServerExists("aws_transfer_server.test", &serverConf), + testAccCheckAWSTransferUserExists("aws_transfer_user.test", &userConf), + testAccCheckResourceDisappears(testAccProvider, resourceAwsTransferUser(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -167,7 +194,7 @@ func TestAccAWSTransferUser_UserName_Validation(t *testing.T) { func TestAccAWSTransferUser_homeDirectoryMappings(t *testing.T) { var conf transfer.DescribedUser rName := acctest.RandString(10) - resourceName := "aws_transfer_user.foo" + resourceName := "aws_transfer_user.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, @@ -213,11 +240,7 @@ func testAccCheckAWSTransferUserExists(n string, res *transfer.DescribedUser) re userName := rs.Primary.Attributes["user_name"] serverID := rs.Primary.Attributes["server_id"] - describe, err := conn.DescribeUser(&transfer.DescribeUserInput{ - ServerId: aws.String(serverID), - UserName: aws.String(userName), - }) - + describe, err := finder.UserByID(conn, serverID, userName) if err != nil { return err } @@ -228,24 +251,6 @@ func testAccCheckAWSTransferUserExists(n string, res *transfer.DescribedUser) re } } -func testAccCheckAWSTransferUserDisappears(serverConf *transfer.DescribedServer, userConf *transfer.DescribedUser) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).transferconn - - params := &transfer.DeleteUserInput{ - ServerId: serverConf.ServerId, - UserName: userConf.UserName, - } - - _, err := conn.DeleteUser(params) - if err != nil { - return err - } - - return waitForTransferUserDeletion(conn, *serverConf.ServerId, *userConf.UserName) - } -} - func testAccCheckAWSTransferUserDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).transferconn @@ -257,12 +262,8 @@ func testAccCheckAWSTransferUserDestroy(s *terraform.State) error { userName := rs.Primary.Attributes["user_name"] serverID := rs.Primary.Attributes["server_id"] - _, err := conn.DescribeUser(&transfer.DescribeUserInput{ - UserName: aws.String(userName), - ServerId: aws.String(serverID), - }) - - if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { + _, err := finder.UserByID(conn, serverID, userName) + if tfresource.NotFound(err) { continue } @@ -275,7 +276,7 @@ func testAccCheckAWSTransferUserDestroy(s *terraform.State) error { } const testAccAWSTransferUserConfig_base = ` -resource "aws_transfer_server" "foo" { +resource "aws_transfer_server" "test" { identity_provider_type = "SERVICE_MANAGED" tags = { @@ -288,7 +289,7 @@ data "aws_partition" "current" {} func testAccAWSTransferUserConfig_basic(rName string) string { return composeConfig(testAccAWSTransferUserConfig_base, fmt.Sprintf(` -resource "aws_iam_role" "foo" { +resource "aws_iam_role" "test" { name = "tf-test-transfer-user-iam-role-%[1]s" assume_role_policy = < Date: Mon, 7 Jun 2021 14:43:24 +0300 Subject: [PATCH 0317/1208] docs --- website/docs/r/transfer_user.html.markdown | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/website/docs/r/transfer_user.html.markdown b/website/docs/r/transfer_user.html.markdown index e54ed51a8752..f011274e4ab7 100644 --- a/website/docs/r/transfer_user.html.markdown +++ b/website/docs/r/transfer_user.html.markdown @@ -78,19 +78,27 @@ resource "aws_transfer_user" "foo" { The following arguments are supported: -* `server_id` - (Requirement) The Server ID of the Transfer Server (e.g. `s-12345678`) -* `user_name` - (Requirement) The name used for log in to your SFTP server. +* `server_id` - (Required) The Server ID of the Transfer Server (e.g. `s-12345678`) +* `user_name` - (Required) The name used for log in to your SFTP server. * `home_directory` - (Optional) The landing directory (folder) for a user when they log in to the server using their SFTP client. It should begin with a `/`. The first item in the path is the name of the home bucket (accessible as `${Transfer:HomeBucket}` in the policy) and the rest is the home directory (accessible as `${Transfer:HomeDirectory}` in the policy). For example, `/example-bucket-1234/username` would set the home bucket to `example-bucket-1234` and the home directory to `username`. -* `home_directory_mappings` - (Optional) Logical directory mappings that specify what S3 paths and keys should be visible to your user and how you want to make them visible. documented below. +* `home_directory_mappings` - (Optional) Logical directory mappings that specify what S3 paths and keys should be visible to your user and how you want to make them visible. See [Home Directory Mappings](#home-directory-mappings) below. * `home_directory_type` - (Optional) The type of landing directory (folder) you mapped for your users' home directory. Valid values are `PATH` and `LOGICAL`. * `policy` - (Optional) An IAM JSON policy document that scopes down user access to portions of their Amazon S3 bucket. IAM variables you can use inside this policy include `${Transfer:UserName}`, `${Transfer:HomeDirectory}`, and `${Transfer:HomeBucket}`. Since the IAM variable syntax matches Terraform's interpolation syntax, they must be escaped inside Terraform configuration strings (`$${Transfer:UserName}`). These are evaluated on-the-fly when navigating the bucket. -* `role` - (Requirement) Amazon Resource Name (ARN) of an IAM role that allows the service to controls your user’s access to your Amazon S3 bucket. +* `posix_profile` - (Optional) Specifies the full POSIX identity, including user ID (Uid), group ID (Gid), and any secondary groups IDs (SecondaryGids), that controls your users' access to your Amazon EFS file systems. See [Posix Profile](#posix-profile) below. +* `role` - (Required) Amazon Resource Name (ARN) of an IAM role that allows the service to controls your user’s access to your Amazon S3 bucket. * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. -Home Directory Mappings (`home_directory_mappings`) support the following: -* `entry` - (Requirement) Represents an entry and a target. -* `target` - (Requirement) Represents the map target. +### Home Directory Mappings + +* `entry` - (Required) Represents an entry and a target. +* `target` - (Required) Represents the map target. + +### Posix Profile + +* `gid` - (Required) The POSIX group ID used for all EFS operations by this user. +* `uid` - (Required) The POSIX user ID used for all EFS operations by this user. +* `secondary_gids` - (Optional) The secondary POSIX group IDs used for all EFS operations by this user. ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 174d62e82c6ea5ed2104289ddb4839fd2ae8e996 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 14:54:33 +0300 Subject: [PATCH 0318/1208] changelog --- .changelog/19693.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19693.txt diff --git a/.changelog/19693.txt b/.changelog/19693.txt new file mode 100644 index 000000000000..4a1fe974b82c --- /dev/null +++ b/.changelog/19693.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_transfer_user: Add `posix_profile` argument. +``` \ No newline at end of file From 69611c1e9e0bfd7305f94493af9bd50d04c6c695 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 8 Jun 2021 11:17:20 -0400 Subject: [PATCH 0319/1208] Migrate from GitHub HashiBot release_commenter behavior to GitHub Actions (#19696) This action handles transient error, rate limit, and abuse limit retries automatically. --- .github/workflows/milestone-closed.yml | 20 ++++++++++++++++++++ .hashibot.hcl | 10 ---------- 2 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/milestone-closed.yml diff --git a/.github/workflows/milestone-closed.yml b/.github/workflows/milestone-closed.yml new file mode 100644 index 000000000000..2ac8888bf9fd --- /dev/null +++ b/.github/workflows/milestone-closed.yml @@ -0,0 +1,20 @@ +name: Closed Milestones + +on: + milestone: + types: [closed] + +permissions: + issues: write + pull-requests: write + +jobs: + Comment: + runs-on: ubuntu-latest + steps: + - uses: bflad/action-milestone-comment@v1 + with: + body: | + This functionality has been released in [${{ github.event.milestone.title }} of the Terraform AWS Provider](https://github.com/${{ github.repository }}/blob/${{ github.event.milestone.title }}/CHANGELOG.md). Please see the [Terraform documentation on provider versioning](https://www.terraform.io/docs/configuration/providers.html#provider-versions) or reach out if you need any assistance upgrading. + + For further feature requests or bug reports with this functionality, please create a [new GitHub issue](https://github.com/${{ github.repository }}/issues/new/choose) following the template. Thank you! diff --git a/.hashibot.hcl b/.hashibot.hcl index b8d0b6e0377e..964ea520bf15 100644 --- a/.hashibot.hcl +++ b/.hashibot.hcl @@ -1,13 +1,3 @@ -queued_behavior "release_commenter" "releases" { - repo_prefix = "terraform-provider-" - - message = <<-EOF - This has been released in [version ${var.release_version} of the Terraform AWS provider](${var.changelog_link}). Please see the [Terraform documentation on provider versioning](https://www.terraform.io/docs/configuration/providers.html#provider-versions) or reach out if you need any assistance upgrading. - - For further feature requests or bug reports with this functionality, please create a [new GitHub issue](https://github.com/hashicorp/terraform-provider-aws/issues/new/choose) following the template for triage. Thanks! - EOF -} - behavior "pull_request_size_labeler" "size" { label_prefix = "size/" label_map = { From 7b8cd1c3ff676df2341ecb2672263d24ebded93e Mon Sep 17 00:00:00 2001 From: angie pinilla Date: Tue, 8 Jun 2021 11:17:30 -0400 Subject: [PATCH 0320/1208] Update website/docs/r/appsync_graphql_api.html.markdown --- website/docs/r/appsync_graphql_api.html.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/website/docs/r/appsync_graphql_api.html.markdown b/website/docs/r/appsync_graphql_api.html.markdown index ef2125f45e1e..f48964b664dd 100644 --- a/website/docs/r/appsync_graphql_api.html.markdown +++ b/website/docs/r/appsync_graphql_api.html.markdown @@ -176,7 +176,6 @@ resource "aws_wafv2_web_acl" "example" { sampled_requests_enabled = false } } - ``` ## Argument Reference From 8e756ac749a76905dd6dea4fb3f0c6e90a74f771 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 8 Jun 2021 15:20:05 +0000 Subject: [PATCH 0321/1208] Update CHANGELOG.md for #19668 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd369eb6415e..926472cb7a07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,18 +2,25 @@ ENHANCEMENTS: +* data-source/aws_transfer_server: Add `domain` attribute. ([#19691](https://github.com/hashicorp/terraform-provider-aws/issues/19691)) * resource/aws_cognito_user_pool: Add `custom_domain`, `domain`, and `estimated_number_of_users` attributes ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) * resource/aws_cognito_user_pool: Add `custom_email_sender`, `custom_sms_sender`, and `kms_key_id` to `lambda_config` ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) * resource/aws_cognito_user_pool: Add plan time validation for `name` ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) +* resource/aws_default_vpc_dhcp_options: Add `owner_id` argument. ([#19656](https://github.com/hashicorp/terraform-provider-aws/issues/19656)) * resource/aws_ecs_task_definition: Add plan time validation for `family` and `requires_compatibilities`. ([#19670](https://github.com/hashicorp/terraform-provider-aws/issues/19670)) +* resource/aws_ecs_task_definition: Add support for `ephemeral_storage`. ([#19694](https://github.com/hashicorp/terraform-provider-aws/issues/19694)) * resource/aws_ecs_task_definition: Add support for `fsx_windows_file_server_volume_configuration`. ([#19670](https://github.com/hashicorp/terraform-provider-aws/issues/19670)) * resource/aws_fsx_lustre_filesystem: Add `data_compression_type` argument. ([#19664](https://github.com/hashicorp/terraform-provider-aws/issues/19664)) * resource/aws_sqs_queue: Add `deduplication_scope` and `fifo_throughput_limit` arguments ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) * resource/aws_sqs_queue: Add `url` attribute ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) +* resource/aws_transfer_server: Add `domain` argument. ([#19691](https://github.com/hashicorp/terraform-provider-aws/issues/19691)) +* resource/aws_transfer_user: Add `posix_profile` argument. ([#19693](https://github.com/hashicorp/terraform-provider-aws/issues/19693)) BUG FIXES: * data-source/aws_acmpca_certificate_authority: Fix `error setting tags` ([#19681](https://github.com/hashicorp/terraform-provider-aws/issues/19681)) +* resource/aws_cloudwatch_event_target: Increase the maximum allowed value for the `input_transformer` `input_paths` argument to 100 ([#19703](https://github.com/hashicorp/terraform-provider-aws/issues/19703)) +* resource/aws_cloudwatch_metric_alarm: Allow extended statistics in the `stat` argument of the `metric` configuration block ([#19668](https://github.com/hashicorp/terraform-provider-aws/issues/19668)) * resource/aws_lambda_function: Prevents perpetual diff in `vpc_config` ([#17610](https://github.com/hashicorp/terraform-provider-aws/issues/17610)) * resource/aws_sqs_queue: Allow `visibility_timeout_seconds` to be `0` when creating queue ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) * resource/aws_sqs_queue: Ensure that queue attributes propagate completely during Create and Update ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) From 931e3ecda05e74603fce1b0a45715e91cf1a3bc7 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 27 May 2021 21:39:37 +0300 Subject: [PATCH 0322/1208] inital commit --- aws/internal/service/budgets/finder/finder.go | 27 + aws/internal/service/budgets/id.go | 14 + aws/provider.go | 1 + aws/resource_aws_budgets_budget_action.go | 606 ++++++++++++++++++ ...resource_aws_budgets_budget_action_test.go | 261 ++++++++ 5 files changed, 909 insertions(+) create mode 100644 aws/internal/service/budgets/finder/finder.go create mode 100644 aws/internal/service/budgets/id.go create mode 100644 aws/resource_aws_budgets_budget_action.go create mode 100644 aws/resource_aws_budgets_budget_action_test.go diff --git a/aws/internal/service/budgets/finder/finder.go b/aws/internal/service/budgets/finder/finder.go new file mode 100644 index 000000000000..2c399fd8e10b --- /dev/null +++ b/aws/internal/service/budgets/finder/finder.go @@ -0,0 +1,27 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/budgets" + tfbudgets "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/budgets" +) + +func ActionById(conn *budgets.Budgets, id string) (*budgets.DescribeBudgetActionOutput, error) { + accountID, actionID, budgetName, err := tfbudgets.DecodeBudgetsBudgetActionID(id) + if err != nil { + return nil, err + } + + input := &budgets.DescribeBudgetActionInput{ + BudgetName: aws.String(budgetName), + AccountId: aws.String(accountID), + ActionId: aws.String(actionID), + } + + out, err := conn.DescribeBudgetAction(input) + if err != nil { + return nil, err + } + + return out, nil +} diff --git a/aws/internal/service/budgets/id.go b/aws/internal/service/budgets/id.go new file mode 100644 index 000000000000..63d140c7fae9 --- /dev/null +++ b/aws/internal/service/budgets/id.go @@ -0,0 +1,14 @@ +package glue + +import ( + "fmt" + "strings" +) + +func DecodeBudgetsBudgetActionID(id string) (string, string, string, error) { + parts := strings.Split(id, ":") + if len(parts) != 3 { + return "", "", "", fmt.Errorf("Unexpected format of ID (%q), expected AccountID:ActionID:BudgetName", id) + } + return parts[0], parts[1], parts[2], nil +} diff --git a/aws/provider.go b/aws/provider.go index b47fadaea280..b64305a8b894 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -532,6 +532,7 @@ func Provider() *schema.Provider { "aws_backup_vault_notifications": resourceAwsBackupVaultNotifications(), "aws_backup_vault_policy": resourceAwsBackupVaultPolicy(), "aws_budgets_budget": resourceAwsBudgetsBudget(), + "aws_budgets_budget_action": resourceAwsBudgetsBudgetAction(), "aws_cloud9_environment_ec2": resourceAwsCloud9EnvironmentEc2(), "aws_cloudformation_stack": resourceAwsCloudFormationStack(), "aws_cloudformation_stack_set": resourceAwsCloudFormationStackSet(), diff --git a/aws/resource_aws_budgets_budget_action.go b/aws/resource_aws_budgets_budget_action.go new file mode 100644 index 000000000000..744ec4992e6d --- /dev/null +++ b/aws/resource_aws_budgets_budget_action.go @@ -0,0 +1,606 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/budgets" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + tfbudgets "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/budgets" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/budgets/finder" +) + +func resourceAwsBudgetsBudgetAction() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsBudgetsBudgetActionCreate, + Read: resourceAwsBudgetsBudgetActionRead, + Update: resourceAwsBudgetsBudgetActionUpdate, + Delete: resourceAwsBudgetsBudgetActionDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "account_id": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + ValidateFunc: validateAwsAccountId, + }, + "action_id": { + Type: schema.TypeString, + Computed: true, + }, + "action_threshold": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_threshold_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(budgets.ThresholdType_Values(), false), + }, + "action_threshold_value": { + Type: schema.TypeFloat, + Required: true, + ValidateFunc: validation.FloatBetween(0, 40000000000), + }, + }, + }, + }, + "action_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(budgets.ActionType_Values(), false), + }, + "approval_model": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(budgets.ApprovalModel_Values(), false), + }, + "budget_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 100), + validation.StringMatch(regexp.MustCompile(`[^:\\]+`), "The ':' and '\\' characters aren't allowed."), + ), + }, + "definition": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "iam_action_definition": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "policy_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + "groups": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 100, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "roles": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 100, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "users": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 100, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "ssm_action_definition": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_sub_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(budgets.ActionSubType_Values(), false), + }, + "instance_ids": { + Type: schema.TypeSet, + Required: true, + MaxItems: 100, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "region": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "scp_action_definition": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "policy_id": { + Type: schema.TypeString, + Required: true, + }, + "target_ids": { + Type: schema.TypeSet, + Required: true, + MaxItems: 100, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + }, + }, + "execution_role_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + "notification_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(budgets.NotificationType_Values(), false), + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "subscriber": { + Type: schema.TypeSet, + Required: true, + MaxItems: 11, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 2147483647), + validation.StringMatch(regexp.MustCompile(`(.*[\n\r\t\f\ ]?)*`), "Can't contain line breaks."), + )}, + "subscription_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(budgets.SubscriptionType_Values(), false), + }, + }, + }, + }, + }, + } +} + +func resourceAwsBudgetsBudgetActionCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).budgetconn + + var accountID string + if v, ok := d.GetOk("account_id"); ok { + accountID = v.(string) + } else { + accountID = meta.(*AWSClient).accountid + } + + input := &budgets.CreateBudgetActionInput{ + AccountId: aws.String(accountID), + BudgetName: aws.String(d.Get("budget_name").(string)), + ActionType: aws.String(d.Get("action_type").(string)), + ApprovalModel: aws.String(d.Get("approval_model").(string)), + ExecutionRoleArn: aws.String(d.Get("execution_role_arn").(string)), + NotificationType: aws.String(d.Get("notification_type").(string)), + ActionThreshold: expandAwsBudgetsBudgetActionActionThreshold(d.Get("action_threshold").([]interface{})), + Subscribers: expandAwsBudgetsBudgetActionSubscriber(d.Get("subscriber").(*schema.Set)), + Definition: expandAwsBudgetsBudgetActionActionDefinition(d.Get("definition").([]interface{})), + } + + var output *budgets.CreateBudgetActionOutput + _, err := retryOnAwsCode(budgets.ErrCodeAccessDeniedException, func() (interface{}, error) { + var err error + output, err = conn.CreateBudgetAction(input) + return output, err + }) + if err != nil { + return fmt.Errorf("create budget failed: %v", err) + } + + d.SetId(fmt.Sprintf("%s:%s:%s", aws.StringValue(output.AccountId), aws.StringValue(output.ActionId), aws.StringValue(output.BudgetName))) + + return resourceAwsBudgetsBudgetActionRead(d, meta) +} + +func resourceAwsBudgetsBudgetActionRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).budgetconn + out, err := finder.ActionById(conn, d.Id()) + if isAWSErr(err, budgets.ErrCodeNotFoundException, "") { + log.Printf("[WARN] Budget Action %s not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("describe Budget Action failed: %w", err) + } + + action := out.Action + if action == nil { + log.Printf("[WARN] Budget Action %s not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + budgetName := aws.StringValue(out.BudgetName) + actId := aws.StringValue(action.ActionId) + d.Set("account_id", out.AccountId) + d.Set("budget_name", budgetName) + d.Set("action_id", actId) + d.Set("action_type", action.ActionType) + d.Set("approval_model", action.ApprovalModel) + d.Set("execution_role_arn", action.ExecutionRoleArn) + d.Set("notification_type", action.NotificationType) + d.Set("status", action.Status) + + if err := d.Set("subscriber", flattenAwsBudgetsBudgetActionSubscriber(action.Subscribers)); err != nil { + return fmt.Errorf("error setting subscriber: %w", err) + } + + if err := d.Set("definition", flattenAwsBudgetsBudgetActionDefinition(action.Definition)); err != nil { + return fmt.Errorf("error setting definition: %w", err) + } + + if err := d.Set("action_threshold", flattenAwsBudgetsBudgetActionActionThreshold(action.ActionThreshold)); err != nil { + return fmt.Errorf("error setting action_threshold: %w", err) + } + + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "budgetservice", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("budget/%s/action/%s", budgetName, actId), + } + d.Set("arn", arn.String()) + + return nil +} + +func resourceAwsBudgetsBudgetActionUpdate(d *schema.ResourceData, meta interface{}) error { + accountID, actionID, budgetName, err := tfbudgets.DecodeBudgetsBudgetActionID(d.Id()) + if err != nil { + return err + } + + conn := meta.(*AWSClient).budgetconn + input := &budgets.UpdateBudgetActionInput{ + BudgetName: aws.String(budgetName), + AccountId: aws.String(accountID), + ActionId: aws.String(actionID), + } + + if d.HasChange("approval_model") { + input.ApprovalModel = aws.String(d.Get("approval_model").(string)) + } + + if d.HasChange("execution_role_arn") { + input.ExecutionRoleArn = aws.String(d.Get("execution_role_arn").(string)) + } + + if d.HasChange("notification_type") { + input.NotificationType = aws.String(d.Get("notification_type").(string)) + } + + if d.HasChange("action_threshold") { + input.ActionThreshold = expandAwsBudgetsBudgetActionActionThreshold(d.Get("action_threshold").([]interface{})) + } + + if d.HasChange("subscriber") { + input.Subscribers = expandAwsBudgetsBudgetActionSubscriber(d.Get("subscriber").(*schema.Set)) + } + + if d.HasChange("definition") { + input.Definition = expandAwsBudgetsBudgetActionActionDefinition(d.Get("definition").([]interface{})) + } + + _, err = conn.UpdateBudgetAction(input) + if err != nil { + return fmt.Errorf("Updating Budget Action failed: %w", err) + } + + return resourceAwsBudgetsBudgetActionRead(d, meta) +} + +func resourceAwsBudgetsBudgetActionDelete(d *schema.ResourceData, meta interface{}) error { + accountID, actionID, budgetName, err := tfbudgets.DecodeBudgetsBudgetActionID(d.Id()) + if err != nil { + return err + } + + conn := meta.(*AWSClient).budgetconn + _, err = conn.DeleteBudgetAction(&budgets.DeleteBudgetActionInput{ + BudgetName: aws.String(budgetName), + AccountId: aws.String(accountID), + ActionId: aws.String(actionID), + }) + if err != nil { + if isAWSErr(err, budgets.ErrCodeNotFoundException, "") { + log.Printf("[INFO] Budget Action %s could not be found. skipping delete.", d.Id()) + return nil + } + + return fmt.Errorf("Deleting Budget Action failed: %w", err) + } + + return nil +} + +func expandAwsBudgetsBudgetActionActionThreshold(l []interface{}) *budgets.ActionThreshold { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &budgets.ActionThreshold{} + + if v, ok := m["action_threshold_type"].(string); ok && v != "" { + config.ActionThresholdType = aws.String(v) + } + + if v, ok := m["action_threshold_value"].(float64); ok { + config.ActionThresholdValue = aws.Float64(v) + } + + return config +} + +func expandAwsBudgetsBudgetActionSubscriber(l *schema.Set) []*budgets.Subscriber { + if l.Len() == 0 { + return []*budgets.Subscriber{} + } + + items := []*budgets.Subscriber{} + + for _, m := range l.List() { + config := &budgets.Subscriber{} + raw := m.(map[string]interface{}) + + if v, ok := raw["address"].(string); ok && v != "" { + config.Address = aws.String(v) + } + + if v, ok := raw["subscription_type"].(string); ok { + config.SubscriptionType = aws.String(v) + } + + items = append(items, config) + } + + return items +} + +func expandAwsBudgetsBudgetActionActionDefinition(l []interface{}) *budgets.Definition { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &budgets.Definition{} + + if v, ok := m["ssm_action_definition"].([]interface{}); ok && len(v) > 0 { + config.SsmActionDefinition = expandAwsBudgetsBudgetActionActionSsmActionDefinition(v) + } + + if v, ok := m["scp_action_definition"].([]interface{}); ok && len(v) > 0 { + config.ScpActionDefinition = expandAwsBudgetsBudgetActionActionScpActionDefinition(v) + } + + if v, ok := m["iam_action_definition"].([]interface{}); ok && len(v) > 0 { + config.IamActionDefinition = expandAwsBudgetsBudgetActionActionIamActionDefinition(v) + } + + return config +} + +func expandAwsBudgetsBudgetActionActionScpActionDefinition(l []interface{}) *budgets.ScpActionDefinition { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &budgets.ScpActionDefinition{} + + if v, ok := m["policy_id"].(string); ok && v != "" { + config.PolicyId = aws.String(v) + } + + if v, ok := m["target_ids"].(*schema.Set); ok && v.Len() > 0 { + config.TargetIds = expandStringSet(v) + } + + return config +} + +func expandAwsBudgetsBudgetActionActionSsmActionDefinition(l []interface{}) *budgets.SsmActionDefinition { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &budgets.SsmActionDefinition{} + + if v, ok := m["action_sub_type"].(string); ok && v != "" { + config.ActionSubType = aws.String(v) + } + + if v, ok := m["region"].(string); ok && v != "" { + config.Region = aws.String(v) + } + + if v, ok := m["instance_ids"].(*schema.Set); ok && v.Len() > 0 { + config.InstanceIds = expandStringSet(v) + } + + return config +} + +func expandAwsBudgetsBudgetActionActionIamActionDefinition(l []interface{}) *budgets.IamActionDefinition { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &budgets.IamActionDefinition{} + + if v, ok := m["policy_arn"].(string); ok && v != "" { + config.PolicyArn = aws.String(v) + } + + if v, ok := m["groups"].(*schema.Set); ok && v.Len() > 0 { + config.Groups = expandStringSet(v) + } + + if v, ok := m["roles"].(*schema.Set); ok && v.Len() > 0 { + config.Roles = expandStringSet(v) + } + + if v, ok := m["users"].(*schema.Set); ok && v.Len() > 0 { + config.Users = expandStringSet(v) + } + + return config +} + +func flattenAwsBudgetsBudgetActionSubscriber(configured []*budgets.Subscriber) []map[string]interface{} { + dataResources := make([]map[string]interface{}, 0, len(configured)) + + for _, raw := range configured { + item := make(map[string]interface{}) + item["address"] = aws.StringValue(raw.Address) + item["subscription_type"] = aws.StringValue(raw.SubscriptionType) + + dataResources = append(dataResources, item) + } + + return dataResources +} + +func flattenAwsBudgetsBudgetActionActionThreshold(lt *budgets.ActionThreshold) []map[string]interface{} { + if lt == nil { + return []map[string]interface{}{} + } + + attrs := map[string]interface{}{ + "action_threshold_type": aws.StringValue(lt.ActionThresholdType), + "action_threshold_value": aws.Float64Value(lt.ActionThresholdValue), + } + + return []map[string]interface{}{attrs} +} + +func flattenAwsBudgetsBudgetActionIamActionDefinition(lt *budgets.IamActionDefinition) []map[string]interface{} { + if lt == nil { + return []map[string]interface{}{} + } + + attrs := map[string]interface{}{ + "policy_arn": aws.StringValue(lt.PolicyArn), + } + + if lt.Users != nil && len(lt.Users) > 0 { + attrs["users"] = flattenStringSet(lt.Users) + } + + if lt.Roles != nil && len(lt.Roles) > 0 { + attrs["roles"] = flattenStringSet(lt.Roles) + } + + if lt.Groups != nil && len(lt.Groups) > 0 { + attrs["groups"] = flattenStringSet(lt.Groups) + } + + return []map[string]interface{}{attrs} +} + +func flattenAwsBudgetsBudgetActionScpActionDefinition(lt *budgets.ScpActionDefinition) []map[string]interface{} { + if lt == nil { + return []map[string]interface{}{} + } + + attrs := map[string]interface{}{ + "policy_id": aws.StringValue(lt.PolicyId), + } + + if lt.TargetIds != nil && len(lt.TargetIds) > 0 { + attrs["target_ids"] = flattenStringSet(lt.TargetIds) + } + + return []map[string]interface{}{attrs} +} + +func flattenAwsBudgetsBudgetActionSsmActionDefinition(lt *budgets.SsmActionDefinition) []map[string]interface{} { + if lt == nil { + return []map[string]interface{}{} + } + + attrs := map[string]interface{}{ + "action_sub_type": aws.StringValue(lt.ActionSubType), + "instance_ids": flattenStringSet(lt.InstanceIds), + "region": aws.StringValue(lt.Region), + } + + return []map[string]interface{}{attrs} +} + +func flattenAwsBudgetsBudgetActionDefinition(lt *budgets.Definition) []map[string]interface{} { + if lt == nil { + return []map[string]interface{}{} + } + + attrs := map[string]interface{}{} + + if lt.SsmActionDefinition != nil { + attrs["ssm_action_definition"] = flattenAwsBudgetsBudgetActionSsmActionDefinition(lt.SsmActionDefinition) + } + + if lt.IamActionDefinition != nil { + attrs["iam_action_definition"] = flattenAwsBudgetsBudgetActionIamActionDefinition(lt.IamActionDefinition) + } + + if lt.ScpActionDefinition != nil { + attrs["scp_action_definition"] = flattenAwsBudgetsBudgetActionScpActionDefinition(lt.ScpActionDefinition) + } + + return []map[string]interface{}{attrs} +} diff --git a/aws/resource_aws_budgets_budget_action_test.go b/aws/resource_aws_budgets_budget_action_test.go new file mode 100644 index 000000000000..17258472fb96 --- /dev/null +++ b/aws/resource_aws_budgets_budget_action_test.go @@ -0,0 +1,261 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/budgets" + "github.com/hashicorp/go-multierror" + "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/budgets/finder" +) + +func init() { + resource.AddTestSweepers("aws_budgets_budget_action", &resource.Sweeper{ + Name: "aws_budgets_budget_action", + F: testSweepBudgetsBudgetActionss, + }) +} + +func testSweepBudgetsBudgetActionss(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %w", err) + } + conn := client.(*AWSClient).budgetconn + accountID := client.(*AWSClient).accountid + input := &budgets.DescribeBudgetsInput{ + AccountId: aws.String(accountID), + } + var sweeperErrs *multierror.Error + + for { + output, err := conn.DescribeBudgets(input) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Budgets sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + } + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving Budgets: %w", err)) + return sweeperErrs + } + + for _, budget := range output.Budgets { + name := aws.StringValue(budget.BudgetName) + + log.Printf("[INFO] Deleting Budget: %s", name) + _, err := conn.DeleteBudget(&budgets.DeleteBudgetInput{ + AccountId: aws.String(accountID), + BudgetName: aws.String(name), + }) + if isAWSErr(err, budgets.ErrCodeNotFoundException, "") { + continue + } + if err != nil { + sweeperErr := fmt.Errorf("error deleting Budget (%s): %w", name, err) + log.Printf("[ERROR] %s", sweeperErr) + sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + continue + } + } + + if aws.StringValue(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSBudgetsBudgetAction_basic(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_budgets_budget_action.test" + var conf budgets.Action + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(budgets.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, budgets.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccAWSBudgetsBudgetActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSBudgetsBudgetActionConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccAWSBudgetsBudgetActionExists(resourceName, &conf), + testAccMatchResourceAttrGlobalARN(resourceName, "arn", "budgetservice", regexp.MustCompile(fmt.Sprintf(`budget/%s/action/.+`, rName))), + resource.TestCheckResourceAttrPair(resourceName, "budget_name", "aws_budgets_budget.test", "name"), + resource.TestCheckResourceAttrPair(resourceName, "execution_role_arn", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "action_type", "APPLY_IAM_POLICY"), + resource.TestCheckResourceAttr(resourceName, "approval_model", "AUTOMATIC"), + resource.TestCheckResourceAttr(resourceName, "notification_type", "ACTUAL"), + resource.TestCheckResourceAttr(resourceName, "action_threshold.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action_threshold.0.action_threshold_type", "ABSOLUTE_VALUE"), + resource.TestCheckResourceAttr(resourceName, "action_threshold.0.action_threshold_value", "100"), + resource.TestCheckResourceAttr(resourceName, "definition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "definition.0.iam_action_definition.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "definition.0.iam_action_definition.0.policy_arn", "aws_iam_policy.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "definition.0.iam_action_definition.0.roles.#", "1"), + resource.TestCheckResourceAttr(resourceName, "subscriber.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSBudgetsBudgetAction_disappears(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_budgets_budget_action.test" + var conf budgets.Action + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(budgets.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, budgets.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccAWSBudgetsBudgetActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSBudgetsBudgetActionConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccAWSBudgetsBudgetActionExists(resourceName, &conf), + testAccCheckResourceDisappears(testAccProvider, resourceAwsBudgetsBudgetAction(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccAWSBudgetsBudgetActionExists(resourceName string, config *budgets.Action) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).budgetconn + out, err := finder.ActionById(conn, rs.Primary.ID) + + if err != nil { + return fmt.Errorf("Describe budget action error: %v", err) + } + + if out.Action == nil { + return fmt.Errorf("No budget Action returned %v in %v", out.Action, out) + } + + *out.Action = *config + + return nil + } +} + +func testAccAWSBudgetsBudgetActionDestroy(s *terraform.State) error { + meta := testAccProvider.Meta() + conn := meta.(*AWSClient).budgetconn + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_budgets_budget_action" { + continue + } + + _, err := finder.ActionById(conn, rs.Primary.ID) + if !isAWSErr(err, budgets.ErrCodeNotFoundException, "") { + return fmt.Errorf("Budget Action '%s' was not deleted properly", rs.Primary.ID) + } + } + + return nil +} + +func testAccAWSBudgetsBudgetActionConfigBasic(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_policy" "test" { + name = %[1]q + description = "My test policy" + + policy = < Date: Thu, 27 May 2021 21:47:22 +0300 Subject: [PATCH 0323/1208] sweeper --- ...resource_aws_budgets_budget_action_test.go | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/aws/resource_aws_budgets_budget_action_test.go b/aws/resource_aws_budgets_budget_action_test.go index 17258472fb96..820b67218a5f 100644 --- a/aws/resource_aws_budgets_budget_action_test.go +++ b/aws/resource_aws_budgets_budget_action_test.go @@ -29,13 +29,13 @@ func testSweepBudgetsBudgetActionss(region string) error { } conn := client.(*AWSClient).budgetconn accountID := client.(*AWSClient).accountid - input := &budgets.DescribeBudgetsInput{ + input := &budgets.DescribeBudgetActionsForAccountInput{ AccountId: aws.String(accountID), } var sweeperErrs *multierror.Error for { - output, err := conn.DescribeBudgets(input) + output, err := conn.DescribeBudgetActionsForAccount(input) if testSweepSkipSweepError(err) { log.Printf("[WARN] Skipping Budgets sweep for %s: %s", region, err) return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors @@ -45,19 +45,18 @@ func testSweepBudgetsBudgetActionss(region string) error { return sweeperErrs } - for _, budget := range output.Budgets { - name := aws.StringValue(budget.BudgetName) + for _, action := range output.Actions { + name := aws.StringValue(action.BudgetName) + log.Printf("[INFO] Deleting Budget Action: %s", name) + id := fmt.Sprintf("%s:%s:%s", accountID, aws.StringValue(action.ActionId), name) - log.Printf("[INFO] Deleting Budget: %s", name) - _, err := conn.DeleteBudget(&budgets.DeleteBudgetInput{ - AccountId: aws.String(accountID), - BudgetName: aws.String(name), - }) - if isAWSErr(err, budgets.ErrCodeNotFoundException, "") { - continue - } + r := resourceAwsBudgetsBudgetAction() + d := r.Data(nil) + d.SetId(id) + + err := r.Delete(d, client) if err != nil { - sweeperErr := fmt.Errorf("error deleting Budget (%s): %w", name, err) + sweeperErr := fmt.Errorf("error deleting Budget Action (%s): %w", name, err) log.Printf("[ERROR] %s", sweeperErr) sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) continue From dd77e8dca988f3b57c2414792fd931a76093baed Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 27 May 2021 22:10:56 +0300 Subject: [PATCH 0324/1208] docs --- .../r/budgets_budget_action.html.markdown | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 website/docs/r/budgets_budget_action.html.markdown diff --git a/website/docs/r/budgets_budget_action.html.markdown b/website/docs/r/budgets_budget_action.html.markdown new file mode 100644 index 000000000000..ef0255d11282 --- /dev/null +++ b/website/docs/r/budgets_budget_action.html.markdown @@ -0,0 +1,157 @@ +--- +subcategory: "Budgets" +layout: "aws" +page_title: "AWS: aws_budgets_budget_action" +description: |- + Provides a budgets budget action resource. +--- + +# Resource: aws_budgets_budget_action + +Provides a budgets budget resource. Budgets use the cost visualisation provided by Cost Explorer to show you the status of your budgets, to provide forecasts of your estimated costs, and to track your AWS usage, including your free tier usage. + +## Example Usage + +```terraform +resource "aws_budgets_budget_action" "example" { + budget_name = aws_budgets_budget.example.name + action_type = "APPLY_IAM_POLICY" + approval_model = "AUTOMATIC" + notification_type = "ACTUAL" + execution_role_arn = aws_iam_role.example.arn + + action_threshold { + action_threshold_type = "ABSOLUTE_VALUE" + action_threshold_value = 100 + } + + definition { + iam_action_definition { + policy_arn = aws_iam_policy.example.arn + roles = [aws_iam_role.example.name] + } + } + + subscriber { + address = "example@example.example" + subscription_type = "EMAIL" + } +} + +resource "aws_iam_policy" "example" { + name = "example" + description = "My example policy" + + policy = < Date: Thu, 27 May 2021 22:13:03 +0300 Subject: [PATCH 0325/1208] changelog --- .changelog/19554.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19554.txt diff --git a/.changelog/19554.txt b/.changelog/19554.txt new file mode 100644 index 000000000000..9696311995f0 --- /dev/null +++ b/.changelog/19554.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_budgets_budget_action +``` From 3978294583b5cdc159886be39c7ae7e0eb27ebf8 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 27 May 2021 22:15:30 +0300 Subject: [PATCH 0326/1208] fmt --- aws/resource_aws_budgets_budget_action_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_budgets_budget_action_test.go b/aws/resource_aws_budgets_budget_action_test.go index 820b67218a5f..e8ee74e09492 100644 --- a/aws/resource_aws_budgets_budget_action_test.go +++ b/aws/resource_aws_budgets_budget_action_test.go @@ -241,19 +241,19 @@ resource "aws_budgets_budget_action" "test" { action_threshold { action_threshold_type = "ABSOLUTE_VALUE" - action_threshold_value = 100 + action_threshold_value = 100 } definition { iam_action_definition { - policy_arn = aws_iam_policy.test.arn - roles = [aws_iam_role.test.name] - } + policy_arn = aws_iam_policy.test.arn + roles = [aws_iam_role.test.name] + } } subscriber { address = "test@test.test" - subscription_type = "EMAIL" + subscription_type = "EMAIL" } } `, rName) From a372d27142ca0c08b81907b6a7ed8510f64b0654 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 27 May 2021 22:32:19 +0300 Subject: [PATCH 0327/1208] docs fmt --- website/docs/r/budgets_budget_action.html.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/website/docs/r/budgets_budget_action.html.markdown b/website/docs/r/budgets_budget_action.html.markdown index ef0255d11282..0bd4b8f3ad50 100644 --- a/website/docs/r/budgets_budget_action.html.markdown +++ b/website/docs/r/budgets_budget_action.html.markdown @@ -22,19 +22,19 @@ resource "aws_budgets_budget_action" "example" { action_threshold { action_threshold_type = "ABSOLUTE_VALUE" - action_threshold_value = 100 + action_threshold_value = 100 } definition { iam_action_definition { - policy_arn = aws_iam_policy.example.arn - roles = [aws_iam_role.example.name] - } + policy_arn = aws_iam_policy.example.arn + roles = [aws_iam_role.example.name] + } } subscriber { address = "example@example.example" - subscription_type = "EMAIL" + subscription_type = "EMAIL" } } From 879eaeb4fcbb03e1cff26b18708a65b0c4d2308d Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Tue, 8 Jun 2021 16:32:50 +0300 Subject: [PATCH 0328/1208] Update website/docs/r/budgets_budget_action.html.markdown Co-authored-by: Kit Ewbank --- website/docs/r/budgets_budget_action.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/budgets_budget_action.html.markdown b/website/docs/r/budgets_budget_action.html.markdown index 0bd4b8f3ad50..ea00d90522f3 100644 --- a/website/docs/r/budgets_budget_action.html.markdown +++ b/website/docs/r/budgets_budget_action.html.markdown @@ -3,7 +3,7 @@ subcategory: "Budgets" layout: "aws" page_title: "AWS: aws_budgets_budget_action" description: |- - Provides a budgets budget action resource. + Provides a budget action resource. --- # Resource: aws_budgets_budget_action From fcdbbc419fd33bebacf857535d3361139af8df70 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Tue, 8 Jun 2021 16:33:04 +0300 Subject: [PATCH 0329/1208] Update website/docs/r/budgets_budget_action.html.markdown Co-authored-by: Kit Ewbank --- website/docs/r/budgets_budget_action.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/budgets_budget_action.html.markdown b/website/docs/r/budgets_budget_action.html.markdown index ea00d90522f3..e3a3be012bc4 100644 --- a/website/docs/r/budgets_budget_action.html.markdown +++ b/website/docs/r/budgets_budget_action.html.markdown @@ -8,7 +8,7 @@ description: |- # Resource: aws_budgets_budget_action -Provides a budgets budget resource. Budgets use the cost visualisation provided by Cost Explorer to show you the status of your budgets, to provide forecasts of your estimated costs, and to track your AWS usage, including your free tier usage. +Provides a budget action resource. Budget actions are cost savings controls that run either automatically on your behalf or by using a workflow approval process. ## Example Usage From cf696decbc907f2d3666fce3295ae627febd04f5 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 8 Jun 2021 21:49:57 +0300 Subject: [PATCH 0330/1208] add waiters --- aws/internal/service/budgets/waiter/status.go | 24 +++++++++++++ aws/internal/service/budgets/waiter/waiter.go | 36 +++++++++++++++++++ aws/resource_aws_budgets_budget_action.go | 11 +++++- 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 aws/internal/service/budgets/waiter/status.go create mode 100644 aws/internal/service/budgets/waiter/waiter.go diff --git a/aws/internal/service/budgets/waiter/status.go b/aws/internal/service/budgets/waiter/status.go new file mode 100644 index 000000000000..46f79acfb233 --- /dev/null +++ b/aws/internal/service/budgets/waiter/status.go @@ -0,0 +1,24 @@ +package waiter + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/budgets" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/budgets/finder" +) + +func ActionStatus(conn *budgets.Budgets, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + out, err := finder.ActionById(conn, id) + if err != nil { + if tfawserr.ErrCodeEquals(err, budgets.ErrCodeNotFoundException) { + return nil, "", nil + } + return nil, "", err + } + + action := out.Action + return action, aws.StringValue(action.Status), err + } +} diff --git a/aws/internal/service/budgets/waiter/waiter.go b/aws/internal/service/budgets/waiter/waiter.go new file mode 100644 index 000000000000..532ca43667a8 --- /dev/null +++ b/aws/internal/service/budgets/waiter/waiter.go @@ -0,0 +1,36 @@ +package waiter + +import ( + "time" + + "github.com/aws/aws-sdk-go/service/budgets" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + ActionAvailableTimeout = 2 * time.Minute +) + +func ActionAvailable(conn *budgets.Budgets, id string) (*budgets.Action, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + budgets.ActionStatusExecutionInProgress, + budgets.ActionStatusPending, + }, + Target: []string{ + budgets.ActionStatusStandby, + budgets.ActionStatusExecutionSuccess, + budgets.ActionStatusExecutionFailure, + }, + Refresh: ActionStatus(conn, id), + Timeout: ActionAvailableTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*budgets.Action); ok { + return v, err + } + + return nil, err +} diff --git a/aws/resource_aws_budgets_budget_action.go b/aws/resource_aws_budgets_budget_action.go index 744ec4992e6d..2cceb30a7aef 100644 --- a/aws/resource_aws_budgets_budget_action.go +++ b/aws/resource_aws_budgets_budget_action.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" tfbudgets "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/budgets" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/budgets/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/budgets/waiter" ) func resourceAwsBudgetsBudgetAction() *schema.Resource { @@ -230,11 +231,15 @@ func resourceAwsBudgetsBudgetActionCreate(d *schema.ResourceData, meta interface return output, err }) if err != nil { - return fmt.Errorf("create budget failed: %v", err) + return fmt.Errorf("create Budget Action failed: %v", err) } d.SetId(fmt.Sprintf("%s:%s:%s", aws.StringValue(output.AccountId), aws.StringValue(output.ActionId), aws.StringValue(output.BudgetName))) + if _, err := waiter.ActionAvailable(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Budget Action (%s) creation: %w", d.Id(), err) + } + return resourceAwsBudgetsBudgetActionRead(d, meta) } @@ -334,6 +339,10 @@ func resourceAwsBudgetsBudgetActionUpdate(d *schema.ResourceData, meta interface return fmt.Errorf("Updating Budget Action failed: %w", err) } + if _, err := waiter.ActionAvailable(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Budget Action (%s) update: %w", d.Id(), err) + } + return resourceAwsBudgetsBudgetActionRead(d, meta) } From 67fa8a8b6e77718f4ded145e7d075d853a28e685 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 8 Jun 2021 16:16:33 -0700 Subject: [PATCH 0331/1208] Handles embedded error in data source --- ..._source_aws_servicequotas_service_quota.go | 10 +- ...ce_aws_servicequotas_service_quota_test.go | 92 +++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/aws/data_source_aws_servicequotas_service_quota.go b/aws/data_source_aws_servicequotas_service_quota.go index eb621f04b312..6f8b011e3c38 100644 --- a/aws/data_source_aws_servicequotas_service_quota.go +++ b/aws/data_source_aws_servicequotas_service_quota.go @@ -105,13 +105,21 @@ func dataSourceAwsServiceQuotasServiceQuotaRead(d *schema.ResourceData, meta int return fmt.Errorf("error getting Service (%s) Quota (%s): %w", serviceCode, quotaCode, err) } - if output == nil { + if output == nil || output.Quota == nil { return fmt.Errorf("error getting Service (%s) Quota (%s): empty result", serviceCode, quotaCode) } serviceQuota = output.Quota } + if serviceQuota.ErrorReason != nil { + return fmt.Errorf("error getting Service (%s) Quota (%s): %s: %s", serviceCode, quotaCode, aws.StringValue(serviceQuota.ErrorReason.ErrorCode), aws.StringValue(serviceQuota.ErrorReason.ErrorMessage)) + } + + if serviceQuota.Value == nil { + return fmt.Errorf("error getting Service (%s) Quota (%s): empty value", serviceCode, quotaCode) + } + input := &servicequotas.GetAWSDefaultServiceQuotaInput{ QuotaCode: serviceQuota.QuotaCode, ServiceCode: serviceQuota.ServiceCode, diff --git a/aws/data_source_aws_servicequotas_service_quota_test.go b/aws/data_source_aws_servicequotas_service_quota_test.go index d1fa2ad2d217..ece9f2ee6198 100644 --- a/aws/data_source_aws_servicequotas_service_quota_test.go +++ b/aws/data_source_aws_servicequotas_service_quota_test.go @@ -35,6 +35,21 @@ func TestAccAwsServiceQuotasServiceQuotaDataSource_QuotaCode(t *testing.T) { }) } +func TestAccAwsServiceQuotasServiceQuotaDataSource_PermissionError_QuotaCode(t *testing.T) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSServiceQuotas(t); testAccAssumeRoleARNPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicequotas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccAwsServiceQuotasServiceQuotaDataSourceConfig_PermissionError_QuotaCode("elasticloadbalancing", "L-53DA6B97"), + ExpectError: regexp.MustCompile(`DEPENDENCY_ACCESS_DENIED_ERROR`), + }, + }, + }) +} + func TestAccAwsServiceQuotasServiceQuotaDataSource_QuotaName(t *testing.T) { dataSourceName := "data.aws_servicequotas_service_quota.test" @@ -61,6 +76,21 @@ func TestAccAwsServiceQuotasServiceQuotaDataSource_QuotaName(t *testing.T) { }) } +func TestAccAwsServiceQuotasServiceQuotaDataSource_PermissionError_QuotaName(t *testing.T) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSServiceQuotas(t); testAccAssumeRoleARNPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicequotas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccAwsServiceQuotasServiceQuotaDataSourceConfig_PermissionError_QuotaName("elasticloadbalancing", "Application Load Balancers per Region"), + ExpectError: regexp.MustCompile(`DEPENDENCY_ACCESS_DENIED_ERROR`), + }, + }, + }) +} + func testAccAwsServiceQuotasServiceQuotaDataSourceConfigQuotaCode(serviceCode, quotaCode string) string { return fmt.Sprintf(` data "aws_servicequotas_service_quota" "test" { @@ -70,6 +100,37 @@ data "aws_servicequotas_service_quota" "test" { `, quotaCode, serviceCode) } +func testAccAwsServiceQuotasServiceQuotaDataSourceConfig_PermissionError_QuotaCode(serviceCode, quotaCode string) string { + policy := `{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "servicequotas:GetServiceQuota" + ], + "Resource": "*" + }, + { + "Effect": "Deny", + "Action": [ + "elasticloadbalancing:*" + ], + "Resource": "*" + } + ] +}` + + return composeConfig( + testAccProviderConfigAssumeRolePolicy(policy), + fmt.Sprintf(` +data "aws_servicequotas_service_quota" "test" { + service_code = %[1]q + quota_code = %[2]q +} +`, serviceCode, quotaCode)) +} + func testAccAwsServiceQuotasServiceQuotaDataSourceConfigQuotaName(serviceCode, quotaName string) string { return fmt.Sprintf(` data "aws_servicequotas_service_quota" "test" { @@ -78,3 +139,34 @@ data "aws_servicequotas_service_quota" "test" { } `, quotaName, serviceCode) } + +func testAccAwsServiceQuotasServiceQuotaDataSourceConfig_PermissionError_QuotaName(serviceCode, quotaName string) string { + policy := `{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "servicequotas:ListServiceQuotas" + ], + "Resource": "*" + }, + { + "Effect": "Deny", + "Action": [ + "elasticloadbalancing:*" + ], + "Resource": "*" + } + ] +}` + + return composeConfig( + testAccProviderConfigAssumeRolePolicy(policy), + fmt.Sprintf(` +data "aws_servicequotas_service_quota" "test" { + service_code = %[1]q + quota_name = %[2]q +} +`, serviceCode, quotaName)) +} From 66e9f48787edf59390690cf0fb456677c154b244 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 8 Jun 2021 16:16:54 -0700 Subject: [PATCH 0332/1208] Handles embedded error in resource --- ...esource_aws_servicequotas_service_quota.go | 20 +++++++- ...ce_aws_servicequotas_service_quota_test.go | 48 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_servicequotas_service_quota.go b/aws/resource_aws_servicequotas_service_quota.go index bc9ed142a7da..9a5f181c0326 100644 --- a/aws/resource_aws_servicequotas_service_quota.go +++ b/aws/resource_aws_servicequotas_service_quota.go @@ -99,10 +99,18 @@ func resourceAwsServiceQuotasServiceQuotaCreate(d *schema.ResourceData, meta int return fmt.Errorf("error getting Service Quotas Service Quota (%s): %s", d.Id(), err) } - if output == nil { + if output == nil || output.Quota == nil { return fmt.Errorf("error getting Service Quotas Service Quota (%s): empty result", d.Id()) } + if output.Quota.ErrorReason != nil { + return fmt.Errorf("error getting Service Quotas Service Quota (%s): %s: %s", d.Id(), aws.StringValue(output.Quota.ErrorReason.ErrorCode), aws.StringValue(output.Quota.ErrorReason.ErrorMessage)) + } + + if output.Quota.Value == nil { + return fmt.Errorf("error getting Service Quotas Service Quota (%s): empty value", d.Id()) + } + if value > aws.Float64Value(output.Quota.Value) { input := &servicequotas.RequestServiceQuotaIncreaseInput{ DesiredValue: aws.Float64(value), @@ -152,10 +160,18 @@ func resourceAwsServiceQuotasServiceQuotaRead(d *schema.ResourceData, meta inter return fmt.Errorf("error getting Service Quotas Service Quota (%s): %s", d.Id(), err) } - if output == nil { + if output == nil || output.Quota == nil { return fmt.Errorf("error getting Service Quotas Service Quota (%s): empty result", d.Id()) } + if output.Quota.ErrorReason != nil { + return fmt.Errorf("error getting Service Quotas Service Quota (%s): %s: %s", d.Id(), aws.StringValue(output.Quota.ErrorReason.ErrorCode), aws.StringValue(output.Quota.ErrorReason.ErrorMessage)) + } + + if output.Quota.Value == nil { + return fmt.Errorf("error getting Service Quotas Service Quota (%s): empty value", d.Id()) + } + defaultInput := &servicequotas.GetAWSDefaultServiceQuotaInput{ QuotaCode: aws.String(quotaCode), ServiceCode: aws.String(serviceCode), diff --git a/aws/resource_aws_servicequotas_service_quota_test.go b/aws/resource_aws_servicequotas_service_quota_test.go index e0737b3cc9e8..ba9c1e0c149c 100644 --- a/aws/resource_aws_servicequotas_service_quota_test.go +++ b/aws/resource_aws_servicequotas_service_quota_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "os" + "regexp" "testing" "github.com/aws/aws-sdk-go/service/servicequotas" @@ -138,6 +139,21 @@ func TestAccAwsServiceQuotasServiceQuota_Value_IncreaseOnUpdate(t *testing.T) { }) } +func TestAccAwsServiceQuotasServiceQuota_PermissionError(t *testing.T) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSServiceQuotas(t); testAccAssumeRoleARNPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicequotas.EndpointsID), + Providers: testAccProviders, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccAwsServiceQuotasServiceQuotaConfig_PermissionError("elasticloadbalancing", "L-53DA6B97"), + ExpectError: regexp.MustCompile(`DEPENDENCY_ACCESS_DENIED_ERROR`), + }, + }, + }) +} + func testAccPreCheckAWSServiceQuotas(t *testing.T) { conn := testAccProvider.Meta().(*AWSClient).servicequotasconn @@ -178,3 +194,35 @@ resource "aws_servicequotas_service_quota" "test" { } `, quotaCode, serviceCode, value) } + +func testAccAwsServiceQuotasServiceQuotaConfig_PermissionError(serviceCode, quotaCode string) string { + policy := `{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "servicequotas:GetServiceQuota" + ], + "Resource": "*" + }, + { + "Effect": "Deny", + "Action": [ + "elasticloadbalancing:*" + ], + "Resource": "*" + } + ] +}` + + return composeConfig( + testAccProviderConfigAssumeRolePolicy(policy), + fmt.Sprintf(` +resource "aws_servicequotas_service_quota" "test" { + service_code = %[1]q + quota_code = %[2]q + value = 1 +} +`, serviceCode, quotaCode)) +} From 402e96a1a192e7c2fe22cb00d126b2ca86179c88 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 8 Jun 2021 16:34:20 -0700 Subject: [PATCH 0333/1208] Adds CHANGELOG entry --- .changelog/19722.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/19722.txt diff --git a/.changelog/19722.txt b/.changelog/19722.txt new file mode 100644 index 000000000000..c92a5a36e587 --- /dev/null +++ b/.changelog/19722.txt @@ -0,0 +1,7 @@ +```release-note:bug +data-source/aws_servicequotas_service_quota: Correctly handle errors embedded in API struct +``` + +```release-note:bug +resource/aws_servicequotas_service_quota: Correctly handle errors embedded in API struct +``` From 08bc5097f8c3b3c8307beda6082c9d94ebd60a2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 05:42:46 +0000 Subject: [PATCH 0334/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.56 to 1.38.57 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.56 to 1.38.57. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.56...v1.38.57) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 13cd084bc81e..7d9462a24f76 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.56 + github.com/aws/aws-sdk-go v1.38.57 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index ccc0ffed975f..5d5aec62196f 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.56 h1:JI5bnuDfjVLgnBaDHeZO5btxGbYCQ5QA3P0maYtwPQw= -github.com/aws/aws-sdk-go v1.38.56/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.57 h1:Jo6uOnWNbj4jL/8t/XUrHOKm1J6pPcYFhGzda20UcUk= +github.com/aws/aws-sdk-go v1.38.57/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 7c8596e269e465dd340b83df7074a4f3d7cdd3cf Mon Sep 17 00:00:00 2001 From: Jon Whitcraft Date: Wed, 9 Jun 2021 09:18:30 -0400 Subject: [PATCH 0335/1208] Mark `resource_label` as required in documentation This is due to the validation in v1 of the go-sdk that expects the value to be set for the api call. Signed-off-by: Jon Whitcraft --- website/docs/r/autoscaling_policy.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/autoscaling_policy.html.markdown b/website/docs/r/autoscaling_policy.html.markdown index b28b4bf0603c..04c9c02e9be5 100644 --- a/website/docs/r/autoscaling_policy.html.markdown +++ b/website/docs/r/autoscaling_policy.html.markdown @@ -183,21 +183,21 @@ The following arguments are supported: The following arguments are supported: * `predefined_metric_type` - (Required) The metric type. Valid values are `ASGTotalCPUUtilization`, `ASGTotalNetworkIn`, `ASGTotalNetworkOut`, or `ALBTargetGroupRequestCount`. -* `resource_label` - (Optional) A label that uniquely identifies a specific Application Load Balancer target group from which to determine the request count served by your Auto Scaling group. +* `resource_label` - (Required) A label that uniquely identifies a specific Application Load Balancer target group from which to determine the request count served by your Auto Scaling group. ##### predefined_metric_pair_specification The following arguments are supported: * `predefined_metric_type` - (Required) Indicates which metrics to use. There are two different types of metrics for each metric type: one is a load metric and one is a scaling metric. For example, if the metric type is `ASGCPUUtilization`, the Auto Scaling group's total CPU metric is used as the load metric, and the average CPU metric is used for the scaling metric. Valid values are `ASGCPUUtilization`, `ASGNetworkIn`, `ASGNetworkOut`, or `ALBRequestCount`. -* `resource_label` - (Optional) A label that uniquely identifies a specific Application Load Balancer target group from which to determine the request count served by your Auto Scaling group. +* `resource_label` - (Required) A label that uniquely identifies a specific Application Load Balancer target group from which to determine the request count served by your Auto Scaling group. ##### predefined_scaling_metric_specification The following arguments are supported: * `predefined_metric_type` - (Required) Describes a scaling metric for a predictive scaling policy. Valid values are `ASGAverageCPUUtilization`, `ASGAverageNetworkIn`, `ASGAverageNetworkOut`, or `ALBRequestCountPerTarget`. -* `resource_label` - (Optional) A label that uniquely identifies a specific Application Load Balancer target group from which to determine the request count served by your Auto Scaling group. +* `resource_label` - (Required) A label that uniquely identifies a specific Application Load Balancer target group from which to determine the request count served by your Auto Scaling group. ## Attributes Reference From 44f8b96159328fe3eca9c968a66cc15b3317c08a Mon Sep 17 00:00:00 2001 From: kumadee Date: Wed, 9 Jun 2021 16:47:50 +0200 Subject: [PATCH 0336/1208] website doc lint fix --- website/docs/d/globalaccelerator_accelerator.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/globalaccelerator_accelerator.markdown b/website/docs/d/globalaccelerator_accelerator.markdown index 9e94f02e78cd..071550500c18 100644 --- a/website/docs/d/globalaccelerator_accelerator.markdown +++ b/website/docs/d/globalaccelerator_accelerator.markdown @@ -24,7 +24,7 @@ variable "accelerator_name" { } data "aws_globalaccelerator_accelerator" "example" { - arn = var.accelerator_arn + arn = var.accelerator_arn name = var.accelerator_name } ``` From 5eac9e4d17965d5568249eb19489de86db3a5d73 Mon Sep 17 00:00:00 2001 From: kumadee Date: Wed, 9 Jun 2021 16:52:33 +0200 Subject: [PATCH 0337/1208] terrafmt fix remove extra whitespaces --- aws/data_source_aws_globalaccelerator_accelerator_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/data_source_aws_globalaccelerator_accelerator_test.go b/aws/data_source_aws_globalaccelerator_accelerator_test.go index bdc947d4fcaa..3730288079db 100644 --- a/aws/data_source_aws_globalaccelerator_accelerator_test.go +++ b/aws/data_source_aws_globalaccelerator_accelerator_test.go @@ -61,11 +61,11 @@ func testAccAWSGlobalAcceleratorAcceleratorConfigWithDataSource(rName string) st return fmt.Sprintf(` resource "aws_globalaccelerator_accelerator" "test" { name = %[1]q - attributes { + attributes { flow_logs_enabled = false flow_logs_s3_bucket = "" flow_logs_s3_prefix = "flow-logs/globalaccelerator/" - } + } } data "aws_globalaccelerator_accelerator" "test_by_arn" { From 1c4b31ad1f60089fd8ce8e2e29fa77cae1944a0e Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Wed, 9 Jun 2021 10:52:38 -0400 Subject: [PATCH 0338/1208] Migrate from GitHub HashiBot pull_request_size_labeler behavior to GitHub Actions (#19729) --- .github/workflows/pull_requests.yml | 18 ++++++++++++++++++ .hashibot.hcl | 29 ----------------------------- 2 files changed, 18 insertions(+), 29 deletions(-) delete mode 100644 .hashibot.hcl diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index fbdc6f65c560..539731bb4927 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -22,6 +22,24 @@ jobs: with: configuration-path: .github/labeler-pr-needs-triage.yml repo-token: ${{ secrets.GITHUB_TOKEN }} + SizeLabeler: + runs-on: ubuntu-latest + steps: + # See also: https://github.com/CodelyTV/pr-size-labeler/pull/26 + - name: Apply Size Label + uses: bflad/pr-size-labeler@7df62b12a176513631973abfe151d2b6213c3f12 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + xs_label: 'size/XS' + xs_max_size: '30' + s_label: 'size/S' + s_max_size: '60' + m_label: 'size/M' + m_max_size: '150' + l_label: 'size/L' + l_max_size: '300' + xl_label: 'size/XL' + message_if_xl: '' PullRequestComments: runs-on: ubuntu-latest steps: diff --git a/.hashibot.hcl b/.hashibot.hcl deleted file mode 100644 index 964ea520bf15..000000000000 --- a/.hashibot.hcl +++ /dev/null @@ -1,29 +0,0 @@ -behavior "pull_request_size_labeler" "size" { - label_prefix = "size/" - label_map = { - "size/XS" = { - from = 0 - to = 30 - } - "size/S" = { - from = 31 - to = 60 - } - "size/M" = { - from = 61 - to = 150 - } - "size/L" = { - from = 151 - to = 300 - } - "size/XL" = { - from = 301 - to = 1000 - } - "size/XXL" = { - from = 1001 - to = 0 - } - } -} From eddcaff06220d893481362ce834ae9a321882763 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 9 Jun 2021 14:54:45 +0000 Subject: [PATCH 0339/1208] Update CHANGELOG.md for #19729 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 926472cb7a07..a487d1585307 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ENHANCEMENTS: * resource/aws_cognito_user_pool: Add `custom_domain`, `domain`, and `estimated_number_of_users` attributes ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) * resource/aws_cognito_user_pool: Add `custom_email_sender`, `custom_sms_sender`, and `kms_key_id` to `lambda_config` ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) * resource/aws_cognito_user_pool: Add plan time validation for `name` ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) +* resource/aws_cognito_user_pool_client: Add plan time validation for `id_token_validity` and `access_token_validity`. ([#19702](https://github.com/hashicorp/terraform-provider-aws/issues/19702)) * resource/aws_default_vpc_dhcp_options: Add `owner_id` argument. ([#19656](https://github.com/hashicorp/terraform-provider-aws/issues/19656)) * resource/aws_ecs_task_definition: Add plan time validation for `family` and `requires_compatibilities`. ([#19670](https://github.com/hashicorp/terraform-provider-aws/issues/19670)) * resource/aws_ecs_task_definition: Add support for `ephemeral_storage`. ([#19694](https://github.com/hashicorp/terraform-provider-aws/issues/19694)) @@ -21,6 +22,7 @@ BUG FIXES: * data-source/aws_acmpca_certificate_authority: Fix `error setting tags` ([#19681](https://github.com/hashicorp/terraform-provider-aws/issues/19681)) * resource/aws_cloudwatch_event_target: Increase the maximum allowed value for the `input_transformer` `input_paths` argument to 100 ([#19703](https://github.com/hashicorp/terraform-provider-aws/issues/19703)) * resource/aws_cloudwatch_metric_alarm: Allow extended statistics in the `stat` argument of the `metric` configuration block ([#19668](https://github.com/hashicorp/terraform-provider-aws/issues/19668)) +* resource/aws_cognito_user_pool_client: Fix plan time validation for `refresh_token_validity` ([#19702](https://github.com/hashicorp/terraform-provider-aws/issues/19702)) * resource/aws_lambda_function: Prevents perpetual diff in `vpc_config` ([#17610](https://github.com/hashicorp/terraform-provider-aws/issues/17610)) * resource/aws_sqs_queue: Allow `visibility_timeout_seconds` to be `0` when creating queue ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) * resource/aws_sqs_queue: Ensure that queue attributes propagate completely during Create and Update ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) From ec7bc20bf1d76bde4038c6625273946412c46a35 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 9 Jun 2021 11:04:49 -0400 Subject: [PATCH 0340/1208] r/aws_cur_report_definition: Add test sweeper. --- aws/resource_aws_cur_report_definition.go | 18 ++++--- ...resource_aws_cur_report_definition_test.go | 52 +++++++++++++++++++ 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_cur_report_definition.go b/aws/resource_aws_cur_report_definition.go index 1a4ca66cbefc..5955cb3f790b 100644 --- a/aws/resource_aws_cur_report_definition.go +++ b/aws/resource_aws_cur_report_definition.go @@ -147,10 +147,13 @@ func resourceAwsCurReportDefinitionCreate(d *schema.ResourceData, meta interface log.Printf("[DEBUG] Creating AWS Cost and Usage Report Definition : %v", reportDefinitionInput) _, err = conn.PutReportDefinition(reportDefinitionInput) + if err != nil { - return fmt.Errorf("Error creating AWS Cost And Usage Report Definition: %w", err) + return fmt.Errorf("error creating Cost And Usage Report Definition (%s): %w", reportName, err) } + d.SetId(reportName) + return resourceAwsCurReportDefinitionRead(d, meta) } @@ -160,14 +163,14 @@ func resourceAwsCurReportDefinitionRead(d *schema.ResourceData, meta interface{} reportDefinition, err := finder.ReportDefinitionByName(conn, d.Id()) if err != nil { - return fmt.Errorf("error reading Report definition (%s): %w", d.Id(), err) + return fmt.Errorf("error reading Cost And Usage Report Definition (%s): %w", d.Id(), err) } if reportDefinition == nil { if d.IsNewResource() { - return fmt.Errorf("error reading Report definition (%s): not found after creation", d.Id()) + return fmt.Errorf("error reading Cost And Usage Report Definition (%s): not found after creation", d.Id()) } - log.Printf("[WARN] Report definition (%s) not found, removing from state", d.Id()) + log.Printf("[WARN] Cost And Usage Report Definition (%s) not found, removing from state", d.Id()) d.SetId("") return nil } @@ -251,21 +254,24 @@ func resourceAwsCurReportDefinitionUpdate(d *schema.ResourceData, meta interface } _, err = conn.ModifyReportDefinition(reportDefinitionInput) + if err != nil { - return fmt.Errorf("Error updating AWS Cost And Usage Report Definition: %w", err) + return fmt.Errorf("error updating Cost And Usage Report Definition (%s): %w", d.Id(), err) } + return resourceAwsCurReportDefinitionRead(d, meta) } func resourceAwsCurReportDefinitionDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).costandusagereportconn + log.Printf("[DEBUG] Deleting Cost And Usage Report Definition (%s)", d.Id()) _, err := conn.DeleteReportDefinition(&cur.DeleteReportDefinitionInput{ ReportName: aws.String(d.Id()), }) if err != nil { - return fmt.Errorf("error deleting Report Definition (%s): %w", d.Id(), err) + return fmt.Errorf("error deleting Cost And Usage Report Definition (%s): %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_cur_report_definition_test.go b/aws/resource_aws_cur_report_definition_test.go index 566c4206a247..34a55f5e7f17 100644 --- a/aws/resource_aws_cur_report_definition_test.go +++ b/aws/resource_aws_cur_report_definition_test.go @@ -2,16 +2,68 @@ package aws import ( "fmt" + "log" "strings" "testing" + "github.com/aws/aws-sdk-go/aws" cur "github.com/aws/aws-sdk-go/service/costandusagereportservice" + multierror "github.com/hashicorp/go-multierror" "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" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/costandusagereportservice/finder" ) +func init() { + resource.AddTestSweepers("aws_cur_report_definition", &resource.Sweeper{ + Name: "aws_cur_report_definition", + F: testSweepCurReportDefinitions, + }) +} + +func testSweepCurReportDefinitions(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).costandusagereportconn + input := &cur.DescribeReportDefinitionsInput{} + var sweeperErrs *multierror.Error + + err = conn.DescribeReportDefinitionsPages(input, func(page *cur.DescribeReportDefinitionsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, reportDefinition := range page.ReportDefinitions { + r := resourceAwsCurReportDefinition() + d := r.Data(nil) + d.SetId(aws.StringValue(reportDefinition.ReportName)) + err = r.Delete(d, client) + + if err != nil { + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) + continue + } + } + + return !lastPage + }) + + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Cost And Usage Report Definitions sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + } + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Cost And Usage Report Definitions: %w", err)) + } + + return sweeperErrs.ErrorOrNil() +} + func TestAccAwsCurReportDefinition_basic(t *testing.T) { resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" From 31b61468c6946bc871c33978c94b00d4fcb07a02 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 9 Jun 2021 11:12:26 -0400 Subject: [PATCH 0341/1208] Serialize CUR tests to avoid API rate-limiting. --- ...resource_aws_cur_report_definition_test.go | 14 ++++---- aws/resource_aws_cur_test.go | 35 +++++++++++++++++++ 2 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 aws/resource_aws_cur_test.go diff --git a/aws/resource_aws_cur_report_definition_test.go b/aws/resource_aws_cur_report_definition_test.go index 34a55f5e7f17..ec78f759522c 100644 --- a/aws/resource_aws_cur_report_definition_test.go +++ b/aws/resource_aws_cur_report_definition_test.go @@ -64,7 +64,7 @@ func testSweepCurReportDefinitions(region string) error { return sweeperErrs.ErrorOrNil() } -func TestAccAwsCurReportDefinition_basic(t *testing.T) { +func testAccAwsCurReportDefinition_basic(t *testing.T) { resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -117,7 +117,7 @@ func TestAccAwsCurReportDefinition_basic(t *testing.T) { }) } -func TestAccAwsCurReportDefinition_textOrCsv(t *testing.T) { +func testAccAwsCurReportDefinition_textOrCsv(t *testing.T) { resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -161,7 +161,7 @@ func TestAccAwsCurReportDefinition_textOrCsv(t *testing.T) { }) } -func TestAccAwsCurReportDefinition_parquet(t *testing.T) { +func testAccAwsCurReportDefinition_parquet(t *testing.T) { resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -204,7 +204,7 @@ func TestAccAwsCurReportDefinition_parquet(t *testing.T) { }) } -func TestAccAwsCurReportDefinition_athena(t *testing.T) { +func testAccAwsCurReportDefinition_athena(t *testing.T) { resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -248,7 +248,7 @@ func TestAccAwsCurReportDefinition_athena(t *testing.T) { }) } -func TestAccAwsCurReportDefinition_refresh(t *testing.T) { +func testAccAwsCurReportDefinition_refresh(t *testing.T) { resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -292,7 +292,7 @@ func TestAccAwsCurReportDefinition_refresh(t *testing.T) { }) } -func TestAccAwsCurReportDefinition_overwrite(t *testing.T) { +func testAccAwsCurReportDefinition_overwrite(t *testing.T) { resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -336,7 +336,7 @@ func TestAccAwsCurReportDefinition_overwrite(t *testing.T) { }) } -func TestAccAwsCurReportDefinition_disappears(t *testing.T) { +func testAccAwsCurReportDefinition_disappears(t *testing.T) { resourceName := "aws_cur_report_definition.test" reportName := acctest.RandomWithPrefix("tf_acc_test") bucketName := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt()) diff --git a/aws/resource_aws_cur_test.go b/aws/resource_aws_cur_test.go new file mode 100644 index 000000000000..54b0765b3ed0 --- /dev/null +++ b/aws/resource_aws_cur_test.go @@ -0,0 +1,35 @@ +package aws + +import ( + "testing" + "time" +) + +// Serialize to limit API rate-limit exceeded errors. +func TestAccAwsCur_serial(t *testing.T) { + testCases := map[string]map[string]func(t *testing.T){ + "ReportDefinition": { + "basic": testAccAwsCurReportDefinition_basic, + "disappears": testAccAwsCurReportDefinition_disappears, + "textOrCsv": testAccAwsCurReportDefinition_textOrCsv, + "parquet": testAccAwsCurReportDefinition_parquet, + "athena": testAccAwsCurReportDefinition_athena, + "refresh": testAccAwsCurReportDefinition_refresh, + "overwrite": testAccAwsCurReportDefinition_overwrite, + }, + } + + for group, m := range testCases { + m := m + t.Run(group, func(t *testing.T) { + for name, tc := range m { + tc := tc + t.Run(name, func(t *testing.T) { + tc(t) + // Explicitly sleep between tests. + time.Sleep(5 * time.Second) + }) + } + }) + } +} From 2fe8b0d0adb087c86ce8fc5d199bb8457c1fec20 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 9 Jun 2021 11:24:58 -0400 Subject: [PATCH 0342/1208] d/aws_globalaccelerator_accelerator: Add acceptance test PreCheck for service availability. --- aws/data_source_aws_globalaccelerator_accelerator_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/data_source_aws_globalaccelerator_accelerator_test.go b/aws/data_source_aws_globalaccelerator_accelerator_test.go index 3730288079db..b9aa18277ab9 100644 --- a/aws/data_source_aws_globalaccelerator_accelerator_test.go +++ b/aws/data_source_aws_globalaccelerator_accelerator_test.go @@ -16,7 +16,7 @@ func TestAccAWSDataGlobalAcceleratorAccelerator_basic(t *testing.T) { dataSourceName2 := "data.aws_globalaccelerator_accelerator.test_by_name" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckGlobalAccelerator(t) }, ErrorCheck: testAccErrorCheck(t, globalaccelerator.EndpointsID), Providers: testAccProviders, Steps: []resource.TestStep{ From d1e11f6c3cda7ee2a25ac9427d386f0ed8795b2a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 9 Jun 2021 11:37:32 -0400 Subject: [PATCH 0343/1208] Modify file extension '.markdown' -> '.html.markdown' for Global Accelerator pages. --- ...rator.markdown => globalaccelerator_accelerator.html.markdown} | 0 ...rator.markdown => globalaccelerator_accelerator.html.markdown} | 0 ...listener.markdown => globalaccelerator_listener.html.markdown} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename website/docs/d/{globalaccelerator_accelerator.markdown => globalaccelerator_accelerator.html.markdown} (100%) rename website/docs/r/{globalaccelerator_accelerator.markdown => globalaccelerator_accelerator.html.markdown} (100%) rename website/docs/r/{globalaccelerator_listener.markdown => globalaccelerator_listener.html.markdown} (100%) diff --git a/website/docs/d/globalaccelerator_accelerator.markdown b/website/docs/d/globalaccelerator_accelerator.html.markdown similarity index 100% rename from website/docs/d/globalaccelerator_accelerator.markdown rename to website/docs/d/globalaccelerator_accelerator.html.markdown diff --git a/website/docs/r/globalaccelerator_accelerator.markdown b/website/docs/r/globalaccelerator_accelerator.html.markdown similarity index 100% rename from website/docs/r/globalaccelerator_accelerator.markdown rename to website/docs/r/globalaccelerator_accelerator.html.markdown diff --git a/website/docs/r/globalaccelerator_listener.markdown b/website/docs/r/globalaccelerator_listener.html.markdown similarity index 100% rename from website/docs/r/globalaccelerator_listener.markdown rename to website/docs/r/globalaccelerator_listener.html.markdown From e316d5976c6cf4b29c2519a38db5be32f39ca295 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 9 Jun 2021 11:38:03 -0400 Subject: [PATCH 0344/1208] Tweak Global Accelerator accelerator data source documentation. --- website/docs/d/globalaccelerator_accelerator.html.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/d/globalaccelerator_accelerator.html.markdown b/website/docs/d/globalaccelerator_accelerator.html.markdown index 071550500c18..e7054ca2f28c 100644 --- a/website/docs/d/globalaccelerator_accelerator.html.markdown +++ b/website/docs/d/globalaccelerator_accelerator.html.markdown @@ -40,5 +40,6 @@ The following arguments are supported: ## Attributes Reference -See the [Globalaccelerator Accelerator Resource](/docs/providers/aws/r/globalaccelerator_accelerator.html) for details on the +website/docs/r/globalaccelerator_accelerator.markdown +See the [`aws_globalaccelerator_accelerator` resource](/docs/providers/aws/r/globalaccelerator_accelerator.html) for details on the returned attributes - they are identical. From a65d64ca3d0d68ee55893e9ed4c275ffd8bd1a19 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 9 Jun 2021 16:38:41 +0000 Subject: [PATCH 0345/1208] Update CHANGELOG.md for #19666 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a487d1585307..66da19df7d93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 3.45.0 (Unreleased) +FEATURES: + +* **New Data Source:** `aws_globalaccelerator_accelerator` ([#19647](https://github.com/hashicorp/terraform-provider-aws/issues/19647)) + ENHANCEMENTS: * data-source/aws_transfer_server: Add `domain` attribute. ([#19691](https://github.com/hashicorp/terraform-provider-aws/issues/19691)) @@ -20,6 +24,7 @@ ENHANCEMENTS: BUG FIXES: * data-source/aws_acmpca_certificate_authority: Fix `error setting tags` ([#19681](https://github.com/hashicorp/terraform-provider-aws/issues/19681)) +* resource/aws_batch_job_definition: Suppress differences for empty `linuxParameters.devices` and `linuxParameters.tmpfs` arrays in the `container_properties` argument ([#19666](https://github.com/hashicorp/terraform-provider-aws/issues/19666)) * resource/aws_cloudwatch_event_target: Increase the maximum allowed value for the `input_transformer` `input_paths` argument to 100 ([#19703](https://github.com/hashicorp/terraform-provider-aws/issues/19703)) * resource/aws_cloudwatch_metric_alarm: Allow extended statistics in the `stat` argument of the `metric` configuration block ([#19668](https://github.com/hashicorp/terraform-provider-aws/issues/19668)) * resource/aws_cognito_user_pool_client: Fix plan time validation for `refresh_token_validity` ([#19702](https://github.com/hashicorp/terraform-provider-aws/issues/19702)) From 4e3025a62a1017d1c246875c0b9bf6647f25ca55 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 9 Jun 2021 13:41:22 -0700 Subject: [PATCH 0346/1208] Adds documentation about global quotas --- website/docs/d/servicequotas_service.html.markdown | 2 ++ website/docs/d/servicequotas_service_quota.html.markdown | 2 ++ website/docs/r/servicequotas_service_quota.html.markdown | 2 ++ 3 files changed, 6 insertions(+) diff --git a/website/docs/d/servicequotas_service.html.markdown b/website/docs/d/servicequotas_service.html.markdown index a3d593d833e9..35be5f1974a5 100644 --- a/website/docs/d/servicequotas_service.html.markdown +++ b/website/docs/d/servicequotas_service.html.markdown @@ -10,6 +10,8 @@ description: |- Retrieve information about a Service Quotas Service. +~> **NOTE:** Global quotas apply to all AWS regions, but can only be accessed in `us-east-1` in the Commercial partition or `us-gov-west-1` in the GovCloud partition. In other regions, the AWS API will return the error `The request failed because the specified service does not exist.` + ## Example Usage ```terraform diff --git a/website/docs/d/servicequotas_service_quota.html.markdown b/website/docs/d/servicequotas_service_quota.html.markdown index a92ce39eebc1..c6b6a650794f 100644 --- a/website/docs/d/servicequotas_service_quota.html.markdown +++ b/website/docs/d/servicequotas_service_quota.html.markdown @@ -10,6 +10,8 @@ description: |- Retrieve information about a Service Quota. +~> **NOTE:** Global quotas apply to all AWS regions, but can only be accessed in `us-east-1` in the Commercial partition or `us-gov-west-1` in the GovCloud partition. In other regions, the AWS API will return the error `The request failed because the specified service does not exist.` + ## Example Usage ```terraform diff --git a/website/docs/r/servicequotas_service_quota.html.markdown b/website/docs/r/servicequotas_service_quota.html.markdown index 97208d1f13e2..0fd6627eb23d 100644 --- a/website/docs/r/servicequotas_service_quota.html.markdown +++ b/website/docs/r/servicequotas_service_quota.html.markdown @@ -10,6 +10,8 @@ description: |- Manages an individual Service Quota. +~> **NOTE:** Global quotas apply to all AWS regions, but can only be accessed in `us-east-1` in the Commercial partition or `us-gov-west-1` in the GovCloud partition. In other regions, the AWS API will return the error `The request failed because the specified service does not exist.` + ## Example Usage ```terraform From 0e46b175322ad1e682ed2375dd1212e011c8cf24 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 9 Jun 2021 13:56:33 -0700 Subject: [PATCH 0347/1208] Adds CHANGELOG entry --- .changelog/19677.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19677.txt diff --git a/.changelog/19677.txt b/.changelog/19677.txt new file mode 100644 index 000000000000..04feae802aff --- /dev/null +++ b/.changelog/19677.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_iot_topic_rule: Allow tags containing `@` character +``` From bc86f9f8cfe5dfbb229a22c5ae082ed9e6cd7cbf Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 9 Jun 2021 21:01:57 +0000 Subject: [PATCH 0348/1208] Update CHANGELOG.md for #19722 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66da19df7d93..dfdd8559de6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,11 +24,13 @@ ENHANCEMENTS: BUG FIXES: * data-source/aws_acmpca_certificate_authority: Fix `error setting tags` ([#19681](https://github.com/hashicorp/terraform-provider-aws/issues/19681)) +* data-source/aws_servicequotas_service_quota: Correctly handle errors embedded in API struct ([#19722](https://github.com/hashicorp/terraform-provider-aws/issues/19722)) * resource/aws_batch_job_definition: Suppress differences for empty `linuxParameters.devices` and `linuxParameters.tmpfs` arrays in the `container_properties` argument ([#19666](https://github.com/hashicorp/terraform-provider-aws/issues/19666)) * resource/aws_cloudwatch_event_target: Increase the maximum allowed value for the `input_transformer` `input_paths` argument to 100 ([#19703](https://github.com/hashicorp/terraform-provider-aws/issues/19703)) * resource/aws_cloudwatch_metric_alarm: Allow extended statistics in the `stat` argument of the `metric` configuration block ([#19668](https://github.com/hashicorp/terraform-provider-aws/issues/19668)) * resource/aws_cognito_user_pool_client: Fix plan time validation for `refresh_token_validity` ([#19702](https://github.com/hashicorp/terraform-provider-aws/issues/19702)) * resource/aws_lambda_function: Prevents perpetual diff in `vpc_config` ([#17610](https://github.com/hashicorp/terraform-provider-aws/issues/17610)) +* resource/aws_servicequotas_service_quota: Correctly handle errors embedded in API struct ([#19722](https://github.com/hashicorp/terraform-provider-aws/issues/19722)) * resource/aws_sqs_queue: Allow `visibility_timeout_seconds` to be `0` when creating queue ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) * resource/aws_sqs_queue: Ensure that queue attributes propagate completely during Create and Update ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) From 51ff63b19fe5cc20f1ffb524f6e5e90453a9b03d Mon Sep 17 00:00:00 2001 From: Phil Nichol <35630607+philnichol@users.noreply.github.com> Date: Sat, 29 May 2021 14:11:28 +0100 Subject: [PATCH 0349/1208] added acctests --- aws/data_source_aws_appmesh_mesh.go | 125 +++++++++++++++++ aws/data_source_aws_appmesh_mesh_test.go | 162 +++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 aws/data_source_aws_appmesh_mesh.go create mode 100644 aws/data_source_aws_appmesh_mesh_test.go diff --git a/aws/data_source_aws_appmesh_mesh.go b/aws/data_source_aws_appmesh_mesh.go new file mode 100644 index 000000000000..c776e0140bf2 --- /dev/null +++ b/aws/data_source_aws_appmesh_mesh.go @@ -0,0 +1,125 @@ +package aws + +import ( + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func dataSourceAwsAppmeshMesh() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsAppmeshMeshRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "spec": { + Type: schema.TypeList, + Computed: true, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "egress_filter": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "arn": { + Type: schema.TypeString, + Computed: true, + }, + + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + + "last_updated_date": { + Type: schema.TypeString, + Computed: true, + }, + + "mesh_owner": { + Type: schema.TypeString, + Optional: true, + }, + + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, + + "tags": tagsSchemaComputed(), + }, + } +} + +func dataSourceAwsAppmeshMeshRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appmeshconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + meshName := d.Get("name").(string) + + req := &appmesh.DescribeMeshInput{ + MeshName: aws.String(meshName), + } + if v, ok := d.GetOk("mesh_owner"); ok { + req.MeshOwner = aws.String(v.(string)) + } + + resp, err := conn.DescribeMesh(req) + if isAWSErr(err, appmesh.ErrCodeNotFoundException, "") { + return fmt.Errorf("App Mesh Mesh (%s) not found", meshName) + } + if err != nil { + return fmt.Errorf("error reading App Mesh service mesh: %s", err) + } + if aws.StringValue(resp.Mesh.Status.Status) == appmesh.MeshStatusCodeDeleted { + return fmt.Errorf("App Mesh Mesh (%s) has status: 'DELETED'", meshName) + } + + arn := aws.StringValue(resp.Mesh.Metadata.Arn) + + d.SetId(aws.StringValue(resp.Mesh.MeshName)) + d.Set("arn", arn) + d.Set("created_date", resp.Mesh.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", resp.Mesh.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_owner", resp.Mesh.Metadata.MeshOwner) + d.Set("resource_owner", resp.Mesh.Metadata.ResourceOwner) + err = d.Set("spec", flattenAppmeshMeshSpec(resp.Mesh.Spec)) + if err != nil { + return fmt.Errorf("error setting spec: %s", err) + } + + tags, err := keyvaluetags.AppmeshListTags(conn, arn) + + if err != nil { + return fmt.Errorf("error listing tags for App Mesh service mesh (%s): %s", arn, err) + } + + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} diff --git a/aws/data_source_aws_appmesh_mesh_test.go b/aws/data_source_aws_appmesh_mesh_test.go new file mode 100644 index 000000000000..cf834951fd2a --- /dev/null +++ b/aws/data_source_aws_appmesh_mesh_test.go @@ -0,0 +1,162 @@ +package aws + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSAppmeshMeshDataSource_basic(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appmesh_mesh.test" + dataSourceName := "data.aws_appmesh_mesh.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsAppmeshMeshDataSourceConfig(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.egress_filter.0.type", dataSourceName, "spec.0.egress_filter.0.type"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + +func TestAccAWSAppmeshMeshDataSource_meshOwner(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appmesh_mesh.test" + dataSourceName := "data.aws_appmesh_mesh.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppmeshMeshDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsAppmeshMeshDataSourceConfig(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.egress_filter.0.type", dataSourceName, "spec.0.egress_filter.0.type"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + +func TestAccAWSAppmeshMeshDataSource_specAndTagsSet(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appmesh_mesh.test" + dataSourceName := "data.aws_appmesh_mesh.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppmeshMeshDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsAppmeshMeshDataSourceConfig(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.egress_filter.0.type", dataSourceName, "spec.0.egress_filter.0.type"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + +func TestAccAWSAppmeshMeshDataSource_nonExistent(t *testing.T) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppmeshMeshDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsAppmeshMeshDataSourceConfig_NonExistent, + ExpectError: regexp.MustCompile(`not found`), + }, + }, + }) +} + +const testAccCheckAwsAppmeshMeshDataSourceConfig_NonExistent = ` +data "aws_appmesh_mesh" "test" { + name = "tf-acc-test-non-existent" +} +` + +func testAccCheckAwsAppmeshMeshDataSourceConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_appmesh_mesh" "test" { + name = %q +} + +data "aws_appmesh_mesh" "test" { + name = aws_appmesh_mesh.test.name +} +`, rName) +} + +func testAccCheckAwsAppmeshMeshDataSourceConfig_meshOwner(rName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_appmesh_mesh" "test" { + name = %q +} + +data "aws_appmesh_mesh" "test" { + name = aws_appmesh_mesh.test.name + mesh_owner = data.aws_caller_identity.current.account_id +} +`, rName) +} + +func testAccCheckAwsAppmeshMeshDataSourceConfig_specAndTagsSet(rName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_appmesh_mesh" "test" { + name = %q + + spec { + egress_filter { + type = "DROP_ALL" + } + } + + tags = { + foo = "bar" + good = "bad" + } +} + +data "aws_appmesh_mesh" "test" { + name = aws_appmesh_mesh.test.name +} +`, rName) +} From 7df1e25a0b944d0e3e0112675a5b6c8f6e8ea62a Mon Sep 17 00:00:00 2001 From: Phil Nichol <35630607+philnichol@users.noreply.github.com> Date: Sat, 29 May 2021 14:24:47 +0100 Subject: [PATCH 0350/1208] updated docs, added provider --- aws/data_source_aws_appmesh_mesh_test.go | 4 +- aws/provider.go | 1 + website/docs/d/appmesh_mesh.html.markdown | 54 +++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 website/docs/d/appmesh_mesh.html.markdown diff --git a/aws/data_source_aws_appmesh_mesh_test.go b/aws/data_source_aws_appmesh_mesh_test.go index cf834951fd2a..86879f925b44 100644 --- a/aws/data_source_aws_appmesh_mesh_test.go +++ b/aws/data_source_aws_appmesh_mesh_test.go @@ -46,7 +46,7 @@ func TestAccAWSAppmeshMeshDataSource_meshOwner(t *testing.T) { CheckDestroy: testAccCheckAppmeshMeshDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckAwsAppmeshMeshDataSourceConfig(rName), + Config: testAccCheckAwsAppmeshMeshDataSourceConfig_meshOwner(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), @@ -73,7 +73,7 @@ func TestAccAWSAppmeshMeshDataSource_specAndTagsSet(t *testing.T) { CheckDestroy: testAccCheckAppmeshMeshDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckAwsAppmeshMeshDataSourceConfig(rName), + Config: testAccCheckAwsAppmeshMeshDataSourceConfig_specAndTagsSet(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), diff --git a/aws/provider.go b/aws/provider.go index c70ec8bf3c64..90a101318462 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -196,6 +196,7 @@ func Provider() *schema.Provider { "aws_api_gateway_vpc_link": dataSourceAwsApiGatewayVpcLink(), "aws_apigatewayv2_api": dataSourceAwsApiGatewayV2Api(), "aws_apigatewayv2_apis": dataSourceAwsApiGatewayV2Apis(), + "aws_appmesh_mesh": dataSourceAwsAppmeshMesh(), "aws_arn": dataSourceAwsArn(), "aws_autoscaling_group": dataSourceAwsAutoscalingGroup(), "aws_autoscaling_groups": dataSourceAwsAutoscalingGroups(), diff --git a/website/docs/d/appmesh_mesh.html.markdown b/website/docs/d/appmesh_mesh.html.markdown new file mode 100644 index 000000000000..e42defab0b7e --- /dev/null +++ b/website/docs/d/appmesh_mesh.html.markdown @@ -0,0 +1,54 @@ +--- +subcategory: "AppMesh" +layout: "aws" +page_title: "AWS: aws_appmesh_mesh" +description: |- + Provides details about an App Mesh Mesh service mesh resource. +--- + +# Data Source: aws_appmesh_mesh + +The App Mesh Mesh data source allows details of an App Mesh Mesh to be retrieved by it's name and/or mesh_owner. + +## Example Usage + +```hcl +data "aws_appmesh_mesh" "simple" { + name = "simpleapp" +} +``` + +```hcl +data "aws_caller_identity" "current" {} + +data "aws_appmesh_mesh" "simple" { + name = "simpleapp" + mesh_owner = data.aws_caller_identity.current.account_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the service mesh. +* `mesh_owner` - (Optional) The AWS account ID of the service mesh's owner. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The ARN of the service mesh. +* `created_date` - The creation date of the service mesh. +* `last_updated_date` - The last update date of the service mesh. +* `resource_owner` - The resource owner's AWS account ID. +* `spec` - The service mesh specification. +* `tags` - A map of tags. + +### Spec + +* `egress_filter` - The egress filter rules for the service mesh. + +### Egress Filter + +* `type` - The egress filter type. By default, the type is `DROP_ALL`, but if the resource was created by Terraform without this value set, this will return `None`. \ No newline at end of file From d719328bab91162d85326ad36f26a78ac3ef77db Mon Sep 17 00:00:00 2001 From: Phil Nichol <35630607+philnichol@users.noreply.github.com> Date: Sat, 29 May 2021 14:28:44 +0100 Subject: [PATCH 0351/1208] removed unecessary comment in docs --- website/docs/d/appmesh_mesh.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/appmesh_mesh.html.markdown b/website/docs/d/appmesh_mesh.html.markdown index e42defab0b7e..8117d503be51 100644 --- a/website/docs/d/appmesh_mesh.html.markdown +++ b/website/docs/d/appmesh_mesh.html.markdown @@ -51,4 +51,4 @@ In addition to all arguments above, the following attributes are exported: ### Egress Filter -* `type` - The egress filter type. By default, the type is `DROP_ALL`, but if the resource was created by Terraform without this value set, this will return `None`. \ No newline at end of file +* `type` - The egress filter type. \ No newline at end of file From 38b4e4ea63d3fbe43cac675cac69b41be2989dcc Mon Sep 17 00:00:00 2001 From: Phil Nichol <35630607+philnichol@users.noreply.github.com> Date: Sat, 29 May 2021 14:31:30 +0100 Subject: [PATCH 0352/1208] added note for changelog --- .changelog/19577.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19577.txt diff --git a/.changelog/19577.txt b/.changelog/19577.txt new file mode 100644 index 000000000000..11ca4ee70159 --- /dev/null +++ b/.changelog/19577.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_appmesh_mesh +``` From d5bda9a32ca8eecc2ca01304f54967d1eecad254 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 9 Jun 2021 17:09:49 -0400 Subject: [PATCH 0353/1208] d/aws_appmesh_mesh: Review changes. --- aws/data_source_aws_appmesh_mesh.go | 57 +++++++++++------------ aws/data_source_aws_appmesh_mesh_test.go | 27 ++--------- website/docs/d/appmesh_mesh.html.markdown | 2 +- 3 files changed, 31 insertions(+), 55 deletions(-) diff --git a/aws/data_source_aws_appmesh_mesh.go b/aws/data_source_aws_appmesh_mesh.go index c776e0140bf2..038ece65d68b 100644 --- a/aws/data_source_aws_appmesh_mesh.go +++ b/aws/data_source_aws_appmesh_mesh.go @@ -15,26 +15,49 @@ func dataSourceAwsAppmeshMesh() *schema.Resource { Read: dataSourceAwsAppmeshMeshRead, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + + "last_updated_date": { + Type: schema.TypeString, + Computed: true, + }, + + "mesh_owner": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "name": { Type: schema.TypeString, Required: true, }, + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, + "spec": { Type: schema.TypeList, Computed: true, - Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "egress_filter": { Type: schema.TypeList, - Optional: true, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "type": { Type: schema.TypeString, - Optional: true, Computed: true, }, }, @@ -44,31 +67,6 @@ func dataSourceAwsAppmeshMesh() *schema.Resource { }, }, - "arn": { - Type: schema.TypeString, - Computed: true, - }, - - "created_date": { - Type: schema.TypeString, - Computed: true, - }, - - "last_updated_date": { - Type: schema.TypeString, - Computed: true, - }, - - "mesh_owner": { - Type: schema.TypeString, - Optional: true, - }, - - "resource_owner": { - Type: schema.TypeString, - Computed: true, - }, - "tags": tagsSchemaComputed(), }, } @@ -88,9 +86,6 @@ func dataSourceAwsAppmeshMeshRead(d *schema.ResourceData, meta interface{}) erro } resp, err := conn.DescribeMesh(req) - if isAWSErr(err, appmesh.ErrCodeNotFoundException, "") { - return fmt.Errorf("App Mesh Mesh (%s) not found", meshName) - } if err != nil { return fmt.Errorf("error reading App Mesh service mesh: %s", err) } diff --git a/aws/data_source_aws_appmesh_mesh_test.go b/aws/data_source_aws_appmesh_mesh_test.go index 86879f925b44..cfb7694417ee 100644 --- a/aws/data_source_aws_appmesh_mesh_test.go +++ b/aws/data_source_aws_appmesh_mesh_test.go @@ -5,6 +5,7 @@ import ( "regexp" "testing" + "github.com/aws/aws-sdk-go/service/appmesh" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,7 +16,7 @@ func TestAccAWSAppmeshMeshDataSource_basic(t *testing.T) { dataSourceName := "data.aws_appmesh_mesh.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { @@ -41,7 +42,7 @@ func TestAccAWSAppmeshMeshDataSource_meshOwner(t *testing.T) { dataSourceName := "data.aws_appmesh_mesh.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAppmeshMeshDestroy, Steps: []resource.TestStep{ @@ -68,7 +69,7 @@ func TestAccAWSAppmeshMeshDataSource_specAndTagsSet(t *testing.T) { dataSourceName := "data.aws_appmesh_mesh.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAppmeshMeshDestroy, Steps: []resource.TestStep{ @@ -89,26 +90,6 @@ func TestAccAWSAppmeshMeshDataSource_specAndTagsSet(t *testing.T) { }) } -func TestAccAWSAppmeshMeshDataSource_nonExistent(t *testing.T) { - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAppmeshMeshDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckAwsAppmeshMeshDataSourceConfig_NonExistent, - ExpectError: regexp.MustCompile(`not found`), - }, - }, - }) -} - -const testAccCheckAwsAppmeshMeshDataSourceConfig_NonExistent = ` -data "aws_appmesh_mesh" "test" { - name = "tf-acc-test-non-existent" -} -` - func testAccCheckAwsAppmeshMeshDataSourceConfig(rName string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { diff --git a/website/docs/d/appmesh_mesh.html.markdown b/website/docs/d/appmesh_mesh.html.markdown index 8117d503be51..e4a0085f0f4e 100644 --- a/website/docs/d/appmesh_mesh.html.markdown +++ b/website/docs/d/appmesh_mesh.html.markdown @@ -8,7 +8,7 @@ description: |- # Data Source: aws_appmesh_mesh -The App Mesh Mesh data source allows details of an App Mesh Mesh to be retrieved by it's name and/or mesh_owner. +The App Mesh Mesh data source allows details of an App Mesh Mesh to be retrieved by its name and optionally the mesh_owner. ## Example Usage From cf58abe2ba8da53c3f2f16f9d75e438bfdf19957 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 9 Jun 2021 17:20:04 -0400 Subject: [PATCH 0354/1208] d/aws_appmesh_mesh: Add 'ErrorCheck' to acceptance tests. --- aws/data_source_aws_appmesh_mesh_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/aws/data_source_aws_appmesh_mesh_test.go b/aws/data_source_aws_appmesh_mesh_test.go index cfb7694417ee..cb0147d48df1 100644 --- a/aws/data_source_aws_appmesh_mesh_test.go +++ b/aws/data_source_aws_appmesh_mesh_test.go @@ -2,7 +2,6 @@ package aws import ( "fmt" - "regexp" "testing" "github.com/aws/aws-sdk-go/service/appmesh" @@ -16,8 +15,10 @@ func TestAccAWSAppmeshMeshDataSource_basic(t *testing.T) { dataSourceName := "data.aws_appmesh_mesh.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, appmesh.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppmeshMeshDestroy, Steps: []resource.TestStep{ { Config: testAccCheckAwsAppmeshMeshDataSourceConfig(rName), @@ -43,6 +44,7 @@ func TestAccAWSAppmeshMeshDataSource_meshOwner(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, appmesh.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAppmeshMeshDestroy, Steps: []resource.TestStep{ @@ -70,6 +72,7 @@ func TestAccAWSAppmeshMeshDataSource_specAndTagsSet(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, appmesh.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAppmeshMeshDestroy, Steps: []resource.TestStep{ From 4c0a8b94a3d207afaada339550d220fe20a2801f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 9 Jun 2021 17:25:26 -0400 Subject: [PATCH 0355/1208] Fix terrafmt errors. --- aws/data_source_aws_appmesh_mesh_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/data_source_aws_appmesh_mesh_test.go b/aws/data_source_aws_appmesh_mesh_test.go index cb0147d48df1..a5a6b8a7d135 100644 --- a/aws/data_source_aws_appmesh_mesh_test.go +++ b/aws/data_source_aws_appmesh_mesh_test.go @@ -96,11 +96,11 @@ func TestAccAWSAppmeshMeshDataSource_specAndTagsSet(t *testing.T) { func testAccCheckAwsAppmeshMeshDataSourceConfig(rName string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { - name = %q + name = %[1]q } data "aws_appmesh_mesh" "test" { - name = aws_appmesh_mesh.test.name + name = aws_appmesh_mesh.test.name } `, rName) } @@ -110,11 +110,11 @@ func testAccCheckAwsAppmeshMeshDataSourceConfig_meshOwner(rName string) string { data "aws_caller_identity" "current" {} resource "aws_appmesh_mesh" "test" { - name = %q + name = %[1]q } data "aws_appmesh_mesh" "test" { - name = aws_appmesh_mesh.test.name + name = aws_appmesh_mesh.test.name mesh_owner = data.aws_caller_identity.current.account_id } `, rName) @@ -125,7 +125,7 @@ func testAccCheckAwsAppmeshMeshDataSourceConfig_specAndTagsSet(rName string) str data "aws_caller_identity" "current" {} resource "aws_appmesh_mesh" "test" { - name = %q + name = %[1]q spec { egress_filter { From 54d901b666636a0675409a660c418e1cc9c147f7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 9 Jun 2021 17:29:24 -0400 Subject: [PATCH 0356/1208] Fix terrafmt errors. --- website/docs/d/appmesh_mesh.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/appmesh_mesh.html.markdown b/website/docs/d/appmesh_mesh.html.markdown index e4a0085f0f4e..9ccad2bdc772 100644 --- a/website/docs/d/appmesh_mesh.html.markdown +++ b/website/docs/d/appmesh_mesh.html.markdown @@ -22,7 +22,7 @@ data "aws_appmesh_mesh" "simple" { data "aws_caller_identity" "current" {} data "aws_appmesh_mesh" "simple" { - name = "simpleapp" + name = "simpleapp" mesh_owner = data.aws_caller_identity.current.account_id } ``` From 6e6e25d1691ff3be3d3a5aff28172cdf442988d7 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 9 Jun 2021 21:35:39 +0000 Subject: [PATCH 0357/1208] Update CHANGELOG.md for #19738 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfdd8559de6b..1781b6d72742 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ ENHANCEMENTS: * resource/aws_cognito_user_pool: Add `custom_email_sender`, `custom_sms_sender`, and `kms_key_id` to `lambda_config` ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) * resource/aws_cognito_user_pool: Add plan time validation for `name` ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) * resource/aws_cognito_user_pool_client: Add plan time validation for `id_token_validity` and `access_token_validity`. ([#19702](https://github.com/hashicorp/terraform-provider-aws/issues/19702)) +* resource/aws_cur_report_definition: Add `arn` attribute. ([#19705](https://github.com/hashicorp/terraform-provider-aws/issues/19705)) +* resource/aws_cur_report_definition: Add plan time validation for `report_name`. ([#19705](https://github.com/hashicorp/terraform-provider-aws/issues/19705)) +* resource/aws_cur_report_definition: Support updating definition. ([#19705](https://github.com/hashicorp/terraform-provider-aws/issues/19705)) * resource/aws_default_vpc_dhcp_options: Add `owner_id` argument. ([#19656](https://github.com/hashicorp/terraform-provider-aws/issues/19656)) * resource/aws_ecs_task_definition: Add plan time validation for `family` and `requires_compatibilities`. ([#19670](https://github.com/hashicorp/terraform-provider-aws/issues/19670)) * resource/aws_ecs_task_definition: Add support for `ephemeral_storage`. ([#19694](https://github.com/hashicorp/terraform-provider-aws/issues/19694)) From 31bf342ed9d61ebb7c88f6ae7feda004bc377c25 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 9 Jun 2021 21:51:41 +0000 Subject: [PATCH 0358/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1781b6d72742..cff56ce6295d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ FEATURES: +* **New Data Source:** `aws_appmesh_mesh` ([#19577](https://github.com/hashicorp/terraform-provider-aws/issues/19577)) * **New Data Source:** `aws_globalaccelerator_accelerator` ([#19647](https://github.com/hashicorp/terraform-provider-aws/issues/19647)) ENHANCEMENTS: From d59c0bf32c5ee2a27d75b42d69290446008d5ba6 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 10 Jun 2021 01:24:08 +0300 Subject: [PATCH 0359/1208] unset columns when updating with schema_reference --- aws/resource_aws_glue_catalog_table.go | 1 + aws/resource_aws_glue_catalog_table_test.go | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/aws/resource_aws_glue_catalog_table.go b/aws/resource_aws_glue_catalog_table.go index 1026f1a4e754..56e7107e73e2 100644 --- a/aws/resource_aws_glue_catalog_table.go +++ b/aws/resource_aws_glue_catalog_table.go @@ -623,6 +623,7 @@ func expandGlueStorageDescriptor(l []interface{}) *glue.StorageDescriptor { } if v, ok := s["schema_reference"]; ok { + storageDescriptor.Columns = nil storageDescriptor.SchemaReference = expandGlueTableSchemaReference(v.([]interface{})) } diff --git a/aws/resource_aws_glue_catalog_table_test.go b/aws/resource_aws_glue_catalog_table_test.go index 5f3bc50d0912..b6d7706fd3fa 100644 --- a/aws/resource_aws_glue_catalog_table_test.go +++ b/aws/resource_aws_glue_catalog_table_test.go @@ -471,6 +471,17 @@ func TestAccAWSGlueCatalogTable_StorageDescriptor_schemaReference(t *testing.T) ImportState: true, ImportStateVerify: true, }, + { + Config: testAccGlueCatalogTableConfigStorageDescriptorSchemaReferenceArn(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGlueCatalogTableExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "storage_descriptor.0.schema_reference.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_descriptor.0.schema_reference.0.schema_version_number", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_descriptor.0.schema_reference.0.schema_id.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "storage_descriptor.0.schema_reference.0.schema_id.0.schema_arn", "aws_glue_schema.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "storage_descriptor.0.columns.#", "2"), + ), + }, }, }) } From c234db184a42b735743ab88cb623ef62f48f31d2 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 10 Jun 2021 01:26:40 +0300 Subject: [PATCH 0360/1208] changelog --- .changelog/19742.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19742.txt diff --git a/.changelog/19742.txt b/.changelog/19742.txt new file mode 100644 index 000000000000..4f5d5b2f91a0 --- /dev/null +++ b/.changelog/19742.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_glue_catalog_table: Fix updating `schema_reference` when columns are present. +``` \ No newline at end of file From 36ddac2c32a001189f6ecfdfabdf34603585c3f8 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 10 Jun 2021 01:31:07 +0300 Subject: [PATCH 0361/1208] check len --- aws/resource_aws_glue_catalog_table.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_glue_catalog_table.go b/aws/resource_aws_glue_catalog_table.go index 56e7107e73e2..2f2fa3cc5588 100644 --- a/aws/resource_aws_glue_catalog_table.go +++ b/aws/resource_aws_glue_catalog_table.go @@ -622,7 +622,7 @@ func expandGlueStorageDescriptor(l []interface{}) *glue.StorageDescriptor { storageDescriptor.StoredAsSubDirectories = aws.Bool(v.(bool)) } - if v, ok := s["schema_reference"]; ok { + if v, ok := s["schema_reference"]; ok && len(v.([]interface{})) > 0 { storageDescriptor.Columns = nil storageDescriptor.SchemaReference = expandGlueTableSchemaReference(v.([]interface{})) } From b73af77386979581ed0d65d0d6c778dde5f53f58 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 10 Jun 2021 01:42:34 +0300 Subject: [PATCH 0362/1208] set location uri to computed --- aws/resource_aws_glue_catalog_database.go | 1 + ...resource_aws_glue_catalog_database_test.go | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/aws/resource_aws_glue_catalog_database.go b/aws/resource_aws_glue_catalog_database.go index 060cf9327346..156c6d039b1c 100644 --- a/aws/resource_aws_glue_catalog_database.go +++ b/aws/resource_aws_glue_catalog_database.go @@ -51,6 +51,7 @@ func resourceAwsGlueCatalogDatabase() *schema.Resource { "location_uri": { Type: schema.TypeString, Optional: true, + Computed: true, }, "parameters": { Type: schema.TypeMap, diff --git a/aws/resource_aws_glue_catalog_database_test.go b/aws/resource_aws_glue_catalog_database_test.go index 541520e6feed..1c1869658b16 100644 --- a/aws/resource_aws_glue_catalog_database_test.go +++ b/aws/resource_aws_glue_catalog_database_test.go @@ -141,6 +141,17 @@ func TestAccAWSGlueCatalogDatabase_targetDatabase(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccGlueCatalogDatabaseConfigTargetDatabaseWithLocation(rName), + Destroy: false, + Check: resource.ComposeTestCheckFunc( + testAccCheckGlueCatalogDatabaseExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "target_database.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "target_database.0.catalog_id", "aws_glue_catalog_database.test2", "catalog_id"), + resource.TestCheckResourceAttrPair(resourceName, "target_database.0.database_name", "aws_glue_catalog_database.test2", "name"), + resource.TestCheckResourceAttrPair(resourceName, "location_uri", "aws_glue_catalog_database.test2", "location_uri"), + ), + }, }, }) } @@ -238,6 +249,24 @@ resource "aws_glue_catalog_database" "test2" { `, rName) } +func testAccGlueCatalogDatabaseConfigTargetDatabaseWithLocation(rName string) string { + return fmt.Sprintf(` +resource "aws_glue_catalog_database" "test" { + name = %[1]q + + target_database { + catalog_id = aws_glue_catalog_database.test2.catalog_id + database_name = aws_glue_catalog_database.test2.name + } +} + +resource "aws_glue_catalog_database" "test2" { + name = "%[1]s-2" + location_uri = "my-location" +} +`, rName) +} + func testAccCheckGlueCatalogDatabaseExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] From 30befcde003cf0411bcef5aa8ddb981663e4ebd2 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 10 Jun 2021 01:45:59 +0300 Subject: [PATCH 0363/1208] changelog --- .changelog/19743.txt | 3 +++ aws/resource_aws_glue_catalog_database_test.go | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .changelog/19743.txt diff --git a/.changelog/19743.txt b/.changelog/19743.txt new file mode 100644 index 000000000000..0a392951498f --- /dev/null +++ b/.changelog/19743.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_glue_catalog_database: Set `location_uri` as compute to prevent drift when `target_table` has `location_uri` set. +``` \ No newline at end of file diff --git a/aws/resource_aws_glue_catalog_database_test.go b/aws/resource_aws_glue_catalog_database_test.go index 1c1869658b16..07b8b7883a41 100644 --- a/aws/resource_aws_glue_catalog_database_test.go +++ b/aws/resource_aws_glue_catalog_database_test.go @@ -149,7 +149,6 @@ func TestAccAWSGlueCatalogDatabase_targetDatabase(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "target_database.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "target_database.0.catalog_id", "aws_glue_catalog_database.test2", "catalog_id"), resource.TestCheckResourceAttrPair(resourceName, "target_database.0.database_name", "aws_glue_catalog_database.test2", "name"), - resource.TestCheckResourceAttrPair(resourceName, "location_uri", "aws_glue_catalog_database.test2", "location_uri"), ), }, }, From 77d9014687a87e5b07ce5cae90338a6c7d385cf2 Mon Sep 17 00:00:00 2001 From: Ian Neubert Date: Wed, 9 Jun 2021 18:01:41 -0700 Subject: [PATCH 0364/1208] Apply suggestions from code review Co-authored-by: angie pinilla --- .changelog/19555.txt | 2 +- aws/resource_aws_cloudwatch_event_target.go | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.changelog/19555.txt b/.changelog/19555.txt index 71ed41d7b3b6..161bc3f9034b 100644 --- a/.changelog/19555.txt +++ b/.changelog/19555.txt @@ -1,3 +1,3 @@ ```release-note:bug -resource/aws_cloudwatch_event_target: Fix ecs_target.launch_type not allowing empty string values. +resource/aws_cloudwatch_event_target: Fix `ecs_target.launch_type` not allowing empty string values. ``` diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index 4b26fac283e6..11fa6a16d115 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -146,7 +146,10 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource { Type: schema.TypeString, Optional: true, Default: events.LaunchTypeEc2, - ValidateFunc: validation.StringInSlice(append(events.LaunchType_Values(), []string{""}...), false), + ValidateFunc: validation.Any( + validation.StringIsEmpty, + validation.StringInSlice(events.LaunchType_Values(), false), + ), }, "network_configuration": { Type: schema.TypeList, From 654014321d8105bfd9c64c7ac01b8157eed2ff33 Mon Sep 17 00:00:00 2001 From: Ian Neubert Date: Wed, 9 Jun 2021 19:07:04 -0700 Subject: [PATCH 0365/1208] Fix error message from gofmt --- aws/resource_aws_cloudwatch_event_target.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index 11fa6a16d115..f4dbe2851140 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -143,9 +143,9 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource { ValidateFunc: validation.StringLenBetween(1, 255), }, "launch_type": { - Type: schema.TypeString, - Optional: true, - Default: events.LaunchTypeEc2, + Type: schema.TypeString, + Optional: true, + Default: events.LaunchTypeEc2, ValidateFunc: validation.Any( validation.StringIsEmpty, validation.StringInSlice(events.LaunchType_Values(), false), From 4424349df4986a615ed24c96461ae9bc9c132bac Mon Sep 17 00:00:00 2001 From: Ian Neubert Date: Wed, 9 Jun 2021 19:08:06 -0700 Subject: [PATCH 0366/1208] Add acceptance tests for CloudWatchEventTargetEcs with LaunchType blank and modifying from a set LaunchType to blank. --- ...source_aws_cloudwatch_event_target_test.go | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/aws/resource_aws_cloudwatch_event_target_test.go b/aws/resource_aws_cloudwatch_event_target_test.go index 987a4b7eaf3e..2cb69481f25c 100644 --- a/aws/resource_aws_cloudwatch_event_target_test.go +++ b/aws/resource_aws_cloudwatch_event_target_test.go @@ -447,6 +447,49 @@ func TestAccAWSCloudWatchEventTarget_ecs(t *testing.T) { ImportStateIdFunc: testAccAWSCloudWatchEventTargetImportStateIdFunc(resourceName), ImportStateVerify: true, }, + { + Config: testAccAWSCloudWatchEventTargetConfigEcsWithBlankLaunchType(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventTargetExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.launch_type", ""), + ), + }, + }, + }) +} + +func TestAccAWSCloudWatchEventTarget_ecsWithBlankLaunchType(t *testing.T) { + resourceName := "aws_cloudwatch_event_target.test" + iamRoleResourceName := "aws_iam_role.test" + ecsTaskDefinitionResourceName := "aws_ecs_task_definition.task" + var v events.Target + rName := acctest.RandomWithPrefix("tf_ecs_target") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventTargetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventTargetConfigEcsWithBlankLaunchType(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventTargetExists(resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "role_arn", iamRoleResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.task_count", "1"), + resource.TestCheckResourceAttrPair(resourceName, "ecs_target.0.task_definition_arn", ecsTaskDefinitionResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.launch_type", ""), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.network_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.network_configuration.0.subnets.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAWSCloudWatchEventTargetImportStateIdFunc(resourceName), + ImportStateVerify: true, + }, }, }) } @@ -1275,6 +1318,110 @@ data "aws_partition" "current" {} `, rName) } +func testAccAWSCloudWatchEventTargetConfigEcsWithBlankLaunchType(rName string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_rule" "test" { + name = %[1]q + description = "schedule_ecs_test" + + schedule_expression = "rate(5 minutes)" +} + +resource "aws_vpc" "vpc" { + cidr_block = "10.1.0.0/16" +} + +resource "aws_subnet" "subnet" { + vpc_id = aws_vpc.vpc.id + cidr_block = "10.1.1.0/24" +} + +resource "aws_cloudwatch_event_target" "test" { + arn = aws_ecs_cluster.test.id + rule = aws_cloudwatch_event_rule.test.id + role_arn = aws_iam_role.test.arn + + ecs_target { + task_count = 1 + task_definition_arn = aws_ecs_task_definition.task.arn + launch_type = "" + + network_configuration { + subnets = [aws_subnet.subnet.id] + } + } +} + +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = < Date: Thu, 10 Jun 2021 16:11:25 +0300 Subject: [PATCH 0367/1208] allow update of data sync smb --- aws/resource_aws_datasync_location_smb.go | 85 +++++++++++-------- ...resource_aws_datasync_location_smb_test.go | 39 ++++++--- 2 files changed, 76 insertions(+), 48 deletions(-) diff --git a/aws/resource_aws_datasync_location_smb.go b/aws/resource_aws_datasync_location_smb.go index 7acf7bb951c6..7da75cb9e2c1 100644 --- a/aws/resource_aws_datasync_location_smb.go +++ b/aws/resource_aws_datasync_location_smb.go @@ -29,52 +29,49 @@ func resourceAwsDataSyncLocationSmb() *schema.Resource { "agent_arns": { Type: schema.TypeSet, Required: true, - ForceNew: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateArn, + }, }, "domain": { - Type: schema.TypeString, - Computed: true, - Optional: true, - ForceNew: true, + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 253), }, "mount_options": { Type: schema.TypeList, Optional: true, - ForceNew: true, MaxItems: 1, DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "version": { - Type: schema.TypeString, - Default: datasync.SmbVersionAutomatic, - Optional: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - datasync.SmbVersionAutomatic, - datasync.SmbVersionSmb2, - datasync.SmbVersionSmb3, - }, false), + Type: schema.TypeString, + Default: datasync.SmbVersionAutomatic, + Optional: true, + ValidateFunc: validation.StringInSlice(datasync.SmbVersion_Values(), false), }, }, }, }, "password": { - Type: schema.TypeString, - Required: true, - Sensitive: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + Sensitive: true, + ValidateFunc: validation.StringLenBetween(1, 104), }, "server_hostname": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, "subdirectory": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 4096), /*// Ignore missing trailing slash DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { if new == "/" { @@ -94,9 +91,9 @@ func resourceAwsDataSyncLocationSmb() *schema.Resource { Computed: true, }, "user": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 104), }, }, @@ -126,7 +123,7 @@ func resourceAwsDataSyncLocationSmbCreate(d *schema.ResourceData, meta interface log.Printf("[DEBUG] Creating DataSync Location SMB: %s", input) output, err := conn.CreateLocationSmb(input) if err != nil { - return fmt.Errorf("error creating DataSync Location SMB: %s", err) + return fmt.Errorf("error creating DataSync Location SMB: %w", err) } d.SetId(aws.StringValue(output.LocationArn)) @@ -153,7 +150,7 @@ func resourceAwsDataSyncLocationSmbRead(d *schema.ResourceData, meta interface{} } if err != nil { - return fmt.Errorf("error reading DataSync Location SMB (%s): %s", d.Id(), err) + return fmt.Errorf("error reading DataSync Location SMB (%s): %w", d.Id(), err) } tagsInput := &datasync.ListTagsForResourceInput{ @@ -164,13 +161,13 @@ func resourceAwsDataSyncLocationSmbRead(d *schema.ResourceData, meta interface{} tagsOutput, err := conn.ListTagsForResource(tagsInput) if err != nil { - return fmt.Errorf("error reading DataSync Location SMB (%s) tags: %s", d.Id(), err) + return fmt.Errorf("error reading DataSync Location SMB (%s) tags: %w", d.Id(), err) } subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri)) if err != nil { - return fmt.Errorf("error parsing Location SMB (%s) URI (%s): %s", d.Id(), aws.StringValue(output.LocationUri), err) + return fmt.Errorf("error parsing Location SMB (%s) URI (%s): %w", d.Id(), aws.StringValue(output.LocationUri), err) } d.Set("agent_arns", flattenStringSet(output.AgentArns)) @@ -180,7 +177,7 @@ func resourceAwsDataSyncLocationSmbRead(d *schema.ResourceData, meta interface{} d.Set("domain", output.Domain) if err := d.Set("mount_options", flattenDataSyncSmbMountOptions(output.MountOptions)); err != nil { - return fmt.Errorf("error setting mount_options: %s", err) + return fmt.Errorf("error setting mount_options: %w", err) } d.Set("subdirectory", subdirectory) @@ -206,6 +203,26 @@ func resourceAwsDataSyncLocationSmbRead(d *schema.ResourceData, meta interface{} func resourceAwsDataSyncLocationSmbUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).datasyncconn + if d.HasChangesExcept("tags_all", "tags") { + input := &datasync.UpdateLocationSmbInput{ + LocationArn: aws.String(d.Id()), + AgentArns: expandStringSet(d.Get("agent_arns").(*schema.Set)), + MountOptions: expandDataSyncSmbMountOptions(d.Get("mount_options").([]interface{})), + Password: aws.String(d.Get("password").(string)), + Subdirectory: aws.String(d.Get("subdirectory").(string)), + User: aws.String(d.Get("user").(string)), + } + + if v, ok := d.GetOk("domain"); ok { + input.Domain = aws.String(v.(string)) + } + + _, err := conn.UpdateLocationSmb(input) + if err != nil { + return fmt.Errorf("error updating DataSync Location SMB (%s): %w", d.Id(), err) + } + } + if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") diff --git a/aws/resource_aws_datasync_location_smb_test.go b/aws/resource_aws_datasync_location_smb_test.go index 6e56e2c9c611..6f5696bbd295 100644 --- a/aws/resource_aws_datasync_location_smb_test.go +++ b/aws/resource_aws_datasync_location_smb_test.go @@ -25,7 +25,7 @@ func init() { func testSweepDataSyncLocationSmbs(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } conn := client.(*AWSClient).datasyncconn @@ -39,7 +39,7 @@ func testSweepDataSyncLocationSmbs(region string) error { } if err != nil { - return fmt.Errorf("Error retrieving DataSync Location SMBs: %s", err) + return fmt.Errorf("Error retrieving DataSync Location SMBs: %w", err) } if len(output.Locations) == 0 { @@ -54,12 +54,11 @@ func testSweepDataSyncLocationSmbs(region string) error { continue } log.Printf("[INFO] Deleting DataSync Location SMB: %s", uri) - input := &datasync.DeleteLocationInput{ - LocationArn: location.LocationArn, - } - - _, err := conn.DeleteLocation(input) + r := resourceAwsDataSyncLocationSmb() + d := r.Data(nil) + d.SetId(aws.StringValue(location.LocationArn)) + err = r.Delete(d, client) if isAWSErr(err, "InvalidRequestException", "not found") { continue } @@ -92,10 +91,9 @@ func TestAccAWSDataSyncLocationSmb_basic(t *testing.T) { CheckDestroy: testAccCheckAWSDataSyncLocationSmbDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSDataSyncLocationSmbConfig(rName), + Config: testAccAWSDataSyncLocationSmbConfig(rName, "/test/"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSDataSyncLocationSmbExists(resourceName, &locationSmb1), - testAccMatchResourceAttrRegionalARN(resourceName, "arn", "datasync", regexp.MustCompile(`location/loc-.+`)), resource.TestCheckResourceAttr(resourceName, "agent_arns.#", "1"), resource.TestCheckResourceAttr(resourceName, "mount_options.#", "1"), @@ -111,6 +109,19 @@ func TestAccAWSDataSyncLocationSmb_basic(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"password", "server_hostname"}, }, + { + Config: testAccAWSDataSyncLocationSmbConfig(rName, "/test2/"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDataSyncLocationSmbExists(resourceName, &locationSmb1), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "datasync", regexp.MustCompile(`location/loc-.+`)), + resource.TestCheckResourceAttr(resourceName, "agent_arns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "mount_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "mount_options.0.version", "AUTOMATIC"), + resource.TestCheckResourceAttr(resourceName, "user", "Guest"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestMatchResourceAttr(resourceName, "uri", regexp.MustCompile(`^smb://.+/`)), + ), + }, }, }) } @@ -127,7 +138,7 @@ func TestAccAWSDataSyncLocationSmb_disappears(t *testing.T) { CheckDestroy: testAccCheckAWSDataSyncLocationSmbDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSDataSyncLocationSmbConfig(rName), + Config: testAccAWSDataSyncLocationSmbConfig(rName, "/test/"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSDataSyncLocationSmbExists(resourceName, &locationSmb1), testAccCheckAWSDataSyncLocationSmbDisappears(&locationSmb1), @@ -357,16 +368,16 @@ resource "aws_datasync_agent" "test" { `, rName)) } -func testAccAWSDataSyncLocationSmbConfig(rName string) string { - return testAccAWSDataSyncLocationSmbConfigBase(rName) + ` +func testAccAWSDataSyncLocationSmbConfig(rName, dir string) string { + return testAccAWSDataSyncLocationSmbConfigBase(rName) + fmt.Sprintf(` resource "aws_datasync_location_smb" "test" { agent_arns = [aws_datasync_agent.test.arn] password = "ZaphodBeeblebroxPW" server_hostname = aws_instance.test.public_ip - subdirectory = "/test/" + subdirectory = %[1]q user = "Guest" } -` +`, dir) } func testAccAWSDataSyncLocationSmbConfigTags1(rName, key1, value1 string) string { From d3c934fecb320a15e9bd454e492ae9270c3dfcf5 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 10 Jun 2021 16:29:59 +0300 Subject: [PATCH 0368/1208] fmt --- aws/resource_aws_datasync_location_smb.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_datasync_location_smb.go b/aws/resource_aws_datasync_location_smb.go index 7da75cb9e2c1..ed0a76cb264d 100644 --- a/aws/resource_aws_datasync_location_smb.go +++ b/aws/resource_aws_datasync_location_smb.go @@ -227,7 +227,7 @@ func resourceAwsDataSyncLocationSmbUpdate(d *schema.ResourceData, meta interface o, n := d.GetChange("tags_all") if err := keyvaluetags.DatasyncUpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating Datasync SMB location (%s) tags: %s", d.Id(), err) + return fmt.Errorf("error updating Datasync SMB location (%s) tags: %w", d.Id(), err) } } return resourceAwsDataSyncLocationSmbRead(d, meta) @@ -248,7 +248,7 @@ func resourceAwsDataSyncLocationSmbDelete(d *schema.ResourceData, meta interface } if err != nil { - return fmt.Errorf("error deleting DataSync Location SMB (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting DataSync Location SMB (%s): %w", d.Id(), err) } return nil From 163da71b9c3b0b522ead33cb3622066535bf1fb6 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 10 Jun 2021 16:33:57 +0300 Subject: [PATCH 0369/1208] changelog --- .changelog/19753.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/19753.txt diff --git a/.changelog/19753.txt b/.changelog/19753.txt new file mode 100644 index 000000000000..50c2a41b0ce8 --- /dev/null +++ b/.changelog/19753.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_datasync_location_smb: Add support for updating. +``` + +```release-note:enhancement +resource/aws_datasync_location_smb: Add plan time validation for `domain`, `agent_arns`, `password`, `server_hostname`, `subdirectory`, and `user`. +``` \ No newline at end of file From 2c49a7052023f0f2a9c66e1fc275b208c32d11c6 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 10 Jun 2021 17:56:44 +0000 Subject: [PATCH 0370/1208] Update CHANGELOG.md for #19677 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cff56ce6295d..9d598713e018 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ BUG FIXES: * resource/aws_cloudwatch_event_target: Increase the maximum allowed value for the `input_transformer` `input_paths` argument to 100 ([#19703](https://github.com/hashicorp/terraform-provider-aws/issues/19703)) * resource/aws_cloudwatch_metric_alarm: Allow extended statistics in the `stat` argument of the `metric` configuration block ([#19668](https://github.com/hashicorp/terraform-provider-aws/issues/19668)) * resource/aws_cognito_user_pool_client: Fix plan time validation for `refresh_token_validity` ([#19702](https://github.com/hashicorp/terraform-provider-aws/issues/19702)) +* resource/aws_iot_topic_rule: Allow tags containing `@` character ([#19677](https://github.com/hashicorp/terraform-provider-aws/issues/19677)) * resource/aws_lambda_function: Prevents perpetual diff in `vpc_config` ([#17610](https://github.com/hashicorp/terraform-provider-aws/issues/17610)) * resource/aws_servicequotas_service_quota: Correctly handle errors embedded in API struct ([#19722](https://github.com/hashicorp/terraform-provider-aws/issues/19722)) * resource/aws_sqs_queue: Allow `visibility_timeout_seconds` to be `0` when creating queue ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) From f458bd42c7d14e83d633c887f6d2f2921d6467d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 18:37:39 +0000 Subject: [PATCH 0371/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.57 to 1.38.59 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.57 to 1.38.59. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.57...v1.38.59) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7d9462a24f76..a42f554c4865 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.57 + github.com/aws/aws-sdk-go v1.38.59 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index 5d5aec62196f..59d57865fd9a 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.57 h1:Jo6uOnWNbj4jL/8t/XUrHOKm1J6pPcYFhGzda20UcUk= -github.com/aws/aws-sdk-go v1.38.57/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.59 h1:rGEMmHdgXSjA2gkdo8Hdwai9mND5X0i+hZetYfABo7g= +github.com/aws/aws-sdk-go v1.38.59/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 7eda4ac5f977144e896a96bd8523158163035b6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 18:39:17 +0000 Subject: [PATCH 0372/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.56 to 1.38.59. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.56...v1.38.59) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 015c2da7b515..600f83ea5fcb 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.56 + github.com/aws/aws-sdk-go v1.38.59 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 196bd6be5e86..ea4c498586ec 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.56 h1:JI5bnuDfjVLgnBaDHeZO5btxGbYCQ5QA3P0maYtwPQw= -github.com/aws/aws-sdk-go v1.38.56/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.59 h1:rGEMmHdgXSjA2gkdo8Hdwai9mND5X0i+hZetYfABo7g= +github.com/aws/aws-sdk-go v1.38.59/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index e22e2afa6626..4626e63153af 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.56" +const SDKVersion = "1.38.59" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index d37080a0eaa9..f35e2530610e 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.56 +# github.com/aws/aws-sdk-go v1.38.59 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From a27213b6f73c378450e4513bf103ec498cd34b4e Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 23 Apr 2021 13:47:53 -0400 Subject: [PATCH 0373/1208] service/ec2: Support Private NAT Gateways Output from acceptance testing: ``` --- PASS: TestAccAWSNatGateway_ConnectivityType_Private (184.75s) --- PASS: TestAccAWSNatGateway_basic (232.08s) --- PASS: TestAccAWSNatGateway_tags (253.75s) --- PASS: TestAccDataSourceAwsNatGateway_basic (181.34s) ``` --- .changelog/pending.txt | 7 ++++ aws/data_source_aws_nat_gateway.go | 5 +++ aws/data_source_aws_nat_gateway_test.go | 1 + aws/resource_aws_nat_gateway.go | 26 ++++++++++++-- aws/resource_aws_nat_gateway_test.go | 46 ++++++++++++++++++++++++ website/docs/d/nat_gateway.html.markdown | 1 + website/docs/r/nat_gateway.html.markdown | 43 ++++++++++------------ 7 files changed, 101 insertions(+), 28 deletions(-) create mode 100644 .changelog/pending.txt diff --git a/.changelog/pending.txt b/.changelog/pending.txt new file mode 100644 index 000000000000..783b2aa12a41 --- /dev/null +++ b/.changelog/pending.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +data-source/aws_nat_gateway: Add `connectivity_type` attribute +``` + +```release-note:enhancement +resource/aws_nat_gateway: Add `connectivity_type` argument +``` diff --git a/aws/data_source_aws_nat_gateway.go b/aws/data_source_aws_nat_gateway.go index a04cabde0d15..dd28248e69f6 100644 --- a/aws/data_source_aws_nat_gateway.go +++ b/aws/data_source_aws_nat_gateway.go @@ -39,6 +39,10 @@ func dataSourceAwsNatGateway() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "connectivity_type": { + Type: schema.TypeString, + Computed: true, + }, "network_interface_id": { Type: schema.TypeString, Computed: true, @@ -121,6 +125,7 @@ func dataSourceAwsNatGatewayRead(d *schema.ResourceData, meta interface{}) error log.Printf("[DEBUG] NAT Gateway response: %s", ngw) d.SetId(aws.StringValue(ngw.NatGatewayId)) + d.Set("connectivity_type", ngw.ConnectivityType) d.Set("state", ngw.State) d.Set("subnet_id", ngw.SubnetId) d.Set("vpc_id", ngw.VpcId) diff --git a/aws/data_source_aws_nat_gateway_test.go b/aws/data_source_aws_nat_gateway_test.go index 138474e41bbe..2bae1302138b 100644 --- a/aws/data_source_aws_nat_gateway_test.go +++ b/aws/data_source_aws_nat_gateway_test.go @@ -21,6 +21,7 @@ func TestAccDataSourceAwsNatGateway_basic(t *testing.T) { { Config: testAccDataSourceAwsNatGatewayConfig(rInt), Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair("data.aws_nat_gateway.test_by_id", "connectivity_type", "aws_nat_gateway.test", "connectivity_type"), resource.TestCheckResourceAttrPair( "data.aws_nat_gateway.test_by_id", "id", "aws_nat_gateway.test", "id"), diff --git a/aws/resource_aws_nat_gateway.go b/aws/resource_aws_nat_gateway.go index 0fd8513ad0ce..a538ef0c4afa 100644 --- a/aws/resource_aws_nat_gateway.go +++ b/aws/resource_aws_nat_gateway.go @@ -11,6 +11,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" ) @@ -27,7 +28,7 @@ func resourceAwsNatGateway() *schema.Resource { Schema: map[string]*schema.Schema{ "allocation_id": { Type: schema.TypeString, - Required: true, + Optional: true, ForceNew: true, }, @@ -37,6 +38,14 @@ func resourceAwsNatGateway() *schema.Resource { ForceNew: true, }, + "connectivity_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: ec2.ConnectivityTypePublic, + ValidateFunc: validation.StringInSlice(ec2.ConnectivityType_Values(), false), + }, + "network_interface_id": { Type: schema.TypeString, Computed: true, @@ -67,11 +76,21 @@ func resourceAwsNatGatewayCreate(d *schema.ResourceData, meta interface{}) error // Create the NAT Gateway createOpts := &ec2.CreateNatGatewayInput{ - AllocationId: aws.String(d.Get("allocation_id").(string)), - SubnetId: aws.String(d.Get("subnet_id").(string)), TagSpecifications: ec2TagSpecificationsFromKeyValueTags(tags, ec2.ResourceTypeNatgateway), } + if v, ok := d.GetOk("allocation_id"); ok { + createOpts.AllocationId = aws.String(v.(string)) + } + + if v, ok := d.GetOk("connectivity_type"); ok { + createOpts.ConnectivityType = aws.String(v.(string)) + } + + if v, ok := d.GetOk("subnet_id"); ok { + createOpts.SubnetId = aws.String(v.(string)) + } + log.Printf("[DEBUG] Create NAT Gateway: %s", *createOpts) natResp, err := conn.CreateNatGateway(createOpts) if err != nil { @@ -124,6 +143,7 @@ func resourceAwsNatGatewayRead(d *schema.ResourceData, meta interface{}) error { // Set NAT Gateway attributes ng := ngRaw.(*ec2.NatGateway) + d.Set("connectivity_type", ng.ConnectivityType) d.Set("subnet_id", ng.SubnetId) // Address diff --git a/aws/resource_aws_nat_gateway_test.go b/aws/resource_aws_nat_gateway_test.go index 44389d8c5ed4..e7804fd3e86b 100644 --- a/aws/resource_aws_nat_gateway_test.go +++ b/aws/resource_aws_nat_gateway_test.go @@ -70,6 +70,7 @@ func TestAccAWSNatGateway_basic(t *testing.T) { Config: testAccNatGatewayConfig, Check: resource.ComposeTestCheckFunc( testAccCheckNatGatewayExists(resourceName, &natGateway), + resource.TestCheckResourceAttr(resourceName, "connectivity_type", "public"), resource.TestCheckResourceAttr(resourceName, "tags.#", "0"), ), }, @@ -82,6 +83,33 @@ func TestAccAWSNatGateway_basic(t *testing.T) { }) } +func TestAccAWSNatGateway_ConnectivityType_Private(t *testing.T) { + var natGateway ec2.NatGateway + resourceName := "aws_nat_gateway.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckNatGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccNatGatewayConfigConnectivityType("private"), + Check: resource.ComposeTestCheckFunc( + testAccCheckNatGatewayExists(resourceName, &natGateway), + resource.TestCheckResourceAttr(resourceName, "connectivity_type", "private"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSNatGateway_tags(t *testing.T) { var natGateway ec2.NatGateway resourceName := "aws_nat_gateway.test" @@ -239,6 +267,24 @@ resource "aws_nat_gateway" "test" { } ` +func testAccNatGatewayConfigConnectivityType(connectivityType string) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, 0) + vpc_id = aws_vpc.test.id +} + +resource "aws_nat_gateway" "test" { + connectivity_type = %[1]q + subnet_id = aws_subnet.test.id +} +`, connectivityType) +} + func testAccNatGatewayConfigTags1(tagKey1, tagValue1 string) string { return testAccNatGatewayConfigBase + fmt.Sprintf(` resource "aws_nat_gateway" "test" { diff --git a/website/docs/d/nat_gateway.html.markdown b/website/docs/d/nat_gateway.html.markdown index ab46bb1c75fc..54173f6de6a7 100644 --- a/website/docs/d/nat_gateway.html.markdown +++ b/website/docs/d/nat_gateway.html.markdown @@ -65,6 +65,7 @@ the selected Nat Gateway. Each attachment supports the following: * `allocation_id` - The Id of the EIP allocated to the selected Nat Gateway. +* `connectivity_type` - The connectivity type of the NAT Gateway. * `network_interface_id` - The Id of the ENI allocated to the selected Nat Gateway. * `private_ip` - The private Ip address of the selected Nat Gateway. * `public_ip` - The public Ip (EIP) address of the selected Nat Gateway. diff --git a/website/docs/r/nat_gateway.html.markdown b/website/docs/r/nat_gateway.html.markdown index 23539a7225a9..18ac92760a58 100644 --- a/website/docs/r/nat_gateway.html.markdown +++ b/website/docs/r/nat_gateway.html.markdown @@ -12,23 +12,29 @@ Provides a resource to create a VPC NAT Gateway. ## Example Usage -```terraform -resource "aws_nat_gateway" "gw" { - allocation_id = aws_eip.nat.id - subnet_id = aws_subnet.example.id -} -``` - -Usage with tags: +### Public NAT ```terraform -resource "aws_nat_gateway" "gw" { - allocation_id = aws_eip.nat.id +resource "aws_nat_gateway" "example" { + allocation_id = aws_eip.example.id subnet_id = aws_subnet.example.id tags = { Name = "gw NAT" } + + # To ensure proper ordering, it is recommended to add an explicit dependency + # on the Internet Gateway for the VPC. + depends_on = [aws_internet_gateway.example] +} +``` + +### Private NAT + +```terraform +resource "aws_nat_gateway" "example" { + connectivity_type = "private" + subnet_id = aws_subnet.example.id } ``` @@ -36,24 +42,11 @@ resource "aws_nat_gateway" "gw" { The following arguments are supported: -* `allocation_id` - (Required) The Allocation ID of the Elastic IP address for the gateway. +* `allocation_id` - (Optional) The Allocation ID of the Elastic IP address for the gateway. Required for `connectivity_type` of `public`. +* `connectivity_type` - (Optional) Connectivity type for the gateway. Valid values are `private` and `public`. Defaults to `public`. * `subnet_id` - (Required) The Subnet ID of the subnet in which to place the gateway. * `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. --> **Note:** It's recommended to denote that the NAT Gateway depends on the Internet Gateway for the VPC in which the NAT Gateway's subnet is located. For example: - -```terraform -resource "aws_internet_gateway" "gw" { - vpc_id = aws_vpc.main.id -} - -resource "aws_nat_gateway" "gw" { - # ... other arguments ... - - depends_on = [aws_internet_gateway.gw] -} -``` - ## Attributes Reference In addition to all arguments above, the following attributes are exported: From e87e6cd181b3a72fc4869692143df9dd851dd39d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 10 Jun 2021 15:02:08 -0400 Subject: [PATCH 0374/1208] Rename CHANGELOG entry file. --- .changelog/{pending.txt => 19758.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changelog/{pending.txt => 19758.txt} (100%) diff --git a/.changelog/pending.txt b/.changelog/19758.txt similarity index 100% rename from .changelog/pending.txt rename to .changelog/19758.txt From 89322cee504de4747cdc954edb6ee1ba4ecf50e1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 10 Jun 2021 15:12:37 -0400 Subject: [PATCH 0375/1208] Fix awsproviderlint error: 'AT010: prefer TestStep ImportState testing over TestCase IDRefreshName'. --- aws/resource_aws_nat_gateway_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_nat_gateway_test.go b/aws/resource_aws_nat_gateway_test.go index e7804fd3e86b..7c71f5e0f8a8 100644 --- a/aws/resource_aws_nat_gateway_test.go +++ b/aws/resource_aws_nat_gateway_test.go @@ -88,11 +88,10 @@ func TestAccAWSNatGateway_ConnectivityType_Private(t *testing.T) { resourceName := "aws_nat_gateway.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), - IDRefreshName: resourceName, - Providers: testAccProviders, - CheckDestroy: testAccCheckNatGatewayDestroy, + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckNatGatewayDestroy, Steps: []resource.TestStep{ { Config: testAccNatGatewayConfigConnectivityType("private"), From 2e43dec3c76a81fda6b9792346a249c4315848ad Mon Sep 17 00:00:00 2001 From: Ian Neubert Date: Thu, 10 Jun 2021 12:22:05 -0700 Subject: [PATCH 0376/1208] Move LaunchType tests into a single test run --- ...source_aws_cloudwatch_event_target_test.go | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target_test.go b/aws/resource_aws_cloudwatch_event_target_test.go index 2cb69481f25c..e738b3964b72 100644 --- a/aws/resource_aws_cloudwatch_event_target_test.go +++ b/aws/resource_aws_cloudwatch_event_target_test.go @@ -447,13 +447,6 @@ func TestAccAWSCloudWatchEventTarget_ecs(t *testing.T) { ImportStateIdFunc: testAccAWSCloudWatchEventTargetImportStateIdFunc(resourceName), ImportStateVerify: true, }, - { - Config: testAccAWSCloudWatchEventTargetConfigEcsWithBlankLaunchType(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckCloudWatchEventTargetExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "ecs_target.0.launch_type", ""), - ), - }, }, }) } @@ -490,6 +483,26 @@ func TestAccAWSCloudWatchEventTarget_ecsWithBlankLaunchType(t *testing.T) { ImportStateIdFunc: testAccAWSCloudWatchEventTargetImportStateIdFunc(resourceName), ImportStateVerify: true, }, + { + Config: testAccAWSCloudWatchEventTargetConfigEcs(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventTargetExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.launch_type", "FARGATE"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAWSCloudWatchEventTargetImportStateIdFunc(resourceName), + ImportStateVerify: true, + }, + { + Config: testAccAWSCloudWatchEventTargetConfigEcsWithBlankLaunchType(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventTargetExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.launch_type", ""), + ), + }, }, }) } From cdbe83be44bf6cd2a53c24f69a423b6bb8abf70f Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 10 Jun 2021 20:00:54 +0000 Subject: [PATCH 0377/1208] Update CHANGELOG.md for #19758 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d598713e018..5b7438833ff1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ FEATURES: ENHANCEMENTS: +* data-source/aws_nat_gateway: Add `connectivity_type` attribute ([#19758](https://github.com/hashicorp/terraform-provider-aws/issues/19758)) * data-source/aws_transfer_server: Add `domain` attribute. ([#19691](https://github.com/hashicorp/terraform-provider-aws/issues/19691)) * resource/aws_cognito_user_pool: Add `custom_domain`, `domain`, and `estimated_number_of_users` attributes ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) * resource/aws_cognito_user_pool: Add `custom_email_sender`, `custom_sms_sender`, and `kms_key_id` to `lambda_config` ([#16502](https://github.com/hashicorp/terraform-provider-aws/issues/16502)) @@ -20,6 +21,7 @@ ENHANCEMENTS: * resource/aws_ecs_task_definition: Add support for `ephemeral_storage`. ([#19694](https://github.com/hashicorp/terraform-provider-aws/issues/19694)) * resource/aws_ecs_task_definition: Add support for `fsx_windows_file_server_volume_configuration`. ([#19670](https://github.com/hashicorp/terraform-provider-aws/issues/19670)) * resource/aws_fsx_lustre_filesystem: Add `data_compression_type` argument. ([#19664](https://github.com/hashicorp/terraform-provider-aws/issues/19664)) +* resource/aws_nat_gateway: Add `connectivity_type` argument ([#19758](https://github.com/hashicorp/terraform-provider-aws/issues/19758)) * resource/aws_sqs_queue: Add `deduplication_scope` and `fifo_throughput_limit` arguments ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) * resource/aws_sqs_queue: Add `url` attribute ([#19639](https://github.com/hashicorp/terraform-provider-aws/issues/19639)) * resource/aws_transfer_server: Add `domain` argument. ([#19691](https://github.com/hashicorp/terraform-provider-aws/issues/19691)) From 4dc92e05c442da565fdac9a0d732095cc477dec5 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 10 Jun 2021 21:20:42 +0000 Subject: [PATCH 0378/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b7438833ff1..290b80e699c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ ENHANCEMENTS: * resource/aws_cur_report_definition: Add `arn` attribute. ([#19705](https://github.com/hashicorp/terraform-provider-aws/issues/19705)) * resource/aws_cur_report_definition: Add plan time validation for `report_name`. ([#19705](https://github.com/hashicorp/terraform-provider-aws/issues/19705)) * resource/aws_cur_report_definition: Support updating definition. ([#19705](https://github.com/hashicorp/terraform-provider-aws/issues/19705)) +* resource/aws_datasync_location_smb: Add plan time validation for `domain`, `agent_arns`, `password`, `server_hostname`, `subdirectory`, and `user`. ([#19753](https://github.com/hashicorp/terraform-provider-aws/issues/19753)) +* resource/aws_datasync_location_smb: Add support for updating. ([#19753](https://github.com/hashicorp/terraform-provider-aws/issues/19753)) * resource/aws_default_vpc_dhcp_options: Add `owner_id` argument. ([#19656](https://github.com/hashicorp/terraform-provider-aws/issues/19656)) * resource/aws_ecs_task_definition: Add plan time validation for `family` and `requires_compatibilities`. ([#19670](https://github.com/hashicorp/terraform-provider-aws/issues/19670)) * resource/aws_ecs_task_definition: Add support for `ephemeral_storage`. ([#19694](https://github.com/hashicorp/terraform-provider-aws/issues/19694)) @@ -34,6 +36,7 @@ BUG FIXES: * resource/aws_batch_job_definition: Suppress differences for empty `linuxParameters.devices` and `linuxParameters.tmpfs` arrays in the `container_properties` argument ([#19666](https://github.com/hashicorp/terraform-provider-aws/issues/19666)) * resource/aws_cloudwatch_event_target: Increase the maximum allowed value for the `input_transformer` `input_paths` argument to 100 ([#19703](https://github.com/hashicorp/terraform-provider-aws/issues/19703)) * resource/aws_cloudwatch_metric_alarm: Allow extended statistics in the `stat` argument of the `metric` configuration block ([#19668](https://github.com/hashicorp/terraform-provider-aws/issues/19668)) +* resource/aws_cognito_user_pool: Suppress diff for empty `account_recovery_setting`. ([#19704](https://github.com/hashicorp/terraform-provider-aws/issues/19704)) * resource/aws_cognito_user_pool_client: Fix plan time validation for `refresh_token_validity` ([#19702](https://github.com/hashicorp/terraform-provider-aws/issues/19702)) * resource/aws_iot_topic_rule: Allow tags containing `@` character ([#19677](https://github.com/hashicorp/terraform-provider-aws/issues/19677)) * resource/aws_lambda_function: Prevents perpetual diff in `vpc_config` ([#17610](https://github.com/hashicorp/terraform-provider-aws/issues/17610)) From c8b84aba1334f1543d417c00dab182576a252f25 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Thu, 10 Jun 2021 17:40:54 -0400 Subject: [PATCH 0379/1208] update documentation to reflect support for empty string --- website/docs/r/cloudwatch_event_target.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cloudwatch_event_target.html.markdown b/website/docs/r/cloudwatch_event_target.html.markdown index 4bb47f3e22a1..b3d6af4652bb 100644 --- a/website/docs/r/cloudwatch_event_target.html.markdown +++ b/website/docs/r/cloudwatch_event_target.html.markdown @@ -352,7 +352,7 @@ The following arguments are supported: `ecs_target` support the following: * `group` - (Optional) Specifies an ECS task group for the task. The maximum length is 255 characters. -* `launch_type` - (Optional) Specifies the launch type on which your task is running. The launch type that you specify here must match one of the launch type (compatibilities) of the target task. Valid values are `EC2` or `FARGATE`. +* `launch_type` - (Optional) Specifies the launch type on which your task is running. The launch type that you specify here must match one of the launch type (compatibilities) of the target task. Valid values include: an empty string `""` (to specify no launch type), `EC2`, or `FARGATE`. * `network_configuration` - (Optional) Use this if the ECS task uses the awsvpc network mode. This specifies the VPC subnets and security groups associated with the task, and whether a public IP address is to be used. Required if launch_type is FARGATE because the awsvpc mode is required for Fargate tasks. * `platform_version` - (Optional) Specifies the platform version for the task. Specify only the numeric portion of the platform version, such as 1.1.0. This is used only if LaunchType is FARGATE. For more information about valid platform versions, see [AWS Fargate Platform Versions](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html). * `task_count` - (Optional) The number of tasks to create based on the TaskDefinition. The default is 1. From 3cd58c8892d0c82931fd7979ebb3288dc8238325 Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Thu, 10 Jun 2021 22:13:03 +0000 Subject: [PATCH 0380/1208] v3.45.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 290b80e699c7..1a610d939313 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 3.45.0 (Unreleased) +## 3.45.0 (June 10, 2021) FEATURES: From c1630b35e0d18f674c60a6c72fb11bf451df64f2 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 10 Jun 2021 22:28:16 +0000 Subject: [PATCH 0381/1208] Update CHANGELOG.md after v3.45.0 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a610d939313..549be7a741bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## 3.46.0 (Unreleased) ## 3.45.0 (June 10, 2021) FEATURES: From 49aef8fd617ba5309eb7032c2bb2107bae1cbf00 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 11 Jun 2021 08:38:50 -0400 Subject: [PATCH 0382/1208] Add missing v3.45.0 CHANGELOG entry (#19555). --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 549be7a741bf..5fc30cfd1bb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ BUG FIXES: * data-source/aws_acmpca_certificate_authority: Fix `error setting tags` ([#19681](https://github.com/hashicorp/terraform-provider-aws/issues/19681)) * data-source/aws_servicequotas_service_quota: Correctly handle errors embedded in API struct ([#19722](https://github.com/hashicorp/terraform-provider-aws/issues/19722)) * resource/aws_batch_job_definition: Suppress differences for empty `linuxParameters.devices` and `linuxParameters.tmpfs` arrays in the `container_properties` argument ([#19666](https://github.com/hashicorp/terraform-provider-aws/issues/19666)) +* resource/aws_cloudwatch_event_target: Fix `ecs_target.launch_type` not allowing empty string values. ([#19703](https://github.com/hashicorp/terraform-provider-aws/issues/19555)) * resource/aws_cloudwatch_event_target: Increase the maximum allowed value for the `input_transformer` `input_paths` argument to 100 ([#19703](https://github.com/hashicorp/terraform-provider-aws/issues/19703)) * resource/aws_cloudwatch_metric_alarm: Allow extended statistics in the `stat` argument of the `metric` configuration block ([#19668](https://github.com/hashicorp/terraform-provider-aws/issues/19668)) * resource/aws_cognito_user_pool: Suppress diff for empty `account_recovery_setting`. ([#19704](https://github.com/hashicorp/terraform-provider-aws/issues/19704)) From e3999a4fc79a2a000192666f60034dc363857df2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 11 Jun 2021 08:46:24 -0400 Subject: [PATCH 0383/1208] r/aws_launch_configuration: Documentation category is 'Autoscaling' (as for the corresponding data source). --- website/docs/r/launch_configuration.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/launch_configuration.html.markdown b/website/docs/r/launch_configuration.html.markdown index ac2fed58bfd7..00360f2e35b7 100644 --- a/website/docs/r/launch_configuration.html.markdown +++ b/website/docs/r/launch_configuration.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "EC2" +subcategory: "Autoscaling" layout: "aws" page_title: "AWS: aws_launch_configuration" description: |- From 7247dd06a08d9647ac061d387e5a185ae948efe6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 11 Jun 2021 08:55:52 -0400 Subject: [PATCH 0384/1208] Add EC2 resources missing from issue labeler action. --- .github/labeler-issue-triage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/labeler-issue-triage.yml b/.github/labeler-issue-triage.yml index 5aa0a23b7fbd..17d21eb0dca0 100644 --- a/.github/labeler-issue-triage.yml +++ b/.github/labeler-issue-triage.yml @@ -141,7 +141,7 @@ service/docdb: service/dynamodb: - '((\*|-) ?`?|(data|resource) "?)aws_dynamodb_' service/ec2: - - '((\*|-) ?`?|(data|resource) "?)aws_(ami|availability_zone|customer_gateway|(default_)?(network_acl|route_table|security_group|subnet|vpc)|ebs_|ec2_|egress_only_internet_gateway|eip|flow_log|instance|internet_gateway|key_pair|launch_template|main_route_table_association|network_interface|placement_group|prefix_list|spot|route(\"|`|$)|vpn_|volume_attachment)' + - '((\*|-) ?`?|(data|resource) "?)aws_(ami|availability_zone|customer_gateway|(default_)?(network_acl|route_table|security_group|subnet|vpc)|ebs_|ec2_|egress_only_internet_gateway|eip|flow_log|instance|internet_gateway|key_pair|launch_template|main_route_table_association|nat_gateway|network_interface|placement_group|prefix_list|route(\"|`|$)|snapshot_create_volume_permission|spot|volume_attachment|vpn_)' service/ecr: - '((\*|-) ?`?|(data|resource) "?)aws_ecr_' service/ecrpublic: From 495536b08fb2aac1471d9221c8e01b6a429edebb Mon Sep 17 00:00:00 2001 From: Oscar Kent-Plummer Date: Thu, 24 Dec 2020 18:46:32 +0000 Subject: [PATCH 0385/1208] Use shared naming logic for ASG and Launch Configuration (name_prefix fix) --- aws/resource_aws_autoscaling_group.go | 31 +++---- aws/resource_aws_autoscaling_group_test.go | 75 ++++------------- aws/resource_aws_launch_configuration.go | 11 +-- aws/resource_aws_launch_configuration_test.go | 84 +++++++++++++------ .../docs/r/autoscaling_group.html.markdown | 2 +- .../docs/r/launch_configuration.html.markdown | 2 +- 6 files changed, 88 insertions(+), 117 deletions(-) diff --git a/aws/resource_aws_autoscaling_group.go b/aws/resource_aws_autoscaling_group.go index 16abd1f656c2..788fa1f1344e 100644 --- a/aws/resource_aws_autoscaling_group.go +++ b/aws/resource_aws_autoscaling_group.go @@ -25,6 +25,7 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/experimental/nullable" "github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/autoscaling/waiter" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" ) @@ -57,10 +58,11 @@ func resourceAwsAutoscalingGroup() *schema.Resource { ValidateFunc: validation.StringLenBetween(0, 255), }, "name_prefix": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ValidateFunc: validation.StringLenBetween(0, 255-resource.UniqueIDSuffixLength), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"name"}, + ValidateFunc: validation.StringLenBetween(0, 255-resource.UniqueIDSuffixLength), }, "launch_configuration": { @@ -641,17 +643,7 @@ func generatePutLifecycleHookInputs(asgName string, cfgs []interface{}) []autosc func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).autoscalingconn - var asgName string - if v, ok := d.GetOk("name"); ok { - asgName = v.(string) - } else { - if v, ok := d.GetOk("name_prefix"); ok { - asgName = resource.PrefixedUniqueId(v.(string)) - } else { - asgName = resource.PrefixedUniqueId("tf-asg-") - } - d.Set("name", asgName) - } + asgName := naming.Generate(d.Get("name").(string), d.Get("name_prefix").(string)) createOpts := autoscaling.CreateAutoScalingGroupInput{ AutoScalingGroupName: aws.String(asgName), @@ -711,14 +703,12 @@ func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) createOpts.AvailabilityZones = expandStringSet(v.(*schema.Set)) } - resourceID := d.Get("name").(string) - if v, ok := d.GetOk("tag"); ok { - createOpts.Tags = keyvaluetags.AutoscalingKeyValueTags(v, resourceID, autoscalingTagResourceTypeAutoScalingGroup).IgnoreAws().AutoscalingTags() + createOpts.Tags = keyvaluetags.AutoscalingKeyValueTags(v, asgName, autoscalingTagResourceTypeAutoScalingGroup).IgnoreAws().AutoscalingTags() } if v, ok := d.GetOk("tags"); ok { - createOpts.Tags = keyvaluetags.AutoscalingKeyValueTags(v, resourceID, autoscalingTagResourceTypeAutoScalingGroup).IgnoreAws().AutoscalingTags() + createOpts.Tags = keyvaluetags.AutoscalingKeyValueTags(v, asgName, autoscalingTagResourceTypeAutoScalingGroup).IgnoreAws().AutoscalingTags() } if v, ok := d.GetOk("capacity_rebalance"); ok { @@ -789,7 +779,7 @@ func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error creating Auto Scaling Group: %s", err) } - d.SetId(d.Get("name").(string)) + d.SetId(asgName) log.Printf("[INFO] Auto Scaling Group ID: %s", d.Id()) if twoPhases { @@ -891,6 +881,7 @@ func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) e } d.Set("name", g.AutoScalingGroupName) + d.Set("name_prefix", aws.StringValue(naming.NamePrefixFromName(aws.StringValue(g.AutoScalingGroupName)))) d.Set("placement_group", g.PlacementGroup) d.Set("protect_from_scale_in", g.NewInstancesProtectedFromScaleIn) d.Set("service_linked_role_arn", g.ServiceLinkedRoleARN) diff --git a/aws/resource_aws_autoscaling_group_test.go b/aws/resource_aws_autoscaling_group_test.go index b5208464a573..56c10aec21ee 100644 --- a/aws/resource_aws_autoscaling_group_test.go +++ b/aws/resource_aws_autoscaling_group_test.go @@ -18,6 +18,7 @@ import ( "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" ) func init() { @@ -145,7 +146,6 @@ func TestAccAWSAutoScalingGroup_basic(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -180,9 +180,7 @@ func TestAccAWSAutoScalingGroup_basic(t *testing.T) { }) } -func TestAccAWSAutoScalingGroup_namePrefix(t *testing.T) { - nameRegexp := regexp.MustCompile("^tf-test-") - +func TestAccAWSAutoScalingGroup_NamePrefix(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, autoscaling.EndpointsID), @@ -190,10 +188,10 @@ func TestAccAWSAutoScalingGroup_namePrefix(t *testing.T) { CheckDestroy: testAccCheckAWSAutoScalingGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAutoScalingGroupConfig_namePrefix(), + Config: testAccAWSAutoScalingGroupConfig_NamePrefix(), Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr( - "aws_autoscaling_group.test", "name", nameRegexp), + naming.TestCheckResourceAttrNameFromPrefix( + "aws_autoscaling_group.test", "name", "tf-test-"), resource.TestCheckResourceAttrSet( "aws_autoscaling_group.test", "arn"), ), @@ -205,7 +203,6 @@ func TestAccAWSAutoScalingGroup_namePrefix(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -216,9 +213,7 @@ func TestAccAWSAutoScalingGroup_namePrefix(t *testing.T) { }) } -func TestAccAWSAutoScalingGroup_autoGeneratedName(t *testing.T) { - asgNameRegexp := regexp.MustCompile("^tf-asg-") - +func TestAccAWSAutoScalingGroup_Name_Generated(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, autoscaling.EndpointsID), @@ -226,10 +221,10 @@ func TestAccAWSAutoScalingGroup_autoGeneratedName(t *testing.T) { CheckDestroy: testAccCheckAWSAutoScalingGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAutoScalingGroupConfig_autoGeneratedName(), + Config: testAccAWSAutoScalingGroupConfig_Name_Generated(), Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr( - "aws_autoscaling_group.bar", "name", asgNameRegexp), + naming.TestCheckResourceAttrNameGenerated( + "aws_autoscaling_group.bar", "name"), resource.TestCheckResourceAttrSet( "aws_autoscaling_group.bar", "arn"), ), @@ -241,7 +236,6 @@ func TestAccAWSAutoScalingGroup_autoGeneratedName(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -273,7 +267,6 @@ func TestAccAWSAutoScalingGroup_terminationPolicies(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -296,7 +289,6 @@ func TestAccAWSAutoScalingGroup_terminationPolicies(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -359,7 +351,6 @@ func TestAccAWSAutoScalingGroup_tags(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -416,7 +407,6 @@ func TestAccAWSAutoScalingGroup_VpcUpdates(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -462,7 +452,6 @@ func TestAccAWSAutoScalingGroup_WithLoadBalancer(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -498,7 +487,6 @@ func TestAccAWSAutoScalingGroup_WithLoadBalancer_ToTargetGroup(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -520,7 +508,6 @@ func TestAccAWSAutoScalingGroup_WithLoadBalancer_ToTargetGroup(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -542,7 +529,6 @@ func TestAccAWSAutoScalingGroup_WithLoadBalancer_ToTargetGroup(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -577,7 +563,6 @@ func TestAccAWSAutoScalingGroup_withPlacementGroup(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -613,7 +598,6 @@ func TestAccAWSAutoScalingGroup_enablingMetrics(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -665,7 +649,6 @@ func TestAccAWSAutoScalingGroup_suspendingProcesses(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -708,7 +691,6 @@ func TestAccAWSAutoScalingGroup_withMetrics(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -751,7 +733,6 @@ func TestAccAWSAutoScalingGroup_serviceLinkedRoleARN(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -786,7 +767,6 @@ func TestAccAWSAutoScalingGroup_MaxInstanceLifetime(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -866,7 +846,6 @@ func TestAccAWSAutoScalingGroup_ALB_TargetGroups(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -913,7 +892,6 @@ func TestAccAWSAutoScalingGroup_TargetGroupArns(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -969,7 +947,6 @@ func TestAccAWSAutoScalingGroup_initialLifecycleHook(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1007,7 +984,6 @@ func TestAccAWSAutoScalingGroup_ALB_TargetGroups_ELBCapacity(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1478,7 +1454,6 @@ func TestAccAWSAutoScalingGroup_classicVpcZoneIdentifier(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1513,7 +1488,6 @@ func TestAccAWSAutoScalingGroup_launchTemplate(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1548,7 +1522,6 @@ func TestAccAWSAutoScalingGroup_launchTemplate_update(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1626,7 +1599,6 @@ func TestAccAWSAutoScalingGroup_LaunchTemplate_IAMInstanceProfile(t *testing.T) ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1663,7 +1635,6 @@ func TestAccAWSAutoScalingGroup_LoadBalancers(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1721,7 +1692,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1766,7 +1736,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_CapacityRebalance(t *testin ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1804,7 +1773,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_OnDem ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1842,7 +1810,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_OnDem ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1899,7 +1866,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_Updat ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1922,7 +1888,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_Updat ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -1960,7 +1925,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_OnDem ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -2007,7 +1971,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_SpotA ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -2045,7 +2008,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_SpotI ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -2092,7 +2054,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_InstancesDistribution_SpotM ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -2149,7 +2110,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_LaunchTemplate_LaunchTempla ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -2188,7 +2148,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_LaunchTemplate_LaunchTempla ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -2238,7 +2197,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_LaunchTemplate_Override_Ins ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -2334,7 +2292,6 @@ func TestAccAWSAutoScalingGroup_MixedInstancesPolicy_LaunchTemplate_Override_Wei ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -2369,7 +2326,6 @@ func TestAccAWSAutoScalingGroup_launchTempPartitionNum(t *testing.T) { ImportStateVerifyIgnore: []string{ "force_delete", "initial_lifecycle_hook", - "name_prefix", "tag", "tags", "wait_for_capacity_timeout", @@ -2380,8 +2336,8 @@ func TestAccAWSAutoScalingGroup_launchTempPartitionNum(t *testing.T) { }) } -func testAccAWSAutoScalingGroupConfig_autoGeneratedName() string { - return composeConfig(testAccAvailableAZsNoOptInDefaultExcludeConfig(), ` +func testAccAWSAutoScalingGroupConfig_Name_Generated() string { + return composeConfig(testAccAvailableAZsNoOptInDefaultExcludeConfig(), fmt.Sprintf(` data "aws_ami" "test_ami" { most_recent = true owners = ["amazon"] @@ -2404,12 +2360,11 @@ resource "aws_autoscaling_group" "bar" { min_size = 0 launch_configuration = aws_launch_configuration.foobar.name } -`) +`)) } -func testAccAWSAutoScalingGroupConfig_namePrefix() string { - return composeConfig(testAccAvailableAZsNoOptInDefaultExcludeConfig(), - ` +func testAccAWSAutoScalingGroupConfig_NamePrefix() string { + return composeConfig(testAccAvailableAZsNoOptInDefaultExcludeConfig(), fmt.Sprintf(` data "aws_ami" "test_ami" { most_recent = true owners = ["amazon"] @@ -2433,7 +2388,7 @@ resource "aws_autoscaling_group" "test" { name_prefix = "tf-test-" launch_configuration = aws_launch_configuration.test.name } -`) +`)) } func testAccAWSAutoScalingGroupConfig_terminationPoliciesEmpty() string { diff --git a/aws/resource_aws_launch_configuration.go b/aws/resource_aws_launch_configuration.go index f111f6e76be2..88e0a8c0bf85 100644 --- a/aws/resource_aws_launch_configuration.go +++ b/aws/resource_aws_launch_configuration.go @@ -13,6 +13,7 @@ import ( "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/hashcode" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" ) @@ -524,14 +525,7 @@ func resourceAwsLaunchConfigurationCreate(d *schema.ResourceData, meta interface createLaunchConfigurationOpts.BlockDeviceMappings = blockDevices } - var lcName string - if v, ok := d.GetOk("name"); ok { - lcName = v.(string) - } else if v, ok := d.GetOk("name_prefix"); ok { - lcName = resource.PrefixedUniqueId(v.(string)) - } else { - lcName = resource.UniqueId() - } + lcName := naming.Generate(d.Get("name").(string), d.Get("name_prefix").(string)) createLaunchConfigurationOpts.LaunchConfigurationName = aws.String(lcName) log.Printf("[DEBUG] autoscaling create launch configuration: %s", createLaunchConfigurationOpts) @@ -596,6 +590,7 @@ func resourceAwsLaunchConfigurationRead(d *schema.ResourceData, meta interface{} d.Set("image_id", lc.ImageId) d.Set("instance_type", lc.InstanceType) d.Set("name", lc.LaunchConfigurationName) + d.Set("name_prefix", aws.StringValue(naming.NamePrefixFromName(aws.StringValue(lc.LaunchConfigurationName)))) d.Set("arn", lc.LaunchConfigurationARN) d.Set("iam_instance_profile", lc.IamInstanceProfile) diff --git a/aws/resource_aws_launch_configuration_test.go b/aws/resource_aws_launch_configuration_test.go index e7ff3eb4ac44..c0577c7e0fd8 100644 --- a/aws/resource_aws_launch_configuration_test.go +++ b/aws/resource_aws_launch_configuration_test.go @@ -13,6 +13,7 @@ import ( "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" ) func init() { @@ -74,10 +75,9 @@ func TestAccAWSLaunchConfiguration_basic(t *testing.T) { CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLaunchConfigurationNoNameConfig(), + Config: testAccAWSLaunchConfigurationConfig(), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLaunchConfigurationExists(resourceName, &conf), - testAccCheckAWSLaunchConfigurationGeneratedNamePrefix(resourceName, "terraform-"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "autoscaling", regexp.MustCompile(`launchConfiguration:.+`)), ), }, @@ -87,13 +87,61 @@ func TestAccAWSLaunchConfiguration_basic(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"associate_public_ip_address"}, }, + }, + }) +} + +func TestAccAWSLaunchConfiguration_NamePrefix(t *testing.T) { + var conf autoscaling.LaunchConfiguration + resourceName := "aws_launch_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLaunchConfigurationNamePrefixConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLaunchConfigurationExists(resourceName, &conf), + naming.TestCheckResourceAttrNameFromPrefix( + resourceName, "name", "tf-acc-test-"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"associate_public_ip_address"}, + }, + }, + }) +} + +func TestAccAWSLaunchConfiguration_Name_Generated(t *testing.T) { + var conf autoscaling.LaunchConfiguration + resourceName := "aws_launch_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy, + Steps: []resource.TestStep{ { - Config: testAccAWSLaunchConfigurationPrefixNameConfig(), + Config: testAccAWSLaunchConfigurationNameGeneratedConfig(), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLaunchConfigurationExists(resourceName, &conf), - testAccCheckAWSLaunchConfigurationGeneratedNamePrefix(resourceName, "tf-acc-test-"), + naming.TestCheckResourceAttrNameGenerated( + resourceName, "name"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "autoscaling", regexp.MustCompile(`launchConfiguration:.+`)), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"associate_public_ip_address"}, + }, }, }) } @@ -210,7 +258,7 @@ func TestAccAWSLaunchConfiguration_RootBlockDevice_VolumeSize(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"associate_public_ip_address", "name_prefix"}, + ImportStateVerifyIgnore: []string{"associate_public_ip_address"}, }, { Config: testAccAWSLaunchConfigurationConfigWithRootBlockDeviceVolumeSize(rName, 20), @@ -245,7 +293,7 @@ func TestAccAWSLaunchConfiguration_encryptedRootBlockDevice(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"associate_public_ip_address", "name_prefix"}, + ImportStateVerifyIgnore: []string{"associate_public_ip_address"}, }, }, }) @@ -488,7 +536,7 @@ func TestAccAWSLaunchConfiguration_ebs_noDevice(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"associate_public_ip_address", "name_prefix"}, + ImportStateVerifyIgnore: []string{"associate_public_ip_address"}, }, }, }) @@ -554,24 +602,6 @@ func testAccCheckAWSLaunchConfigurationWithEncryption(conf *autoscaling.LaunchCo } } -func testAccCheckAWSLaunchConfigurationGeneratedNamePrefix( - resource, prefix string) resource.TestCheckFunc { - return func(s *terraform.State) error { - r, ok := s.RootModule().Resources[resource] - if !ok { - return fmt.Errorf("Resource not found") - } - name, ok := r.Primary.Attributes["name"] - if !ok { - return fmt.Errorf("Name attr not found: %#v", r.Primary.Attributes) - } - if !strings.HasPrefix(name, prefix) { - return fmt.Errorf("Name: %q, does not have prefix: %q", name, prefix) - } - return nil - } -} - func testAccCheckAWSLaunchConfigurationDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).autoscalingconn @@ -823,7 +853,7 @@ resource "aws_launch_configuration" "test" { `, acctest.RandInt())) } -func testAccAWSLaunchConfigurationNoNameConfig() string { +func testAccAWSLaunchConfigurationNameGeneratedConfig() string { return composeConfig(testAccLatestAmazonLinuxHvmEbsAmiConfig(), ` resource "aws_launch_configuration" "test" { image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id @@ -834,7 +864,7 @@ resource "aws_launch_configuration" "test" { `) } -func testAccAWSLaunchConfigurationPrefixNameConfig() string { +func testAccAWSLaunchConfigurationNamePrefixConfig() string { return composeConfig(testAccLatestAmazonLinuxHvmEbsAmiConfig(), ` resource "aws_launch_configuration" "test" { name_prefix = "tf-acc-test-" diff --git a/website/docs/r/autoscaling_group.html.markdown b/website/docs/r/autoscaling_group.html.markdown index e2bbe96b555e..c6ed0cac317b 100644 --- a/website/docs/r/autoscaling_group.html.markdown +++ b/website/docs/r/autoscaling_group.html.markdown @@ -334,7 +334,7 @@ resource "aws_autoscaling_group" "example" { The following arguments are supported: -* `name` - (Optional) The name of the Auto Scaling Group. By default generated by Terraform. +* `name` - (Optional) The name of the Auto Scaling Group. By default generated by Terraform. Conflicts with `name_prefix`. * `name_prefix` - (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `name`. * `max_size` - (Required) The maximum size of the Auto Scaling Group. diff --git a/website/docs/r/launch_configuration.html.markdown b/website/docs/r/launch_configuration.html.markdown index 00360f2e35b7..2686c98a062f 100644 --- a/website/docs/r/launch_configuration.html.markdown +++ b/website/docs/r/launch_configuration.html.markdown @@ -136,7 +136,7 @@ resource "aws_autoscaling_group" "bar" { The following arguments are supported: * `name` - (Optional) The name of the launch configuration. If you leave - this blank, Terraform will auto-generate a unique name. + this blank, Terraform will auto-generate a unique name. Conflicts with `name_prefix`. * `name_prefix` - (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `name`. * `image_id` - (Required) The EC2 image ID to launch. From d82cff5d92751da05e0e6a3236d0e92343bf35db Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 11 Jun 2021 10:17:46 -0400 Subject: [PATCH 0386/1208] .github/workflows: Fix waiting-response label removal Reference: https://github.com/hashicorp/terraform-provider-aws/labels/waiting-response --- .github/workflows/issue-comment-created.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issue-comment-created.yml b/.github/workflows/issue-comment-created.yml index b8c4d6bfacc1..ff2256754927 100644 --- a/.github/workflows/issue-comment-created.yml +++ b/.github/workflows/issue-comment-created.yml @@ -12,4 +12,4 @@ jobs: with: labels: | stale - waiting-reply + waiting-response From f4464d547b2dc73514ac500977d31f34e0580a09 Mon Sep 17 00:00:00 2001 From: brodster2 Date: Fri, 11 Jun 2021 15:31:17 +0100 Subject: [PATCH 0387/1208] Add missing 'status' attribute to organizations datasource docs --- website/docs/d/organizations_organization.html.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/d/organizations_organization.html.markdown b/website/docs/d/organizations_organization.html.markdown index b40f4f9c8a85..e3928229e46b 100644 --- a/website/docs/d/organizations_organization.html.markdown +++ b/website/docs/d/organizations_organization.html.markdown @@ -91,6 +91,7 @@ If the account is the master account for the organization, the following attribu * `email` - Email of the account * `id` - Identifier of the account * `name` - Name of the account + * `status` - Status of the account * `aws_service_access_principals` - A list of AWS service principal names that have integration enabled with your organization. Organization must have `feature_set` set to `ALL`. For additional information, see the [AWS Organizations User Guide](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_integrate_services.html). * `enabled_policy_types` - A list of Organizations policy types that are enabled in the Organization Root. Organization must have `feature_set` set to `ALL`. For additional information about valid policy types (e.g. `SERVICE_CONTROL_POLICY`), see the [AWS Organizations API Reference](https://docs.aws.amazon.com/organizations/latest/APIReference/API_EnablePolicyType.html). * `non_master_accounts` - List of organization accounts excluding the master account. For a list including the master account, see the `accounts` attribute. All elements have these attributes: @@ -98,6 +99,7 @@ If the account is the master account for the organization, the following attribu * `email` - Email of the account * `id` - Identifier of the account * `name` - Name of the account + * `status` - Status of the account * `roots` - List of organization roots. All elements have these attributes: * `arn` - ARN of the root * `id` - Identifier of the root From faf3d0122086ecac16116dddb528cab20296338f Mon Sep 17 00:00:00 2001 From: Phil Nichol <35630607+philnichol@users.noreply.github.com> Date: Fri, 11 Jun 2021 15:44:23 +0100 Subject: [PATCH 0388/1208] added virtual service data source --- ...data_source_aws_appmesh_virtual_service.go | 147 +++++++++++++++++ ...source_aws_appmesh_virtual_service_test.go | 151 ++++++++++++++++++ aws/provider.go | 1 + .../d/appmesh_virtual_service.html.markdown | 66 ++++++++ 4 files changed, 365 insertions(+) create mode 100644 aws/data_source_aws_appmesh_virtual_service.go create mode 100644 aws/data_source_aws_appmesh_virtual_service_test.go create mode 100644 website/docs/d/appmesh_virtual_service.html.markdown diff --git a/aws/data_source_aws_appmesh_virtual_service.go b/aws/data_source_aws_appmesh_virtual_service.go new file mode 100644 index 000000000000..8954223d0fbf --- /dev/null +++ b/aws/data_source_aws_appmesh_virtual_service.go @@ -0,0 +1,147 @@ +package aws + +import ( + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func dataSourceAwsAppmeshVirtualService() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsAppmeshVirtualServiceRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + + "last_updated_date": { + Type: schema.TypeString, + Computed: true, + }, + + "mesh_name": { + Type: schema.TypeString, + Required: true, + }, + + "mesh_owner": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "name": { + Type: schema.TypeString, + Required: true, + }, + + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, + + "spec": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "provider": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_node": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_node_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "virtual_router": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_router_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + + "tags": tagsSchema(), + }, + } +} + +func dataSourceAwsAppmeshVirtualServiceRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appmeshconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + req := &appmesh.DescribeVirtualServiceInput{ + MeshName: aws.String(d.Get("mesh_name").(string)), + VirtualServiceName: aws.String(d.Get("name").(string)), + } + + if v, ok := d.GetOk("mesh_owner"); ok { + req.MeshOwner = aws.String(v.(string)) + } + + resp, err := conn.DescribeVirtualService(req) + if err != nil { + return fmt.Errorf("error reading App Mesh Virtual Service: %s", err) + } + + arn := aws.StringValue(resp.VirtualService.Metadata.Arn) + + d.SetId(aws.StringValue(resp.VirtualService.VirtualServiceName)) + + d.Set("name", resp.VirtualService.VirtualServiceName) + d.Set("mesh_name", resp.VirtualService.MeshName) + d.Set("mesh_owner", resp.VirtualService.Metadata.MeshOwner) + d.Set("arn", arn) + d.Set("created_date", resp.VirtualService.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", resp.VirtualService.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("resource_owner", resp.VirtualService.Metadata.ResourceOwner) + + err = d.Set("spec", flattenAppmeshVirtualServiceSpec(resp.VirtualService.Spec)) + if err != nil { + return fmt.Errorf("error setting spec: %s", err) + } + + tags, err := keyvaluetags.AppmeshListTags(conn, arn) + + if err != nil { + return fmt.Errorf("error listing tags for App Mesh Virtual Service (%s): %s", arn, err) + } + + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} diff --git a/aws/data_source_aws_appmesh_virtual_service_test.go b/aws/data_source_aws_appmesh_virtual_service_test.go new file mode 100644 index 000000000000..280d31df6454 --- /dev/null +++ b/aws/data_source_aws_appmesh_virtual_service_test.go @@ -0,0 +1,151 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSAppmeshVirtualServiceDataSource_virtualNode(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appmesh_virtual_service.test" + dataSourceName := "data.aws_appmesh_virtual_service.test" + vsName := fmt.Sprintf("tf-acc-test-%d.mesh.local", acctest.RandInt()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, appmesh.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppmeshVirtualServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsAppmeshVirtualServiceDataSourceConfig_virtualNode(rName, vsName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_name", dataSourceName, "mesh_name"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.provider.0.virtual_node.0.virtual_node_name", dataSourceName, "spec.0.provider.0.virtual_node.0.virtual_node_name"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + +func TestAccAWSAppmeshVirtualServiceDataSource_virtualRouter(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appmesh_virtual_service.test" + dataSourceName := "data.aws_appmesh_virtual_service.test" + vsName := fmt.Sprintf("tf-acc-test-%d.mesh.local", acctest.RandInt()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, appmesh.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppmeshVirtualServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsAppmeshVirtualServiceDataSourceConfig_virtualRouter(rName, vsName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_name", dataSourceName, "mesh_name"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.provider.0.virtual_router.0.virtual_router_name", dataSourceName, "spec.0.provider.0.virtual_router.0.virtual_router_name"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + +func testAccCheckAwsAppmeshVirtualServiceDataSourceConfig_virtualNode(rName, vsName string) string { + return fmt.Sprintf(` +resource "aws_appmesh_mesh" "test" { + name = %[1]q +} + +resource "aws_appmesh_virtual_node" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + + spec {} +} + +resource "aws_appmesh_virtual_service" "test" { + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + provider { + virtual_node { + virtual_node_name = aws_appmesh_virtual_node.test.name + } + } + } + + tags = { + foo = "bar" + good = "bad" + } +} + +data "aws_appmesh_virtual_service" "test" { + name = aws_appmesh_virtual_service.test.name + mesh_name = aws_appmesh_mesh.test.name +} +`, rName, vsName) +} + +func testAccCheckAwsAppmeshVirtualServiceDataSourceConfig_virtualRouter(rName, vsName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_appmesh_mesh" "test" { + name = %[1]q +} + +resource "aws_appmesh_virtual_router" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + listener { + port_mapping { + port = 8080 + protocol = "http" + } + } + } +} + +resource "aws_appmesh_virtual_service" "test" { + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + provider { + virtual_router { + virtual_router_name = aws_appmesh_virtual_router.test.name + } + } + } +} + +data "aws_appmesh_virtual_service" "test" { + name = aws_appmesh_virtual_service.test.name + mesh_name = aws_appmesh_mesh.test.name + mesh_owner = data.aws_caller_identity.current.account_id +} +`, rName, vsName) +} diff --git a/aws/provider.go b/aws/provider.go index 90a101318462..4a6c3d71bce6 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -197,6 +197,7 @@ func Provider() *schema.Provider { "aws_apigatewayv2_api": dataSourceAwsApiGatewayV2Api(), "aws_apigatewayv2_apis": dataSourceAwsApiGatewayV2Apis(), "aws_appmesh_mesh": dataSourceAwsAppmeshMesh(), + "aws_appmesh_virtual_service": dataSourceAwsAppmeshVirtualService(), "aws_arn": dataSourceAwsArn(), "aws_autoscaling_group": dataSourceAwsAutoscalingGroup(), "aws_autoscaling_groups": dataSourceAwsAutoscalingGroups(), diff --git a/website/docs/d/appmesh_virtual_service.html.markdown b/website/docs/d/appmesh_virtual_service.html.markdown new file mode 100644 index 000000000000..eb7766c46d3f --- /dev/null +++ b/website/docs/d/appmesh_virtual_service.html.markdown @@ -0,0 +1,66 @@ +--- +subcategory: "AppMesh" +layout: "aws" +page_title: "AWS: aws_appmesh_virtual_service" +description: |- + Provides an AWS App Mesh virtual service resource. +--- + +# Data Source: aws_appmesh_virtual_service + +The App Mesh Virtual Service data source allows details of an App Mesh Virtual Service to be retrieved by its name, mesh_name, and optionally the mesh_owner. + +## Example Usage + +```hcl +data "aws_appmesh_virtual_service" "test" { + name = "example.mesh.local" + mesh_name = "example-mesh" +} +``` + +```hcl +data "aws_caller_identity" "current" {} + +data "aws_appmesh_virtual_service" "test" { + name = "example.mesh.local" + mesh_name = "example-mesh" + mesh_owner = data.aws_caller_identity.current.account_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the virtual service. +* `mesh_name` - (Required) The name of the service mesh in which the virtual service exists. +* `mesh_owner` - (Optional) The AWS account ID of the service mesh's owner. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The ARN of the virtual service. +* `created_date` - The creation date of the virtual service. +* `last_updated_date` - The last update date of the virtual service. +* `resource_owner` - The resource owner's AWS account ID. +* `spec` - The virtual service specification +* `tags` - A map of tags. + +### Spec + +* `provider` - The App Mesh object that is acting as the provider for a virtual service. + +### Provider + +* `virtual_node` - The virtual node associated with the virtual service. +* `virtual_router` - The virtual router associated with the virtual service. + +### Virtual Node + +* `virtual_node_name` - The name of the virtual node that is acting as a service provider. + +### Virtual Router + +* `virtual_router_name` - The name of the virtual router that is acting as a service provider. From 66a3904353818106ce5cb494bc512a797d2b360f Mon Sep 17 00:00:00 2001 From: Phil Nichol <35630607+philnichol@users.noreply.github.com> Date: Fri, 11 Jun 2021 15:51:42 +0100 Subject: [PATCH 0389/1208] added note for changelog --- .changelog/19774.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19774.txt diff --git a/.changelog/19774.txt b/.changelog/19774.txt new file mode 100644 index 000000000000..a4268e1737ad --- /dev/null +++ b/.changelog/19774.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_appmesh_virtual_service +``` From b89836aa3d1347b6035ceb766b78b6e5c0ebc13c Mon Sep 17 00:00:00 2001 From: Phil Nichol <35630607+philnichol@users.noreply.github.com> Date: Fri, 11 Jun 2021 16:19:46 +0100 Subject: [PATCH 0390/1208] fix terrafmt errors --- ...source_aws_appmesh_virtual_service_test.go | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/aws/data_source_aws_appmesh_virtual_service_test.go b/aws/data_source_aws_appmesh_virtual_service_test.go index 280d31df6454..365a3bf0ea8b 100644 --- a/aws/data_source_aws_appmesh_virtual_service_test.go +++ b/aws/data_source_aws_appmesh_virtual_service_test.go @@ -72,37 +72,37 @@ func TestAccAWSAppmeshVirtualServiceDataSource_virtualRouter(t *testing.T) { func testAccCheckAwsAppmeshVirtualServiceDataSourceConfig_virtualNode(rName, vsName string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { - name = %[1]q + name = %[1]q } - + resource "aws_appmesh_virtual_node" "test" { - name = %[1]q - mesh_name = aws_appmesh_mesh.test.id - - spec {} + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + + spec {} } - + resource "aws_appmesh_virtual_service" "test" { - name = %[2]q - mesh_name = aws_appmesh_mesh.test.id - - spec { - provider { - virtual_node { - virtual_node_name = aws_appmesh_virtual_node.test.name - } - } - } - - tags = { + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + provider { + virtual_node { + virtual_node_name = aws_appmesh_virtual_node.test.name + } + } + } + + tags = { foo = "bar" good = "bad" - } + } } data "aws_appmesh_virtual_service" "test" { - name = aws_appmesh_virtual_service.test.name - mesh_name = aws_appmesh_mesh.test.name + name = aws_appmesh_virtual_service.test.name + mesh_name = aws_appmesh_mesh.test.name } `, rName, vsName) } @@ -112,9 +112,9 @@ func testAccCheckAwsAppmeshVirtualServiceDataSourceConfig_virtualRouter(rName, v data "aws_caller_identity" "current" {} resource "aws_appmesh_mesh" "test" { - name = %[1]q + name = %[1]q } - + resource "aws_appmesh_virtual_router" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -128,22 +128,22 @@ resource "aws_appmesh_virtual_router" "test" { } } } - + resource "aws_appmesh_virtual_service" "test" { - name = %[2]q - mesh_name = aws_appmesh_mesh.test.id - - spec { - provider { - virtual_router { - virtual_router_name = aws_appmesh_virtual_router.test.name - } - } - } + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + provider { + virtual_router { + virtual_router_name = aws_appmesh_virtual_router.test.name + } + } + } } data "aws_appmesh_virtual_service" "test" { - name = aws_appmesh_virtual_service.test.name + name = aws_appmesh_virtual_service.test.name mesh_name = aws_appmesh_mesh.test.name mesh_owner = data.aws_caller_identity.current.account_id } From a174d4bf9f498d74d6fdd3e068f2780a4668a0ae Mon Sep 17 00:00:00 2001 From: Phil Nichol <35630607+philnichol@users.noreply.github.com> Date: Fri, 11 Jun 2021 16:24:23 +0100 Subject: [PATCH 0391/1208] fixed terrafmt error --- website/docs/d/appmesh_virtual_service.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/d/appmesh_virtual_service.html.markdown b/website/docs/d/appmesh_virtual_service.html.markdown index eb7766c46d3f..cab1b5201cad 100644 --- a/website/docs/d/appmesh_virtual_service.html.markdown +++ b/website/docs/d/appmesh_virtual_service.html.markdown @@ -14,8 +14,8 @@ The App Mesh Virtual Service data source allows details of an App Mesh Virtual S ```hcl data "aws_appmesh_virtual_service" "test" { - name = "example.mesh.local" - mesh_name = "example-mesh" + name = "example.mesh.local" + mesh_name = "example-mesh" } ``` @@ -23,7 +23,7 @@ data "aws_appmesh_virtual_service" "test" { data "aws_caller_identity" "current" {} data "aws_appmesh_virtual_service" "test" { - name = "example.mesh.local" + name = "example.mesh.local" mesh_name = "example-mesh" mesh_owner = data.aws_caller_identity.current.account_id } From 597a344b3dd8561b8510f11eb7af4f8b1f6b48e0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 11 Jun 2021 11:39:06 -0400 Subject: [PATCH 0392/1208] 'name_prefix' is Computed. --- aws/resource_aws_autoscaling_group.go | 34 ++++---- aws/resource_aws_autoscaling_group_test.go | 82 ++++++++----------- aws/resource_aws_launch_configuration.go | 11 +-- aws/resource_aws_launch_configuration_test.go | 39 ++++----- 4 files changed, 73 insertions(+), 93 deletions(-) diff --git a/aws/resource_aws_autoscaling_group.go b/aws/resource_aws_autoscaling_group.go index 788fa1f1344e..dcbb4805b10b 100644 --- a/aws/resource_aws_autoscaling_group.go +++ b/aws/resource_aws_autoscaling_group.go @@ -57,25 +57,26 @@ func resourceAwsAutoscalingGroup() *schema.Resource { ConflictsWith: []string{"name_prefix"}, ValidateFunc: validation.StringLenBetween(0, 255), }, + "name_prefix": { Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: true, ConflictsWith: []string{"name"}, ValidateFunc: validation.StringLenBetween(0, 255-resource.UniqueIDSuffixLength), }, "launch_configuration": { - Type: schema.TypeString, - Optional: true, - ConflictsWith: []string{"launch_template"}, + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{"launch_configuration", "launch_template", "mixed_instances_policy"}, }, "launch_template": { - Type: schema.TypeList, - MaxItems: 1, - Optional: true, - ConflictsWith: []string{"launch_configuration"}, + Type: schema.TypeList, + MaxItems: 1, + Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { @@ -99,6 +100,7 @@ func resourceAwsAutoscalingGroup() *schema.Resource { }, }, }, + ExactlyOneOf: []string{"launch_configuration", "launch_template", "mixed_instances_policy"}, }, "mixed_instances_policy": { @@ -235,6 +237,7 @@ func resourceAwsAutoscalingGroup() *schema.Resource { }, }, }, + ExactlyOneOf: []string{"launch_configuration", "launch_template", "mixed_instances_policy"}, }, "capacity_rebalance": { @@ -679,20 +682,13 @@ func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) } } - launchConfigurationValue, launchConfigurationOk := d.GetOk("launch_configuration") - launchTemplateValue, launchTemplateOk := d.GetOk("launch_template") - - if createOpts.MixedInstancesPolicy == nil && !launchConfigurationOk && !launchTemplateOk { - return fmt.Errorf("One of `launch_configuration`, `launch_template`, or `mixed_instances_policy` must be set for an Auto Scaling Group") - } - - if launchConfigurationOk { - createOpts.LaunchConfigurationName = aws.String(launchConfigurationValue.(string)) + if v, ok := d.GetOk("launch_configuration"); ok { + createOpts.LaunchConfigurationName = aws.String(v.(string)) } - if launchTemplateOk { + if v, ok := d.GetOk("launch_template"); ok { var err error - createOpts.LaunchTemplate, err = expandLaunchTemplateSpecification(launchTemplateValue.([]interface{})) + createOpts.LaunchTemplate, err = expandLaunchTemplateSpecification(v.([]interface{})) if err != nil { return err } @@ -881,7 +877,7 @@ func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) e } d.Set("name", g.AutoScalingGroupName) - d.Set("name_prefix", aws.StringValue(naming.NamePrefixFromName(aws.StringValue(g.AutoScalingGroupName)))) + d.Set("name_prefix", naming.NamePrefixFromName(aws.StringValue(g.AutoScalingGroupName))) d.Set("placement_group", g.PlacementGroup) d.Set("protect_from_scale_in", g.NewInstancesProtectedFromScaleIn) d.Set("service_linked_role_arn", g.ServiceLinkedRoleARN) diff --git a/aws/resource_aws_autoscaling_group_test.go b/aws/resource_aws_autoscaling_group_test.go index 56c10aec21ee..62897a65e9fb 100644 --- a/aws/resource_aws_autoscaling_group_test.go +++ b/aws/resource_aws_autoscaling_group_test.go @@ -180,7 +180,10 @@ func TestAccAWSAutoScalingGroup_basic(t *testing.T) { }) } -func TestAccAWSAutoScalingGroup_NamePrefix(t *testing.T) { +func TestAccAWSAutoScalingGroup_Name_Generated(t *testing.T) { + var group autoscaling.Group + resourceName := "aws_autoscaling_group.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, autoscaling.EndpointsID), @@ -188,12 +191,11 @@ func TestAccAWSAutoScalingGroup_NamePrefix(t *testing.T) { CheckDestroy: testAccCheckAWSAutoScalingGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAutoScalingGroupConfig_NamePrefix(), + Config: testAccAWSAutoScalingGroupConfigNameGenerated(), Check: resource.ComposeTestCheckFunc( - naming.TestCheckResourceAttrNameFromPrefix( - "aws_autoscaling_group.test", "name", "tf-test-"), - resource.TestCheckResourceAttrSet( - "aws_autoscaling_group.test", "arn"), + testAccCheckAWSAutoScalingGroupExists(resourceName, &group), + naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), ), }, { @@ -213,7 +215,10 @@ func TestAccAWSAutoScalingGroup_NamePrefix(t *testing.T) { }) } -func TestAccAWSAutoScalingGroup_Name_Generated(t *testing.T) { +func TestAccAWSAutoScalingGroup_NamePrefix(t *testing.T) { + var group autoscaling.Group + resourceName := "aws_autoscaling_group.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, autoscaling.EndpointsID), @@ -221,16 +226,15 @@ func TestAccAWSAutoScalingGroup_Name_Generated(t *testing.T) { CheckDestroy: testAccCheckAWSAutoScalingGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAutoScalingGroupConfig_Name_Generated(), + Config: testAccAWSAutoScalingGroupConfigNamePrefix("tf-acc-test-prefix-"), Check: resource.ComposeTestCheckFunc( - naming.TestCheckResourceAttrNameGenerated( - "aws_autoscaling_group.bar", "name"), - resource.TestCheckResourceAttrSet( - "aws_autoscaling_group.bar", "arn"), + testAccCheckAWSAutoScalingGroupExists(resourceName, &group), + naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), ), }, { - ResourceName: "aws_autoscaling_group.bar", + ResourceName: "aws_autoscaling_group.test", ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{ @@ -2336,59 +2340,43 @@ func TestAccAWSAutoScalingGroup_launchTempPartitionNum(t *testing.T) { }) } -func testAccAWSAutoScalingGroupConfig_Name_Generated() string { - return composeConfig(testAccAvailableAZsNoOptInDefaultExcludeConfig(), fmt.Sprintf(` -data "aws_ami" "test_ami" { - most_recent = true - owners = ["amazon"] - - filter { - name = "name" - values = ["amzn-ami-hvm-*-x86_64-gp2"] - } -} - -resource "aws_launch_configuration" "foobar" { - image_id = data.aws_ami.test_ami.id +func testAccAWSAutoScalingGroupConfigNameGenerated() string { + return composeConfig( + testAccAvailableAZsNoOptInDefaultExcludeConfig(), + testAccLatestAmazonLinuxHvmEbsAmiConfig(), + ` +resource "aws_launch_configuration" "test" { + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id instance_type = "t2.micro" } -resource "aws_autoscaling_group" "bar" { +resource "aws_autoscaling_group" "test" { availability_zones = [data.aws_availability_zones.available.names[0]] - desired_capacity = 0 max_size = 0 min_size = 0 - launch_configuration = aws_launch_configuration.foobar.name -} -`)) + launch_configuration = aws_launch_configuration.test.name } - -func testAccAWSAutoScalingGroupConfig_NamePrefix() string { - return composeConfig(testAccAvailableAZsNoOptInDefaultExcludeConfig(), fmt.Sprintf(` -data "aws_ami" "test_ami" { - most_recent = true - owners = ["amazon"] - - filter { - name = "name" - values = ["amzn-ami-hvm-*-x86_64-gp2"] - } +`) } +func testAccAWSAutoScalingGroupConfigNamePrefix(namePrefix string) string { + return composeConfig( + testAccAvailableAZsNoOptInDefaultExcludeConfig(), + testAccLatestAmazonLinuxHvmEbsAmiConfig(), + fmt.Sprintf(` resource "aws_launch_configuration" "test" { - image_id = data.aws_ami.test_ami.id + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id instance_type = "t2.micro" } resource "aws_autoscaling_group" "test" { availability_zones = [data.aws_availability_zones.available.names[0]] - desired_capacity = 0 max_size = 0 min_size = 0 - name_prefix = "tf-test-" + name_prefix = %[1]q launch_configuration = aws_launch_configuration.test.name } -`)) +`, namePrefix)) } func testAccAWSAutoScalingGroupConfig_terminationPoliciesEmpty() string { diff --git a/aws/resource_aws_launch_configuration.go b/aws/resource_aws_launch_configuration.go index 88e0a8c0bf85..18f290219805 100644 --- a/aws/resource_aws_launch_configuration.go +++ b/aws/resource_aws_launch_configuration.go @@ -31,6 +31,7 @@ func resourceAwsLaunchConfiguration() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "name": { Type: schema.TypeString, Optional: true, @@ -43,6 +44,7 @@ func resourceAwsLaunchConfiguration() *schema.Resource { "name_prefix": { Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: true, ConflictsWith: []string{"name"}, ValidateFunc: validation.StringLenBetween(1, 255-resource.UniqueIDSuffixLength), @@ -351,8 +353,10 @@ func resourceAwsLaunchConfigurationCreate(d *schema.ResourceData, meta interface autoscalingconn := meta.(*AWSClient).autoscalingconn ec2conn := meta.(*AWSClient).ec2conn + lcName := naming.Generate(d.Get("name").(string), d.Get("name_prefix").(string)) + createLaunchConfigurationOpts := autoscaling.CreateLaunchConfigurationInput{ - LaunchConfigurationName: aws.String(d.Get("name").(string)), + LaunchConfigurationName: aws.String(lcName), ImageId: aws.String(d.Get("image_id").(string)), InstanceType: aws.String(d.Get("instance_type").(string)), EbsOptimized: aws.Bool(d.Get("ebs_optimized").(bool)), @@ -525,9 +529,6 @@ func resourceAwsLaunchConfigurationCreate(d *schema.ResourceData, meta interface createLaunchConfigurationOpts.BlockDeviceMappings = blockDevices } - lcName := naming.Generate(d.Get("name").(string), d.Get("name_prefix").(string)) - createLaunchConfigurationOpts.LaunchConfigurationName = aws.String(lcName) - log.Printf("[DEBUG] autoscaling create launch configuration: %s", createLaunchConfigurationOpts) // IAM profiles can take ~10 seconds to propagate in AWS: @@ -590,7 +591,7 @@ func resourceAwsLaunchConfigurationRead(d *schema.ResourceData, meta interface{} d.Set("image_id", lc.ImageId) d.Set("instance_type", lc.InstanceType) d.Set("name", lc.LaunchConfigurationName) - d.Set("name_prefix", aws.StringValue(naming.NamePrefixFromName(aws.StringValue(lc.LaunchConfigurationName)))) + d.Set("name_prefix", naming.NamePrefixFromName(aws.StringValue(lc.LaunchConfigurationName))) d.Set("arn", lc.LaunchConfigurationARN) d.Set("iam_instance_profile", lc.IamInstanceProfile) diff --git a/aws/resource_aws_launch_configuration_test.go b/aws/resource_aws_launch_configuration_test.go index c0577c7e0fd8..df69f5ad6fda 100644 --- a/aws/resource_aws_launch_configuration_test.go +++ b/aws/resource_aws_launch_configuration_test.go @@ -91,7 +91,7 @@ func TestAccAWSLaunchConfiguration_basic(t *testing.T) { }) } -func TestAccAWSLaunchConfiguration_NamePrefix(t *testing.T) { +func TestAccAWSLaunchConfiguration_Name_Generated(t *testing.T) { var conf autoscaling.LaunchConfiguration resourceName := "aws_launch_configuration.test" @@ -101,11 +101,11 @@ func TestAccAWSLaunchConfiguration_NamePrefix(t *testing.T) { CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLaunchConfigurationNamePrefixConfig(), + Config: testAccAWSLaunchConfigurationConfigNameGenerated(), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLaunchConfigurationExists(resourceName, &conf), - naming.TestCheckResourceAttrNameFromPrefix( - resourceName, "name", "tf-acc-test-"), + naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), ), }, { @@ -118,7 +118,7 @@ func TestAccAWSLaunchConfiguration_NamePrefix(t *testing.T) { }) } -func TestAccAWSLaunchConfiguration_Name_Generated(t *testing.T) { +func TestAccAWSLaunchConfiguration_NamePrefix(t *testing.T) { var conf autoscaling.LaunchConfiguration resourceName := "aws_launch_configuration.test" @@ -128,12 +128,11 @@ func TestAccAWSLaunchConfiguration_Name_Generated(t *testing.T) { CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLaunchConfigurationNameGeneratedConfig(), + Config: testAccAWSLaunchConfigurationConfigNamePrefix("tf-acc-test-prefix-"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLaunchConfigurationExists(resourceName, &conf), - naming.TestCheckResourceAttrNameGenerated( - resourceName, "name"), - testAccMatchResourceAttrRegionalARN(resourceName, "arn", "autoscaling", regexp.MustCompile(`launchConfiguration:.+`)), + naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), ), }, { @@ -853,27 +852,23 @@ resource "aws_launch_configuration" "test" { `, acctest.RandInt())) } -func testAccAWSLaunchConfigurationNameGeneratedConfig() string { +func testAccAWSLaunchConfigurationConfigNameGenerated() string { return composeConfig(testAccLatestAmazonLinuxHvmEbsAmiConfig(), ` resource "aws_launch_configuration" "test" { - image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id - instance_type = "t2.micro" - user_data = "testtest-user-data-change" - associate_public_ip_address = false + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = "t2.micro" } `) } -func testAccAWSLaunchConfigurationNamePrefixConfig() string { - return composeConfig(testAccLatestAmazonLinuxHvmEbsAmiConfig(), ` +func testAccAWSLaunchConfigurationConfigNamePrefix(namePrefix string) string { + return composeConfig(testAccLatestAmazonLinuxHvmEbsAmiConfig(), fmt.Sprintf(` resource "aws_launch_configuration" "test" { - name_prefix = "tf-acc-test-" - image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id - instance_type = "t2.micro" - user_data = "testtest-user-data-change" - associate_public_ip_address = false + name_prefix = %[1]q + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = "t2.micro" } -`) +`, namePrefix)) } func testAccAWSLaunchConfigurationWithEncryption() string { From 6fc31579662124de664423c511fc6d300bffb251 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 11 Jun 2021 12:08:03 -0400 Subject: [PATCH 0393/1208] fix awsproviderlint error: 'XAT001: missing ErrorCheck'. --- aws/resource_aws_launch_configuration_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aws/resource_aws_launch_configuration_test.go b/aws/resource_aws_launch_configuration_test.go index df69f5ad6fda..ae4384abc907 100644 --- a/aws/resource_aws_launch_configuration_test.go +++ b/aws/resource_aws_launch_configuration_test.go @@ -97,6 +97,7 @@ func TestAccAWSLaunchConfiguration_Name_Generated(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, autoscaling.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy, Steps: []resource.TestStep{ @@ -124,6 +125,7 @@ func TestAccAWSLaunchConfiguration_NamePrefix(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, autoscaling.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy, Steps: []resource.TestStep{ From 3c8f36d9d7381791e8e691068b343afd6855a78f Mon Sep 17 00:00:00 2001 From: Eric Kinolik Date: Fri, 11 Jun 2021 12:45:44 -0700 Subject: [PATCH 0394/1208] Docs use incorrect argument for on_premises_instance_tag_filter --- website/docs/r/codedeploy_deployment_group.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/codedeploy_deployment_group.html.markdown b/website/docs/r/codedeploy_deployment_group.html.markdown index 9e3eca1b98dd..e15ca1a01b09 100644 --- a/website/docs/r/codedeploy_deployment_group.html.markdown +++ b/website/docs/r/codedeploy_deployment_group.html.markdown @@ -331,9 +331,9 @@ The `test_traffic_route` configuration block supports the following: * `listener_arns` - (Required) List of Amazon Resource Names (ARNs) of the load balancer listeners. -### on_premises_tag_filter Argument Reference +### on_premises_instance_tag_filter Argument Reference -The `on_premises_tag_filter` configuration block supports the following: +The `on_premises_instance_tag_filter` configuration block supports the following: * `key` - (Optional) The key of the tag filter. * `type` - (Optional) The type of the tag filter, either `KEY_ONLY`, `VALUE_ONLY`, or `KEY_AND_VALUE`. From 41ca3a38af7dda987bc5fd13016f090e48e61793 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 11 Jun 2021 12:48:52 +0300 Subject: [PATCH 0395/1208] add mount_options and validations --- aws/resource_aws_datasync_location_nfs.go | 66 +++++++++++++++++++++-- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_datasync_location_nfs.go b/aws/resource_aws_datasync_location_nfs.go index f73404988ae7..33c953b71187 100644 --- a/aws/resource_aws_datasync_location_nfs.go +++ b/aws/resource_aws_datasync_location_nfs.go @@ -38,7 +38,28 @@ func resourceAwsDataSyncLocationNfs() *schema.Resource { Type: schema.TypeSet, Required: true, ForceNew: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateArn, + }, + }, + }, + }, + }, + "mount_options": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "version": { + Type: schema.TypeString, + Default: datasync.NfsVersionAutomatic, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(datasync.NfsVersion_Values(), false), }, }, }, @@ -47,12 +68,13 @@ func resourceAwsDataSyncLocationNfs() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validation.NoZeroValues, + ValidateFunc: validation.StringLenBetween(1, 255), }, "subdirectory": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 4096), // Ignore missing trailing slash DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { if new == "/" { @@ -88,6 +110,10 @@ func resourceAwsDataSyncLocationNfsCreate(d *schema.ResourceData, meta interface Tags: tags.IgnoreAws().DatasyncTags(), } + if v, ok := d.GetOk("mount_options"); ok { + input.MountOptions = expandDataSyncNfsMountOptions(v.([]interface{})) + } + log.Printf("[DEBUG] Creating DataSync Location NFS: %s", input) output, err := conn.CreateLocationNfs(input) if err != nil { @@ -133,6 +159,10 @@ func resourceAwsDataSyncLocationNfsRead(d *schema.ResourceData, meta interface{} return fmt.Errorf("error setting on_prem_config: %s", err) } + if err := d.Set("mount_options", flattenDataSyncNfsMountOptions(output.MountOptions)); err != nil { + return fmt.Errorf("error setting mount_options: %s", err) + } + d.Set("subdirectory", subdirectory) d.Set("uri", output.LocationUri) @@ -190,3 +220,29 @@ func resourceAwsDataSyncLocationNfsDelete(d *schema.ResourceData, meta interface return nil } + +func expandDataSyncNfsMountOptions(l []interface{}) *datasync.NfsMountOptions { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + nfsMountOptions := &datasync.NfsMountOptions{ + Version: aws.String(m["version"].(string)), + } + + return nfsMountOptions +} + +func flattenDataSyncNfsMountOptions(mountOptions *datasync.NfsMountOptions) []interface{} { + if mountOptions == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "version": aws.StringValue(mountOptions.Version), + } + + return []interface{}{m} +} From 70cfa997db18116a00323323eedaff8b12ad4784 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 11 Jun 2021 13:10:29 +0300 Subject: [PATCH 0396/1208] add support for update --- aws/resource_aws_datasync_location_nfs.go | 36 +++++--- ...resource_aws_datasync_location_nfs_test.go | 84 ++++++++++++++++--- 2 files changed, 97 insertions(+), 23 deletions(-) diff --git a/aws/resource_aws_datasync_location_nfs.go b/aws/resource_aws_datasync_location_nfs.go index 33c953b71187..33a48542a068 100644 --- a/aws/resource_aws_datasync_location_nfs.go +++ b/aws/resource_aws_datasync_location_nfs.go @@ -30,7 +30,6 @@ func resourceAwsDataSyncLocationNfs() *schema.Resource { "on_prem_config": { Type: schema.TypeList, Required: true, - ForceNew: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -49,7 +48,6 @@ func resourceAwsDataSyncLocationNfs() *schema.Resource { "mount_options": { Type: schema.TypeList, Optional: true, - ForceNew: true, MaxItems: 1, DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, Elem: &schema.Resource{ @@ -73,7 +71,6 @@ func resourceAwsDataSyncLocationNfs() *schema.Resource { "subdirectory": { Type: schema.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 4096), // Ignore missing trailing slash DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { @@ -117,7 +114,7 @@ func resourceAwsDataSyncLocationNfsCreate(d *schema.ResourceData, meta interface log.Printf("[DEBUG] Creating DataSync Location NFS: %s", input) output, err := conn.CreateLocationNfs(input) if err != nil { - return fmt.Errorf("error creating DataSync Location NFS: %s", err) + return fmt.Errorf("error creating DataSync Location NFS: %w", err) } d.SetId(aws.StringValue(output.LocationArn)) @@ -144,23 +141,23 @@ func resourceAwsDataSyncLocationNfsRead(d *schema.ResourceData, meta interface{} } if err != nil { - return fmt.Errorf("error reading DataSync Location NFS (%s): %s", d.Id(), err) + return fmt.Errorf("error reading DataSync Location NFS (%s): %w", d.Id(), err) } subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri)) if err != nil { - return fmt.Errorf("error parsing Location NFS (%s) URI (%s): %s", d.Id(), aws.StringValue(output.LocationUri), err) + return fmt.Errorf("error parsing Location NFS (%s) URI (%s): %w", d.Id(), aws.StringValue(output.LocationUri), err) } d.Set("arn", output.LocationArn) if err := d.Set("on_prem_config", flattenDataSyncOnPremConfig(output.OnPremConfig)); err != nil { - return fmt.Errorf("error setting on_prem_config: %s", err) + return fmt.Errorf("error setting on_prem_config: %w", err) } if err := d.Set("mount_options", flattenDataSyncNfsMountOptions(output.MountOptions)); err != nil { - return fmt.Errorf("error setting mount_options: %s", err) + return fmt.Errorf("error setting mount_options: %w", err) } d.Set("subdirectory", subdirectory) @@ -169,7 +166,7 @@ func resourceAwsDataSyncLocationNfsRead(d *schema.ResourceData, meta interface{} tags, err := keyvaluetags.DatasyncListTags(conn, d.Id()) if err != nil { - return fmt.Errorf("error listing tags for DataSync Location NFS (%s): %s", d.Id(), err) + return fmt.Errorf("error listing tags for DataSync Location NFS (%s): %w", d.Id(), err) } tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -189,11 +186,28 @@ func resourceAwsDataSyncLocationNfsRead(d *schema.ResourceData, meta interface{} func resourceAwsDataSyncLocationNfsUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).datasyncconn + if d.HasChangesExcept("tags_all", "tags") { + input := &datasync.UpdateLocationNfsInput{ + LocationArn: aws.String(d.Id()), + OnPremConfig: expandDataSyncOnPremConfig(d.Get("on_prem_config").([]interface{})), + Subdirectory: aws.String(d.Get("subdirectory").(string)), + } + + if v, ok := d.GetOk("mount_options"); ok { + input.MountOptions = expandDataSyncNfsMountOptions(v.([]interface{})) + } + + _, err := conn.UpdateLocationNfs(input) + if err != nil { + return fmt.Errorf("error updating DataSync Location NFS (%s): %w", d.Id(), err) + } + } + if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") if err := keyvaluetags.DatasyncUpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating DataSync Location NFS (%s) tags: %s", d.Id(), err) + return fmt.Errorf("error updating DataSync Location NFS (%s) tags: %w", d.Id(), err) } } @@ -215,7 +229,7 @@ func resourceAwsDataSyncLocationNfsDelete(d *schema.ResourceData, meta interface } if err != nil { - return fmt.Errorf("error deleting DataSync Location NFS (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting DataSync Location NFS (%s): %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_datasync_location_nfs_test.go b/aws/resource_aws_datasync_location_nfs_test.go index 008d61096703..009e36eeb775 100644 --- a/aws/resource_aws_datasync_location_nfs_test.go +++ b/aws/resource_aws_datasync_location_nfs_test.go @@ -34,38 +34,37 @@ func testSweepDataSyncLocationNfss(region string) error { output, err := conn.ListLocations(input) if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping DataSync Location EFS sweep for %s: %s", region, err) + log.Printf("[WARN] Skipping DataSync Location Nfs sweep for %s: %s", region, err) return nil } if err != nil { - return fmt.Errorf("Error retrieving DataSync Location EFSs: %s", err) + return fmt.Errorf("Error retrieving DataSync Location Nfss: %s", err) } if len(output.Locations) == 0 { - log.Print("[DEBUG] No DataSync Location EFSs to sweep") + log.Print("[DEBUG] No DataSync Location Nfss to sweep") return nil } for _, location := range output.Locations { uri := aws.StringValue(location.LocationUri) if !strings.HasPrefix(uri, "nfs://") { - log.Printf("[INFO] Skipping DataSync Location EFS: %s", uri) + log.Printf("[INFO] Skipping DataSync Location Nfs: %s", uri) continue } - log.Printf("[INFO] Deleting DataSync Location EFS: %s", uri) - input := &datasync.DeleteLocationInput{ - LocationArn: location.LocationArn, - } - - _, err := conn.DeleteLocation(input) + log.Printf("[INFO] Deleting DataSync Location Nfs: %s", uri) + r := resourceAwsDataSyncLocationNfs() + d := r.Data(nil) + d.SetId(aws.StringValue(location.LocationArn)) + err = r.Delete(d, client) if isAWSErr(err, "InvalidRequestException", "not found") { continue } if err != nil { - log.Printf("[ERROR] Failed to delete DataSync Location EFS (%s): %s", uri, err) + log.Printf("[ERROR] Failed to delete DataSync Location Nfs (%s): %s", uri, err) } } @@ -97,6 +96,8 @@ func TestAccAWSDataSyncLocationNfs_basic(t *testing.T) { testAccMatchResourceAttrRegionalARN(resourceName, "arn", "datasync", regexp.MustCompile(`location/loc-.+`)), resource.TestCheckResourceAttr(resourceName, "on_prem_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "on_prem_config.0.agent_arns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "mount_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "mount_options.0.version", "AUTOMATIC"), resource.TestCheckResourceAttr(resourceName, "server_hostname", "example.com"), resource.TestCheckResourceAttr(resourceName, "subdirectory", "/"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), @@ -113,6 +114,41 @@ func TestAccAWSDataSyncLocationNfs_basic(t *testing.T) { }) } +func TestAccAWSDataSyncLocationNfs_mountOptions(t *testing.T) { + var locationNfs1 datasync.DescribeLocationNfsOutput + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_datasync_location_nfs.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSDataSync(t) }, + ErrorCheck: testAccErrorCheck(t, datasync.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDataSyncLocationNfsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDataSyncLocationNfsConfigMountOptions(rName, "NFS4_0"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDataSyncLocationNfsExists(resourceName, &locationNfs1), + resource.TestCheckResourceAttr(resourceName, "mount_options.0.version", "NFS4_0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"server_hostname"}, + }, + { + Config: testAccAWSDataSyncLocationNfsConfigMountOptions(rName, "NFS4_1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDataSyncLocationNfsExists(resourceName, &locationNfs1), + resource.TestCheckResourceAttr(resourceName, "mount_options.0.version", "NFS4_1"), + ), + }, + }, + }) +} + func TestAccAWSDataSyncLocationNfs_disappears(t *testing.T) { var locationNfs1 datasync.DescribeLocationNfsOutput rName := acctest.RandomWithPrefix("tf-acc-test") @@ -189,6 +225,13 @@ func TestAccAWSDataSyncLocationNfs_Subdirectory(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"server_hostname"}, }, + { + Config: testAccAWSDataSyncLocationNfsConfigSubdirectory(rName, "/subdirectory2/"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDataSyncLocationNfsExists(resourceName, &locationNfs1), + resource.TestCheckResourceAttr(resourceName, "subdirectory", "/subdirectory2/"), + ), + }, }, }) } @@ -312,7 +355,7 @@ func testAccCheckAWSDataSyncLocationNfsDisappears(location *datasync.DescribeLoc func testAccCheckAWSDataSyncLocationNfsNotRecreated(i, j *datasync.DescribeLocationNfsOutput) resource.TestCheckFunc { return func(s *terraform.State) error { if !aws.TimeValue(i.CreationTime).Equal(aws.TimeValue(j.CreationTime)) { - return errors.New("DataSync Location EFS was recreated") + return errors.New("DataSync Location Nfs was recreated") } return nil @@ -432,6 +475,23 @@ resource "aws_datasync_location_nfs" "test" { ` } +func testAccAWSDataSyncLocationNfsConfigMountOptions(rName, option string) string { + return testAccAWSDataSyncLocationNfsConfigBase(rName) + fmt.Sprintf(` +resource "aws_datasync_location_nfs" "test" { + server_hostname = "example.com" + subdirectory = "/" + + on_prem_config { + agent_arns = [aws_datasync_agent.test.arn] + } + + mount_options { + version = %[1]q + } +} +`, option) +} + func testAccAWSDataSyncLocationNfsConfigAgentArnsMultiple(rName string) string { return testAccAWSDataSyncLocationNfsConfigBase(rName) + fmt.Sprintf(` resource "aws_instance" "test2" { From 30cbf988095459d1dd5af3aa0c17e92c19469acd Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 11 Jun 2021 13:14:12 +0300 Subject: [PATCH 0397/1208] changelog --- .changelog/19767.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changelog/19767.txt diff --git a/.changelog/19767.txt b/.changelog/19767.txt new file mode 100644 index 000000000000..512a178dfcb6 --- /dev/null +++ b/.changelog/19767.txt @@ -0,0 +1,11 @@ +```release-note:enhancement +resource/aws_datasync_location_nfs: Add support for updating. +``` + +```release-note:enhancement +resource/aws_datasync_location_nfs: Add `mount_options` argument. +``` + +```release-note:enhancement +resource/aws_datasync_location_nfs: Add plan time validation for `on_prem_config.agent_arns`, `server_hostname`, and `subdirectory`. +``` \ No newline at end of file From 9685f84f2c8ade91d740229bd3702184589dca3b Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 11 Jun 2021 16:46:16 +0300 Subject: [PATCH 0398/1208] docs --- website/docs/r/datasync_location_nfs.html.markdown | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/website/docs/r/datasync_location_nfs.html.markdown b/website/docs/r/datasync_location_nfs.html.markdown index af8ffddac582..1dc7814a0dad 100644 --- a/website/docs/r/datasync_location_nfs.html.markdown +++ b/website/docs/r/datasync_location_nfs.html.markdown @@ -29,11 +29,18 @@ resource "aws_datasync_location_nfs" "example" { The following arguments are supported: +* `mount_options` - (Optional) Configuration block containing mount options used by DataSync to access the NFS Server. * `on_prem_config` - (Required) Configuration block containing information for connecting to the NFS File System. * `server_hostname` - (Required) Specifies the IP address or DNS name of the NFS server. The DataSync Agent(s) use this to mount the NFS server. * `subdirectory` - (Required) Subdirectory to perform actions as source or destination. Should be exported by the NFS server. * `tags` - (Optional) Key-value pairs of resource tags to assign to the DataSync Location. 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. +### mount_options Argument Reference + +The following arguments are supported inside the `mount_options` configuration block: + +* `version` - (Optional) The specific NFS version that you want DataSync to use for mounting your NFS share. Valid values: `AUTOMATIC`, `NFS3`, `NFS4_0` and `NFS4_1`. Default: `AUTOMATIC` + ### on_prem_config Argument Reference The following arguments are supported inside the `on_prem_config` configuration block: From ae759569427615140613f560616bd208b6021dc0 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 13 Jun 2021 00:37:05 +0300 Subject: [PATCH 0399/1208] add support for config --- aws/resource_aws_ecs_cluster.go | 236 ++++++++++++++++++++++++--- aws/resource_aws_ecs_cluster_test.go | 66 ++++++++ 2 files changed, 279 insertions(+), 23 deletions(-) diff --git a/aws/resource_aws_ecs_cluster.go b/aws/resource_aws_ecs_cluster.go index 5f8913603fca..e9cad024d7bc 100644 --- a/aws/resource_aws_ecs_cluster.go +++ b/aws/resource_aws_ecs_cluster.go @@ -36,9 +36,10 @@ func resourceAwsEcsCluster() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, "arn": { Type: schema.TypeString, @@ -51,6 +52,62 @@ func resourceAwsEcsCluster() *schema.Resource { Type: schema.TypeString, }, }, + "configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "execute_command_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + }, + "log_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cloud_watch_encryption_enabled": { + Type: schema.TypeBool, + Optional: true, + }, + "cloud_watch_log_group_name": { + Type: schema.TypeString, + Optional: true, + }, + "s3_bucket_name": { + Type: schema.TypeString, + Optional: true, + }, + "s3_bucket_encryption_enabled": { + Type: schema.TypeBool, + Optional: true, + }, + "s3_key_prefix": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "logging": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(ecs.ExecuteCommandLogging_Values(), false), + }, + }, + }, + }, + }, + }, + }, "default_capacity_provider_strategy": { Type: schema.TypeSet, Optional: true, @@ -82,11 +139,9 @@ func resourceAwsEcsCluster() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.ClusterSettingNameContainerInsights, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(ecs.ClusterSettingName_Values(), false), }, "value": { Type: schema.TypeString, @@ -135,6 +190,10 @@ func resourceAwsEcsClusterCreate(d *schema.ResourceData, meta interface{}) error input.Settings = expandEcsSettings(v.(*schema.Set)) } + if v, ok := d.GetOk("configuration"); ok && len(v.([]interface{})) > 0 { + input.Configuration = expandECSClusterConfiguration(v.([]interface{})) + } + // CreateCluster will create the ECS IAM Service Linked Role on first ECS provision // This process does not complete before the initial API call finishes. var out *ecs.CreateClusterOutput @@ -166,7 +225,7 @@ func resourceAwsEcsClusterCreate(d *schema.ResourceData, meta interface{}) error d.SetId(aws.StringValue(out.Cluster.ClusterArn)) if err = waitForEcsClusterActive(conn, clusterName, ecsClusterTimeoutCreate); err != nil { - return fmt.Errorf("error waiting for ECS Cluster (%s) creation: %s", d.Id(), err) + return fmt.Errorf("error waiting for ECS Cluster (%s) creation: %w", d.Id(), err) } return resourceAwsEcsClusterRead(d, meta) @@ -240,14 +299,20 @@ func resourceAwsEcsClusterRead(d *schema.ResourceData, meta interface{}) error { d.Set("name", cluster.ClusterName) if err := d.Set("capacity_providers", aws.StringValueSlice(cluster.CapacityProviders)); err != nil { - return fmt.Errorf("error setting capacity_providers: %s", err) + return fmt.Errorf("error setting capacity_providers: %w", err) } if err := d.Set("default_capacity_provider_strategy", flattenEcsCapacityProviderStrategy(cluster.DefaultCapacityProviderStrategy)); err != nil { - return fmt.Errorf("error setting default_capacity_provider_strategy: %s", err) + return fmt.Errorf("error setting default_capacity_provider_strategy: %w", err) } if err := d.Set("setting", flattenEcsSettings(cluster.Settings)); err != nil { - return fmt.Errorf("error setting setting: %s", err) + return fmt.Errorf("error setting setting: %w", err) + } + + if cluster.Configuration != nil { + if err := d.Set("configuration", flattenECSClusterConfiguration(cluster.Configuration)); err != nil { + return fmt.Errorf("error setting configuration: %w", err) + } } tags := keyvaluetags.EcsKeyValueTags(cluster.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -269,19 +334,26 @@ func resourceAwsEcsClusterUpdate(d *schema.ResourceData, meta interface{}) error clusterName := d.Get("name").(string) - if d.HasChange("setting") { - input := ecs.UpdateClusterSettingsInput{ - Cluster: aws.String(d.Id()), - Settings: expandEcsSettings(d.Get("setting").(*schema.Set)), + if d.HasChanges("setting", "configuration") { + input := ecs.UpdateClusterInput{ + Cluster: aws.String(d.Id()), + } + + if v, ok := d.GetOk("setting"); ok { + input.Settings = expandEcsSettings(v.(*schema.Set)) + } + + if v, ok := d.GetOk("configuration"); ok && len(v.([]interface{})) > 0 { + input.Configuration = expandECSClusterConfiguration(v.([]interface{})) } - _, err := conn.UpdateClusterSettings(&input) + _, err := conn.UpdateCluster(&input) if err != nil { - return fmt.Errorf("error changing ECS cluster settings (%s): %s", d.Id(), err) + return fmt.Errorf("error changing ECS cluster (%s): %w", d.Id(), err) } if err = waitForEcsClusterActive(conn, clusterName, ecsClusterTimeoutUpdate); err != nil { - return fmt.Errorf("error waiting for ECS Cluster (%s) update: %s", d.Id(), err) + return fmt.Errorf("error waiting for ECS Cluster (%s) update: %w", d.Id(), err) } } @@ -289,7 +361,7 @@ func resourceAwsEcsClusterUpdate(d *schema.ResourceData, meta interface{}) error o, n := d.GetChange("tags_all") if err := keyvaluetags.EcsUpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating ECS Cluster (%s) tags: %s", d.Id(), err) + return fmt.Errorf("error updating ECS Cluster (%s) tags: %w", d.Id(), err) } } @@ -320,11 +392,11 @@ func resourceAwsEcsClusterUpdate(d *schema.ResourceData, meta interface{}) error _, err = conn.PutClusterCapacityProviders(&input) } if err != nil { - return fmt.Errorf("error changing ECS cluster capacity provider settings (%s): %s", d.Id(), err) + return fmt.Errorf("error changing ECS cluster capacity provider settings (%s): %w", d.Id(), err) } if err = waitForEcsClusterActive(conn, clusterName, ecsClusterTimeoutUpdate); err != nil { - return fmt.Errorf("error waiting for ECS Cluster (%s) update: %s", d.Id(), err) + return fmt.Errorf("error waiting for ECS Cluster (%s) update: %w", d.Id(), err) } } @@ -376,7 +448,7 @@ func resourceAwsEcsClusterDelete(d *schema.ResourceData, meta interface{}) error } _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf("Error waiting for ECS cluster to become inactive: %s", err) + return fmt.Errorf("Error waiting for ECS cluster to become inactive: %w", err) } log.Printf("[DEBUG] ECS cluster %q deleted", d.Id()) @@ -450,3 +522,121 @@ func flattenEcsSettings(list []*ecs.ClusterSetting) []map[string]interface{} { } return result } + +func flattenECSClusterConfiguration(apiObject *ecs.ClusterConfiguration) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if apiObject.ExecuteCommandConfiguration != nil { + tfMap["execute_command_configuration"] = flattenECSClusterConfigurationExecuteCommandConfiguration(apiObject.ExecuteCommandConfiguration) + } + return tfMap +} + +func flattenECSClusterConfigurationExecuteCommandConfiguration(apiObject *ecs.ExecuteCommandConfiguration) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if apiObject.KmsKeyId != nil { + tfMap["kms_key_id"] = aws.StringValue(apiObject.KmsKeyId) + } + + if apiObject.LogConfiguration != nil { + tfMap["log_configuration"] = flattenECSClusterConfigurationExecuteCommandConfigurationLogConfiguration(apiObject.LogConfiguration) + } + + if apiObject.Logging != nil { + tfMap["logging"] = aws.StringValue(apiObject.Logging) + } + + return tfMap +} + +func flattenECSClusterConfigurationExecuteCommandConfigurationLogConfiguration(apiObject *ecs.ExecuteCommandLogConfiguration) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + tfMap["cloud_watch_log_group_name"] = aws.StringValue(apiObject.CloudWatchLogGroupName) + tfMap["cloud_watch_encryption_enabled"] = aws.BoolValue(apiObject.CloudWatchEncryptionEnabled) + tfMap["s3_bucket_encryption_enabled"] = aws.BoolValue(apiObject.S3EncryptionEnabled) + tfMap["s3_bucket_name"] = aws.StringValue(apiObject.S3BucketName) + tfMap["s3_key_prefix"] = aws.StringValue(apiObject.S3KeyPrefix) + + return tfMap +} + +func expandECSClusterConfiguration(nc []interface{}) *ecs.ClusterConfiguration { + if len(nc) == 0 { + return &ecs.ClusterConfiguration{} + } + raw := nc[0].(map[string]interface{}) + + config := &ecs.ClusterConfiguration{} + if v, ok := raw["execute_command_configuration"].([]interface{}); ok && len(v) > 0 { + config.ExecuteCommandConfiguration = expandECSClusterConfigurationExecuteCommandConfiguration(v) + } + + return config +} + +func expandECSClusterConfigurationExecuteCommandConfiguration(nc []interface{}) *ecs.ExecuteCommandConfiguration { + if len(nc) == 0 { + return &ecs.ExecuteCommandConfiguration{} + } + raw := nc[0].(map[string]interface{}) + + config := &ecs.ExecuteCommandConfiguration{} + if v, ok := raw["log_configuration"].([]interface{}); ok && len(v) > 0 { + config.LogConfiguration = expandECSClusterConfigurationExecuteCommandLogConfiguration(v) + } + + if v, ok := raw["kms_key_id"].(string); ok && v != "" { + config.KmsKeyId = aws.String(v) + } + + if v, ok := raw["logging"].(string); ok && v != "" { + config.Logging = aws.String(v) + } + + return config +} + +func expandECSClusterConfigurationExecuteCommandLogConfiguration(nc []interface{}) *ecs.ExecuteCommandLogConfiguration { + if len(nc) == 0 { + return &ecs.ExecuteCommandLogConfiguration{} + } + raw := nc[0].(map[string]interface{}) + + config := &ecs.ExecuteCommandLogConfiguration{} + + if v, ok := raw["cloud_watch_log_group_name"].(string); ok && v != "" { + config.CloudWatchLogGroupName = aws.String(v) + } + + if v, ok := raw["s3_bucket_name"].(string); ok && v != "" { + config.S3BucketName = aws.String(v) + } + + if v, ok := raw["s3_key_prefix"].(string); ok && v != "" { + config.S3KeyPrefix = aws.String(v) + } + + if v, ok := raw["cloud_watch_encryption_enabled"].(bool); ok { + config.CloudWatchEncryptionEnabled = aws.Bool(v) + } + + if v, ok := raw["s3_bucket_encryption_enabled"].(bool); ok { + config.S3EncryptionEnabled = aws.Bool(v) + } + + return config +} diff --git a/aws/resource_aws_ecs_cluster_test.go b/aws/resource_aws_ecs_cluster_test.go index 002535147206..832a6c50c2a6 100644 --- a/aws/resource_aws_ecs_cluster_test.go +++ b/aws/resource_aws_ecs_cluster_test.go @@ -337,6 +337,43 @@ func TestAccAWSEcsCluster_containerInsights(t *testing.T) { }) } +func TestAccAWSEcsCluster_configuration(t *testing.T) { + var cluster1 ecs.Cluster + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_ecs_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ecs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEcsClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEcsClusterConfiguationConfig(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcsClusterExists(resourceName, &cluster1), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "configuration.0.kms_key_id", "aws_kms_key.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.logging", "OVERRIDE"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.log_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.log_configuration.0.cloud_watch_encryption_enabled", "true"), + resource.TestCheckResourceAttrPair(resourceName, "configuration.0.log_configuration.0.cloud_watch_log_group_name", "aws_cloudwatch_log_group.test", "name"), + ), + }, + { + Config: testAccAWSEcsClusterConfiguationConfig(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcsClusterExists(resourceName, &cluster1), + resource.TestCheckResourceAttrPair(resourceName, "configuration.0.kms_key_id", "aws_kms_key.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.logging", "OVERRIDE"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.log_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.log_configuration.0.cloud_watch_encryption_enabled", "false"), + resource.TestCheckResourceAttrPair(resourceName, "configuration.0.log_configuration.0.cloud_watch_log_group_name", "aws_cloudwatch_log_group.test", "name")), + }, + }, + }) +} + func testAccCheckAWSEcsClusterDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ecsconn @@ -604,3 +641,32 @@ resource "aws_ecs_cluster" "test" { } `, rName) } + +func testAccAWSEcsClusterConfiguationConfig(rName string, enable bool) string { + return fmt.Sprintf(` +resource "aws_kms_key" "test" { + description = %[1]q + deletion_window_in_days = 7 +} + +resource "aws_cloudwatch_log_group" "test" { + name = %[1]q +} + +resource "aws_ecs_cluster" "test" { + name = %[1]q + + configuration { + execute_command_configuration { + kms_key_id = aws_kms_key.test.arn + logging = "OVERRIDE" + + log_configuration { + cloud_watch_encryption_enabled = %[2]t + cloud_watch_log_group_name = aws_cloudwatch_log_group.test.name + } + } + } +} +`, rName, enable) +} From 8265e4a4b385840316e920336591fe42fb9eb51b Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 13 Jun 2021 00:47:19 +0300 Subject: [PATCH 0400/1208] tests --- aws/resource_aws_ecs_cluster_test.go | 49 ++++++++++++---------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/aws/resource_aws_ecs_cluster_test.go b/aws/resource_aws_ecs_cluster_test.go index 832a6c50c2a6..b4824c8f9269 100644 --- a/aws/resource_aws_ecs_cluster_test.go +++ b/aws/resource_aws_ecs_cluster_test.go @@ -310,7 +310,7 @@ func TestAccAWSEcsCluster_containerInsights(t *testing.T) { ), }, { - Config: testAccAWSEcsClusterConfigContainerInsights(rName), + Config: testAccAWSEcsClusterConfigContainerInsights(rName, "enabled"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsClusterExists(resourceName, &cluster1), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "ecs", fmt.Sprintf("cluster/%s", rName)), @@ -323,7 +323,7 @@ func TestAccAWSEcsCluster_containerInsights(t *testing.T) { ), }, { - Config: testAccAWSEcsClusterConfigContainerInsightsDisable(rName), + Config: testAccAWSEcsClusterConfigContainerInsights(rName, "disabled"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsClusterExists(resourceName, &cluster1), resource.TestCheckResourceAttr(resourceName, "setting.#", "1"), @@ -353,22 +353,27 @@ func TestAccAWSEcsCluster_configuration(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsClusterExists(resourceName, &cluster1), resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "configuration.0.kms_key_id", "aws_kms_key.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "configuration.0.logging", "OVERRIDE"), - resource.TestCheckResourceAttr(resourceName, "configuration.0.log_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "configuration.0.log_configuration.0.cloud_watch_encryption_enabled", "true"), - resource.TestCheckResourceAttrPair(resourceName, "configuration.0.log_configuration.0.cloud_watch_log_group_name", "aws_cloudwatch_log_group.test", "name"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "configuration.0.execute_command_configuration.0.kms_key_id", "aws_kms_key.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.0.logging", "OVERRIDE"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.0.log_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.0.log_configuration.0.cloud_watch_encryption_enabled", "true"), + resource.TestCheckResourceAttrPair(resourceName, "configuration.0.execute_command_configuration.0.log_configuration.0.cloud_watch_log_group_name", "aws_cloudwatch_log_group.test", "name"), ), }, { Config: testAccAWSEcsClusterConfiguationConfig(rName, false), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsClusterExists(resourceName, &cluster1), - resource.TestCheckResourceAttrPair(resourceName, "configuration.0.kms_key_id", "aws_kms_key.test", "arn"), - resource.TestCheckResourceAttr(resourceName, "configuration.0.logging", "OVERRIDE"), - resource.TestCheckResourceAttr(resourceName, "configuration.0.log_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "configuration.0.log_configuration.0.cloud_watch_encryption_enabled", "false"), - resource.TestCheckResourceAttrPair(resourceName, "configuration.0.log_configuration.0.cloud_watch_log_group_name", "aws_cloudwatch_log_group.test", "name")), + resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.#", "1"), + + resource.TestCheckResourceAttrPair(resourceName, "configuration.0.execute_command_configuration.0.kms_key_id", "aws_kms_key.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.0.logging", "OVERRIDE"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.0.log_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.0.log_configuration.0.cloud_watch_encryption_enabled", "false"), + resource.TestCheckResourceAttrPair(resourceName, "configuration.0.execute_command_configuration.0.log_configuration.0.cloud_watch_log_group_name", "aws_cloudwatch_log_group.test", "name"), + ), }, }, }) @@ -618,28 +623,16 @@ resource "aws_ecs_cluster" "test" { `, rName, tag1Key, tag1Value, tag2Key, tag2Value) } -func testAccAWSEcsClusterConfigContainerInsights(rName string) string { - return fmt.Sprintf(` -resource "aws_ecs_cluster" "test" { - name = %q - setting { - name = "containerInsights" - value = "enabled" - } -} -`, rName) -} - -func testAccAWSEcsClusterConfigContainerInsightsDisable(rName string) string { +func testAccAWSEcsClusterConfigContainerInsights(rName, value string) string { return fmt.Sprintf(` resource "aws_ecs_cluster" "test" { - name = %q + name = %[1]q setting { name = "containerInsights" - value = "disabled" + value = %[2]q } } -`, rName) +`, rName, value) } func testAccAWSEcsClusterConfiguationConfig(rName string, enable bool) string { From 6fd816a5dded55691b8886f004287f207b9edd4a Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 13 Jun 2021 00:47:42 +0300 Subject: [PATCH 0401/1208] fmt --- aws/resource_aws_ecs_cluster_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/aws/resource_aws_ecs_cluster_test.go b/aws/resource_aws_ecs_cluster_test.go index b4824c8f9269..0b29e5d56251 100644 --- a/aws/resource_aws_ecs_cluster_test.go +++ b/aws/resource_aws_ecs_cluster_test.go @@ -367,7 +367,6 @@ func TestAccAWSEcsCluster_configuration(t *testing.T) { testAccCheckAWSEcsClusterExists(resourceName, &cluster1), resource.TestCheckResourceAttr(resourceName, "configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "configuration.0.execute_command_configuration.0.kms_key_id", "aws_kms_key.test", "arn"), resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.0.logging", "OVERRIDE"), resource.TestCheckResourceAttr(resourceName, "configuration.0.execute_command_configuration.0.log_configuration.#", "1"), From 850d9648c65a6d8180df2ec17db90f78be47deed Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 13 Jun 2021 00:52:30 +0300 Subject: [PATCH 0402/1208] disappears --- aws/resource_aws_ecs_cluster_test.go | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/aws/resource_aws_ecs_cluster_test.go b/aws/resource_aws_ecs_cluster_test.go index 0b29e5d56251..cf06853acec4 100644 --- a/aws/resource_aws_ecs_cluster_test.go +++ b/aws/resource_aws_ecs_cluster_test.go @@ -106,7 +106,7 @@ func TestAccAWSEcsCluster_disappears(t *testing.T) { Config: testAccAWSEcsClusterConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsClusterExists(resourceName, &cluster1), - testAccCheckAWSEcsClusterDisappears(&cluster1), + testAccCheckResourceDisappears(testAccProvider, resourceAwsEcsCluster(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -435,22 +435,6 @@ func testAccCheckAWSEcsClusterExists(resourceName string, cluster *ecs.Cluster) } } -func testAccCheckAWSEcsClusterDisappears(cluster *ecs.Cluster) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).ecsconn - - input := &ecs.DeleteClusterInput{ - Cluster: cluster.ClusterArn, - } - - if _, err := conn.DeleteCluster(input); err != nil { - return fmt.Errorf("error deleting ECS Cluster (%s): %s", aws.StringValue(cluster.ClusterArn), err) - } - - return nil - } -} - func testAccAWSEcsClusterConfig(rName string) string { return fmt.Sprintf(` resource "aws_ecs_cluster" "test" { From 417fa7e99b01fbe1444d5c97627c2c334ff16cd1 Mon Sep 17 00:00:00 2001 From: Dan Cohen Date: Fri, 18 Dec 2020 17:30:09 +0000 Subject: [PATCH 0403/1208] implement the event bus policy resource --- aws/provider.go | 1 + ...esource_aws_cloudwatch_event_bus_policy.go | 172 ++++++++++++++++++ ...ce_aws_cloudwatch_event_bus_policy_test.go | 102 +++++++++++ 3 files changed, 275 insertions(+) create mode 100644 aws/resource_aws_cloudwatch_event_bus_policy.go create mode 100644 aws/resource_aws_cloudwatch_event_bus_policy_test.go diff --git a/aws/provider.go b/aws/provider.go index 90a101318462..9d2b36f8c3cd 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -549,6 +549,7 @@ func Provider() *schema.Provider { "aws_cloudfront_realtime_log_config": resourceAwsCloudFrontRealtimeLogConfig(), "aws_cloudtrail": resourceAwsCloudTrail(), "aws_cloudwatch_event_bus": resourceAwsCloudWatchEventBus(), + "aws_cloudwatch_event_bus_policy": resourceAwsCloudWatchEventBusPolicy(), "aws_cloudwatch_event_permission": resourceAwsCloudWatchEventPermission(), "aws_cloudwatch_event_rule": resourceAwsCloudWatchEventRule(), "aws_cloudwatch_event_target": resourceAwsCloudWatchEventTarget(), diff --git a/aws/resource_aws_cloudwatch_event_bus_policy.go b/aws/resource_aws_cloudwatch_event_bus_policy.go new file mode 100644 index 000000000000..9b8c859ab709 --- /dev/null +++ b/aws/resource_aws_cloudwatch_event_bus_policy.go @@ -0,0 +1,172 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + tfevents "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents" + iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" +) + +func resourceAwsCloudWatchEventBusPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsCloudWatchEventBusPolicyCreate, + Read: resourceAwsCloudWatchEventBusPolicyRead, + Update: resourceAwsCloudWatchEventBusPolicyUpdate, + Delete: resourceAwsCloudWatchEventBusPolicyDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "event_bus_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validateCloudWatchEventBusName, + Default: tfevents.DefaultEventBusName, + }, + "policy": { + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func resourceAwsCloudWatchEventBusPolicyCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + eventBusName := d.Get("event_bus_name").(string) + policy := d.Get("policy").(string) + + input := events.PutPermissionInput{ + EventBusName: aws.String(eventBusName), + Policy: aws.String(policy), + } + + log.Printf("[DEBUG] Creating CloudWatch Events policy: %s", input) + _, err := conn.PutPermission(&input) + if err != nil { + return fmt.Errorf("Creating CloudWatch Events policy failed: %w", err) + } + + d.SetId(eventBusName) + + return resourceAwsCloudWatchEventBusPolicyRead(d, meta) +} + +// See also: https://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_DescribeEventBus.html +func resourceAwsCloudWatchEventBusPolicyRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + eventBusName := d.Id() + + input := events.DescribeEventBusInput{ + Name: aws.String(eventBusName), + } + var output *events.DescribeEventBusOutput + var policy *string + + // Especially with concurrent PutPermission calls there can be a slight delay + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + log.Printf("[DEBUG] Reading CloudWatch Events bus: %s", input) + output, err := conn.DescribeEventBus(&input) + if err != nil { + return resource.NonRetryableError(fmt.Errorf("reading CloudWatch Events permission (%s) failed: %w", d.Id(), err)) + } + + policy, err = getEventBusPolicy(output) + if err != nil { + return resource.RetryableError(err) + } + return nil + }) + + if isResourceTimeoutError(err) { + output, err = conn.DescribeEventBus(&input) + if output != nil { + policy, err = getEventBusPolicy(output) + } + } + + if isResourceNotFoundError(err) { + log.Printf("[WARN] Policy on {%s} EventBus not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error reading policy from CloudWatch EventBus (%s): %w", d.Id(), err) + } + + busName := aws.StringValue(output.Name) + if busName == "" { + busName = tfevents.DefaultEventBusName + } + d.Set("event_bus_name", busName) + + d.Set("policy", policy) + + return nil +} + +func getEventBusPolicy(output *events.DescribeEventBusOutput) (*string, error) { + if output == nil || output.Policy == nil { + return nil, &resource.NotFoundError{ + Message: fmt.Sprintf("Policy for CloudWatch EventBus %s not found", *output.Name), + LastResponse: output, + } + } + + return output.Policy, nil +} + +func resourceAwsCloudWatchEventBusPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + eventBusName := d.Id() + + input := events.PutPermissionInput{ + EventBusName: aws.String(eventBusName), + Policy: aws.String(d.Get("policy").(string)), + } + + log.Printf("[DEBUG] Update CloudWatch EventBus policy: %s", input) + _, err := conn.PutPermission(&input) + if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] CloudWatch EventBus %q not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("error updating policy for CloudWatch EventBus (%s): %w", d.Id(), err) + } + + return resourceAwsCloudWatchEventBusPolicyRead(d, meta) +} + +func resourceAwsCloudWatchEventBusPolicyDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudwatcheventsconn + + eventBusName := d.Id() + removeAllPermissions := true + + input := events.RemovePermissionInput{ + EventBusName: aws.String(eventBusName), + RemoveAllPermissions: &removeAllPermissions, + } + + log.Printf("[DEBUG] Delete CloudWatch EventBus Policy: %s", input) + _, err := conn.RemovePermission(&input) + if isAWSErr(err, events.ErrCodeResourceNotFoundException, "") { + return nil + } + if err != nil { + return fmt.Errorf("error deleting policy for CloudWatch EventBus (%s): %w", d.Id(), err) + } + return nil +} diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go new file mode 100644 index 000000000000..fa2229d3658e --- /dev/null +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -0,0 +1,102 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + events "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "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 TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { + resourceName := "aws_cloudwatch_event_bus_policy.test" + rstring := acctest.RandString(5) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventBusDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudwatchEventBusPolicyConfig(rstring), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAWSCloudwatchEventBusPolicyExists(pr string) resource.TestCheckFunc { + return func(state *terraform.State) error { + eventBusResource, ok := state.RootModule().Resources[pr] + if !ok { + return fmt.Errorf("Not found: %s", pr) + } + + if eventBusResource.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + eventBusName := eventBusResource.Primary.ID + + input := &events.DescribeEventBusInput{ + Name: aws.String(eventBusName), + } + + cloudWatchEventsConnection := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn + describedEventBus, err := cloudWatchEventsConnection.DescribeEventBus(input) + + if err != nil { + return fmt.Errorf("Reading CloudWatch Events bus policy for '%s' failed: %w", pr, err) + } + if describedEventBus.Policy == nil { + return fmt.Errorf("Not found: %s", pr) + } + + return nil + } +} + +func testAccAWSCloudwatchEventBusPolicyConfig(name string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q +} + +data "aws_iam_policy_document" "access" { + statement { + sid = "test-resource-policy" + + effect = "Allow" + + principals { + identifiers = ["ecs.amazonaws.com"] + type = "Service" + } + + actions = [ + "events:PutEvents", + "events:PutRule" + ] + + resources = [ + aws_cloudwatch_event_bus.test.arn, + ] + } +} + +resource "aws_cloudwatch_event_bus_policy" "test" { + policy = data.aws_iam_policy_document.access.json + event_bus_name = aws_cloudwatch_event_bus.test.name +} +`, name) +} From 77d2d67dc7b611d6362cce0d1a83429a2bd4a5cf Mon Sep 17 00:00:00 2001 From: Dan Cohen Date: Mon, 21 Dec 2020 14:26:01 +0000 Subject: [PATCH 0404/1208] wip --- ...esource_aws_cloudwatch_event_bus_policy.go | 22 +++++++++++++++---- ...ce_aws_cloudwatch_event_bus_policy_test.go | 2 +- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy.go b/aws/resource_aws_cloudwatch_event_bus_policy.go index 9b8c859ab709..87e97b8fb081 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy.go @@ -1,6 +1,7 @@ package aws import ( + "encoding/json" "fmt" "log" @@ -19,7 +20,10 @@ func resourceAwsCloudWatchEventBusPolicy() *schema.Resource { Update: resourceAwsCloudWatchEventBusPolicyUpdate, Delete: resourceAwsCloudWatchEventBusPolicyDelete, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + d.Set("event_bus_name", d.Id()) + return []*schema.ResourceData{d}, nil + }, }, Schema: map[string]*schema.Schema{ @@ -70,12 +74,13 @@ func resourceAwsCloudWatchEventBusPolicyRead(d *schema.ResourceData, meta interf Name: aws.String(eventBusName), } var output *events.DescribeEventBusOutput + var err error var policy *string // Especially with concurrent PutPermission calls there can be a slight delay - err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + err = resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { log.Printf("[DEBUG] Reading CloudWatch Events bus: %s", input) - output, err := conn.DescribeEventBus(&input) + output, err = conn.DescribeEventBus(&input) if err != nil { return resource.NonRetryableError(fmt.Errorf("reading CloudWatch Events permission (%s) failed: %w", d.Id(), err)) } @@ -109,7 +114,16 @@ func resourceAwsCloudWatchEventBusPolicyRead(d *schema.ResourceData, meta interf } d.Set("event_bus_name", busName) - d.Set("policy", policy) + log.Printf("[WARN] about to unmarshal json") + policyBytes := []byte(*policy) + log.Printf("[WARN] converted policy into byte array") + var policyObject interface{} + if err := json.Unmarshal(policyBytes, &policyObject); err != nil { + return fmt.Errorf("error parsing json from policy for CloudWatch EventBus (%s): %w", d.Id(), err) + } + marshalled, _ := json.Marshal(policyObject) + log.Printf("[WARN] finished unmarshalling json") + d.Set("policy", string(marshalled)) return nil } diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index fa2229d3658e..d609471e15f9 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -58,7 +58,7 @@ func testAccCheckAWSCloudwatchEventBusPolicyExists(pr string) resource.TestCheck if err != nil { return fmt.Errorf("Reading CloudWatch Events bus policy for '%s' failed: %w", pr, err) } - if describedEventBus.Policy == nil { + if describedEventBus.Policy == nil || len(*describedEventBus.Policy) == 0 { return fmt.Errorf("Not found: %s", pr) } From 3223e423246549391a23de8c33cf313eb24cc69e Mon Sep 17 00:00:00 2001 From: Dan Cohen Date: Tue, 22 Dec 2020 12:19:01 +0000 Subject: [PATCH 0405/1208] remove the unnecessary json marshal & unmarshal --- aws/resource_aws_cloudwatch_event_bus_policy.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy.go b/aws/resource_aws_cloudwatch_event_bus_policy.go index 87e97b8fb081..bc0e34779bf2 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy.go @@ -114,16 +114,7 @@ func resourceAwsCloudWatchEventBusPolicyRead(d *schema.ResourceData, meta interf } d.Set("event_bus_name", busName) - log.Printf("[WARN] about to unmarshal json") - policyBytes := []byte(*policy) - log.Printf("[WARN] converted policy into byte array") - var policyObject interface{} - if err := json.Unmarshal(policyBytes, &policyObject); err != nil { - return fmt.Errorf("error parsing json from policy for CloudWatch EventBus (%s): %w", d.Id(), err) - } - marshalled, _ := json.Marshal(policyObject) - log.Printf("[WARN] finished unmarshalling json") - d.Set("policy", string(marshalled)) + d.Set("policy", policy) return nil } From 86a43bf40d98a8d8c30871a5623442a59c33e123 Mon Sep 17 00:00:00 2001 From: Dan Cohen Date: Tue, 22 Dec 2020 14:32:37 +0000 Subject: [PATCH 0406/1208] set up proper validation and equality comparison for the policy --- aws/resource_aws_cloudwatch_event_bus_policy.go | 8 +++++--- aws/resource_aws_cloudwatch_event_bus_policy_test.go | 8 ++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy.go b/aws/resource_aws_cloudwatch_event_bus_policy.go index bc0e34779bf2..53feea3118a5 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy.go @@ -1,7 +1,6 @@ package aws import ( - "encoding/json" "fmt" "log" @@ -9,6 +8,7 @@ import ( events "github.com/aws/aws-sdk-go/service/cloudwatchevents" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" tfevents "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" ) @@ -35,8 +35,10 @@ func resourceAwsCloudWatchEventBusPolicy() *schema.Resource { Default: tfevents.DefaultEventBusName, }, "policy": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs, }, }, } diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index d609471e15f9..8f95810d175e 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -74,20 +74,16 @@ resource "aws_cloudwatch_event_bus" "test" { data "aws_iam_policy_document" "access" { statement { - sid = "test-resource-policy" - + sid = "test-resource-policy" effect = "Allow" - principals { identifiers = ["ecs.amazonaws.com"] type = "Service" } - actions = [ "events:PutEvents", "events:PutRule" ] - resources = [ aws_cloudwatch_event_bus.test.arn, ] @@ -95,7 +91,7 @@ data "aws_iam_policy_document" "access" { } resource "aws_cloudwatch_event_bus_policy" "test" { - policy = data.aws_iam_policy_document.access.json + policy = data.aws_iam_policy_document.access.json event_bus_name = aws_cloudwatch_event_bus.test.name } `, name) From 770f2f2ff43b9c74f2079a29a120b7eb04d96bf1 Mon Sep 17 00:00:00 2001 From: Dan Cohen Date: Tue, 22 Dec 2020 14:44:57 +0000 Subject: [PATCH 0407/1208] fix linting --- aws/resource_aws_cloudwatch_event_bus_policy_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index 8f95810d175e..d607c7fc956e 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -74,7 +74,7 @@ resource "aws_cloudwatch_event_bus" "test" { data "aws_iam_policy_document" "access" { statement { - sid = "test-resource-policy" + sid = "test-resource-policy" effect = "Allow" principals { identifiers = ["ecs.amazonaws.com"] From 037e0464daa292ba246546158bfb3f0b91401e2d Mon Sep 17 00:00:00 2001 From: Dan Cohen Date: Tue, 22 Dec 2020 14:55:34 +0000 Subject: [PATCH 0408/1208] add the documentation --- .../cloudwatch_event_bus_policy.html.markdown | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 website/docs/r/cloudwatch_event_bus_policy.html.markdown diff --git a/website/docs/r/cloudwatch_event_bus_policy.html.markdown b/website/docs/r/cloudwatch_event_bus_policy.html.markdown new file mode 100644 index 000000000000..ed9cd103c737 --- /dev/null +++ b/website/docs/r/cloudwatch_event_bus_policy.html.markdown @@ -0,0 +1,41 @@ +--- +subcategory: "EventBridge (CloudWatch Events)" +layout: "aws" +page_title: "AWS: aws_cloudwatch_event_bus_policy" +description: |- + Provides a resource to create an EventBridge policy to support cross-account events. +--- + +# Resource: aws_cloudwatch_event_permission + +Provides a resource to create an EventBridge resource policy to support cross-account events. + +~> **Note:** EventBridge was formerly known as CloudWatch Events. The functionality is identical. + +~> **Note:** The cloudwatch eventbus policy resource is incompatible with the cloudwatch event permissions resource and will overwrite them. + +## Example Usage + +### Account Access + +```hcl +resource "aws_cloudwatch_event_bus_policy" "test" { + policy = data.aws_iam_policy_document.access.json + event_bus_name = aws_cloudwatch_event_bus.test.name +} +``` + +## Argument Reference + +The following arguments are supported: + +* `policy` - (Required) The text of the policy. For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). +* `event_bus_name` - (Optional) The event bus to set the permissions on. If you omit this, the permissions are set on the `default` event bus. + +## Import + +EventBridge permissions can be imported using the `event_bus_name`, e.g. + +```shell +$ terraform import aws_cloudwatch_event_bus_policy.DevAccountAccess example-event-bus +``` From d03d52199471b1ed5bbb78b2485bee5440861616 Mon Sep 17 00:00:00 2001 From: Dan Cohen Date: Sun, 13 Jun 2021 13:35:23 +0100 Subject: [PATCH 0409/1208] Update aws/resource_aws_cloudwatch_event_bus_policy.go update according to suggestion Co-authored-by: Heitor Lessa --- aws/resource_aws_cloudwatch_event_bus_policy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy.go b/aws/resource_aws_cloudwatch_event_bus_policy.go index 53feea3118a5..b618d07d285f 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy.go @@ -31,7 +31,7 @@ func resourceAwsCloudWatchEventBusPolicy() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - ValidateFunc: validateCloudWatchEventBusName, + ValidateFunc: validateCloudWatchEventBusNameOrARN, Default: tfevents.DefaultEventBusName, }, "policy": { From 0b0e3e8acd8b2a6ff0f180ec617bd461007b75ab Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 14 Jun 2021 10:19:28 +0300 Subject: [PATCH 0410/1208] finder/waiter/fix flatten --- aws/internal/service/ecs/finder/finder.go | 32 ++++++++ aws/internal/service/ecs/waiter/status.go | 24 ++++++ aws/internal/service/ecs/waiter/waiter.go | 39 ++++++++++ aws/resource_aws_ecs_cluster.go | 95 +++++++---------------- aws/resource_aws_ecs_cluster_test.go | 34 ++++---- 5 files changed, 141 insertions(+), 83 deletions(-) create mode 100644 aws/internal/service/ecs/finder/finder.go diff --git a/aws/internal/service/ecs/finder/finder.go b/aws/internal/service/ecs/finder/finder.go new file mode 100644 index 000000000000..f6a25ae29523 --- /dev/null +++ b/aws/internal/service/ecs/finder/finder.go @@ -0,0 +1,32 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ecs" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func CluserByARN(conn *ecs.ECS, arn string) (*ecs.DescribeClustersOutput, error) { + input := &ecs.DescribeClustersInput{ + Clusters: []*string{aws.String(arn)}, + Include: []*string{aws.String(ecs.ClusterFieldTags), aws.String(ecs.ClusterFieldConfigurations)}, + } + + output, err := conn.DescribeClusters(input) + + if err != nil { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if output == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output, nil +} diff --git a/aws/internal/service/ecs/waiter/status.go b/aws/internal/service/ecs/waiter/status.go index 3e69362b027d..f84de77a123a 100644 --- a/aws/internal/service/ecs/waiter/status.go +++ b/aws/internal/service/ecs/waiter/status.go @@ -7,6 +7,7 @@ import ( "github.com/aws/aws-sdk-go/service/ecs" "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/finder" ) const ( @@ -23,6 +24,9 @@ const ( ServiceStatusError = "ERROR" ServiceStatusNone = "NONE" + + ClusterStatusError = "ERROR" + ClusterStatusNone = "NONE" ) // CapacityProviderStatus fetches the Capacity Provider and its Status @@ -71,3 +75,23 @@ func ServiceStatus(conn *ecs.ECS, id, cluster string) resource.StateRefreshFunc return output, aws.StringValue(output.Services[0].Status), err } } + +func ClusterStatus(conn *ecs.ECS, arn string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.CluserByARN(conn, arn) + + if tfawserr.ErrCodeEquals(err, ecs.ErrCodeClusterNotFoundException) { + return nil, ClusterStatusNone, nil + } + + if err != nil { + return nil, ClusterStatusError, err + } + + if len(output.Clusters) == 0 { + return nil, ClusterStatusNone, nil + } + + return output, aws.StringValue(output.Clusters[0].Status), err + } +} diff --git a/aws/internal/service/ecs/waiter/waiter.go b/aws/internal/service/ecs/waiter/waiter.go index 3f12cef4d75f..a7135e7b3faf 100644 --- a/aws/internal/service/ecs/waiter/waiter.go +++ b/aws/internal/service/ecs/waiter/waiter.go @@ -17,6 +17,10 @@ const ( ServiceInactiveTimeoutMin = 1 * time.Second ServiceDescribeTimeout = 2 * time.Minute ServiceUpdateTimeout = 2 * time.Minute + + ClusterAvailableTimeout = 10 * time.Minute + ClusterDeleteTimeout = 10 * time.Minute + ClusterAvailableDelay = 10 * time.Second ) // CapacityProviderInactive waits for a Capacity Provider to return INACTIVE @@ -98,3 +102,38 @@ func ServiceDescribeReady(conn *ecs.ECS, id, cluster string) (*ecs.DescribeServi return nil, err } + +func ClusterAvailable(conn *ecs.ECS, arn string) (*ecs.Cluster, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"PROVISIONING"}, + Target: []string{"ACTIVE"}, + Refresh: ClusterStatus(conn, arn), + Timeout: ClusterAvailableTimeout, + Delay: ClusterAvailableDelay, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*ecs.Cluster); ok { + return v, err + } + + return nil, err +} + +func ClusterDeleted(conn *ecs.ECS, arn string) (*ecs.Cluster, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"ACTIVE", "DEPROVISIONING"}, + Target: []string{"INACTIVE"}, + Refresh: ClusterStatus(conn, arn), + Timeout: ClusterDeleteTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*ecs.Cluster); ok { + return v, err + } + + return nil, err +} diff --git a/aws/resource_aws_ecs_cluster.go b/aws/resource_aws_ecs_cluster.go index e9cad024d7bc..6f1172c26a72 100644 --- a/aws/resource_aws_ecs_cluster.go +++ b/aws/resource_aws_ecs_cluster.go @@ -13,11 +13,12 @@ import ( "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/waiter" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" ) const ( - ecsClusterTimeoutCreate = 10 * time.Minute ecsClusterTimeoutDelete = 10 * time.Minute ecsClusterTimeoutUpdate = 10 * time.Minute ) @@ -224,8 +225,8 @@ func resourceAwsEcsClusterCreate(d *schema.ResourceData, meta interface{}) error d.SetId(aws.StringValue(out.Cluster.ClusterArn)) - if err = waitForEcsClusterActive(conn, clusterName, ecsClusterTimeoutCreate); err != nil { - return fmt.Errorf("error waiting for ECS Cluster (%s) creation: %w", d.Id(), err) + if _, err := waiter.ClusterAvailable(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for ECS Cluster (%s) to become Available: %w", d.Id(), err) } return resourceAwsEcsClusterRead(d, meta) @@ -236,16 +237,10 @@ func resourceAwsEcsClusterRead(d *schema.ResourceData, meta interface{}) error { defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - input := &ecs.DescribeClustersInput{ - Clusters: []*string{aws.String(d.Id())}, - Include: []*string{aws.String(ecs.ClusterFieldTags)}, - } - - log.Printf("[DEBUG] Reading ECS Cluster: %s", input) var out *ecs.DescribeClustersOutput err := resource.Retry(2*time.Minute, func() *resource.RetryError { var err error - out, err = conn.DescribeClusters(input) + out, err = finder.CluserByARN(conn, d.Id()) if err != nil { return resource.NonRetryableError(err) @@ -261,7 +256,7 @@ func resourceAwsEcsClusterRead(d *schema.ResourceData, meta interface{}) error { return nil }) if isResourceTimeoutError(err) { - out, err = conn.DescribeClusters(input) + out, err = finder.CluserByARN(conn, d.Id()) } if isResourceNotFoundError(err) { @@ -332,8 +327,6 @@ func resourceAwsEcsClusterRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsEcsClusterUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ecsconn - clusterName := d.Get("name").(string) - if d.HasChanges("setting", "configuration") { input := ecs.UpdateClusterInput{ Cluster: aws.String(d.Id()), @@ -352,8 +345,8 @@ func resourceAwsEcsClusterUpdate(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error changing ECS cluster (%s): %w", d.Id(), err) } - if err = waitForEcsClusterActive(conn, clusterName, ecsClusterTimeoutUpdate); err != nil { - return fmt.Errorf("error waiting for ECS Cluster (%s) update: %w", d.Id(), err) + if _, err := waiter.ClusterAvailable(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for ECS Cluster (%s) to become Available: %w", d.Id(), err) } } @@ -395,8 +388,8 @@ func resourceAwsEcsClusterUpdate(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error changing ECS cluster capacity provider settings (%s): %w", d.Id(), err) } - if err = waitForEcsClusterActive(conn, clusterName, ecsClusterTimeoutUpdate); err != nil { - return fmt.Errorf("error waiting for ECS Cluster (%s) update: %w", d.Id(), err) + if _, err := waiter.ClusterAvailable(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for ECS Cluster (%s) to become Available: %w", d.Id(), err) } } @@ -439,51 +432,14 @@ func resourceAwsEcsClusterDelete(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("Error deleting ECS cluster: %s", err) } - clusterName := d.Get("name").(string) - stateConf := resource.StateChangeConf{ - Pending: []string{"ACTIVE", "DEPROVISIONING"}, - Target: []string{"INACTIVE"}, - Timeout: ecsClusterTimeoutDelete, - Refresh: refreshEcsClusterStatus(conn, clusterName), - } - _, err = stateConf.WaitForState() - if err != nil { - return fmt.Errorf("Error waiting for ECS cluster to become inactive: %w", err) + if _, err := waiter.ClusterDeleted(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for ECS Cluster (%s) to become Deleted: %w", d.Id(), err) } log.Printf("[DEBUG] ECS cluster %q deleted", d.Id()) return nil } -func waitForEcsClusterActive(conn *ecs.ECS, clusterName string, timeout time.Duration) error { - stateConf := resource.StateChangeConf{ - Pending: []string{"PROVISIONING"}, - Target: []string{"ACTIVE"}, - Timeout: timeout, - Refresh: refreshEcsClusterStatus(conn, clusterName), - Delay: 10 * time.Second, - } - _, err := stateConf.WaitForState() - return err -} - -func refreshEcsClusterStatus(conn *ecs.ECS, clusterName string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - output, err := conn.DescribeClusters(&ecs.DescribeClustersInput{ - Clusters: []*string{aws.String(clusterName)}, - }) - if err != nil { - return nil, "", err - } - for _, c := range output.Clusters { - if aws.StringValue(c.ClusterName) == clusterName { - return c, aws.StringValue(c.Status), nil - } - } - return nil, "", fmt.Errorf("ECS cluster %q missing", clusterName) - } -} - func expandEcsSettings(configured *schema.Set) []*ecs.ClusterSetting { list := configured.List() if len(list) == 0 { @@ -523,7 +479,7 @@ func flattenEcsSettings(list []*ecs.ClusterSetting) []map[string]interface{} { return result } -func flattenECSClusterConfiguration(apiObject *ecs.ClusterConfiguration) map[string]interface{} { +func flattenECSClusterConfiguration(apiObject *ecs.ClusterConfiguration) []interface{} { if apiObject == nil { return nil } @@ -533,10 +489,10 @@ func flattenECSClusterConfiguration(apiObject *ecs.ClusterConfiguration) map[str if apiObject.ExecuteCommandConfiguration != nil { tfMap["execute_command_configuration"] = flattenECSClusterConfigurationExecuteCommandConfiguration(apiObject.ExecuteCommandConfiguration) } - return tfMap + return []interface{}{tfMap} } -func flattenECSClusterConfigurationExecuteCommandConfiguration(apiObject *ecs.ExecuteCommandConfiguration) map[string]interface{} { +func flattenECSClusterConfigurationExecuteCommandConfiguration(apiObject *ecs.ExecuteCommandConfiguration) []interface{} { if apiObject == nil { return nil } @@ -555,23 +511,32 @@ func flattenECSClusterConfigurationExecuteCommandConfiguration(apiObject *ecs.Ex tfMap["logging"] = aws.StringValue(apiObject.Logging) } - return tfMap + return []interface{}{tfMap} } -func flattenECSClusterConfigurationExecuteCommandConfigurationLogConfiguration(apiObject *ecs.ExecuteCommandLogConfiguration) map[string]interface{} { +func flattenECSClusterConfigurationExecuteCommandConfigurationLogConfiguration(apiObject *ecs.ExecuteCommandLogConfiguration) []interface{} { if apiObject == nil { return nil } tfMap := map[string]interface{}{} - tfMap["cloud_watch_log_group_name"] = aws.StringValue(apiObject.CloudWatchLogGroupName) tfMap["cloud_watch_encryption_enabled"] = aws.BoolValue(apiObject.CloudWatchEncryptionEnabled) tfMap["s3_bucket_encryption_enabled"] = aws.BoolValue(apiObject.S3EncryptionEnabled) - tfMap["s3_bucket_name"] = aws.StringValue(apiObject.S3BucketName) - tfMap["s3_key_prefix"] = aws.StringValue(apiObject.S3KeyPrefix) - return tfMap + if apiObject.CloudWatchLogGroupName != nil { + tfMap["cloud_watch_log_group_name"] = aws.StringValue(apiObject.CloudWatchLogGroupName) + } + + if apiObject.S3BucketName != nil { + tfMap["s3_bucket_name"] = aws.StringValue(apiObject.S3BucketName) + } + + if apiObject.S3KeyPrefix != nil { + tfMap["s3_key_prefix"] = aws.StringValue(apiObject.S3KeyPrefix) + } + + return []interface{}{tfMap} } func expandECSClusterConfiguration(nc []interface{}) *ecs.ClusterConfiguration { diff --git a/aws/resource_aws_ecs_cluster_test.go b/aws/resource_aws_ecs_cluster_test.go index cf06853acec4..7f599eedf6d8 100644 --- a/aws/resource_aws_ecs_cluster_test.go +++ b/aws/resource_aws_ecs_cluster_test.go @@ -10,6 +10,7 @@ import ( "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/finder" ) func init() { @@ -35,14 +36,13 @@ func testSweepEcsClusters(region string) error { } for _, clusterARNPtr := range page.ClusterArns { - input := &ecs.DeleteClusterInput{ - Cluster: clusterARNPtr, - } clusterARN := aws.StringValue(clusterARNPtr) log.Printf("[INFO] Deleting ECS Cluster: %s", clusterARN) - _, err = conn.DeleteCluster(input) - + r := resourceAwsEcsCluster() + d := r.Data(nil) + d.SetId(clusterARN) + err = r.Delete(d, client) if err != nil { log.Printf("[ERROR] Error deleting ECS Cluster (%s): %s", clusterARN, err) } @@ -55,7 +55,7 @@ func testSweepEcsClusters(region string) error { log.Printf("[WARN] Skipping ECS Cluster sweep for %s: %s", region, err) return nil } - return fmt.Errorf("error retrieving ECS Clusters: %s", err) + return fmt.Errorf("error retrieving ECS Clusters: %w", err) } return nil @@ -361,6 +361,12 @@ func TestAccAWSEcsCluster_configuration(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "configuration.0.execute_command_configuration.0.log_configuration.0.cloud_watch_log_group_name", "aws_cloudwatch_log_group.test", "name"), ), }, + { + ResourceName: resourceName, + ImportStateId: rName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccAWSEcsClusterConfiguationConfig(rName, false), Check: resource.ComposeTestCheckFunc( @@ -386,16 +392,14 @@ func testAccCheckAWSEcsClusterDestroy(s *terraform.State) error { continue } - out, err := conn.DescribeClusters(&ecs.DescribeClustersInput{ - Clusters: []*string{aws.String(rs.Primary.ID)}, - }) + out, err := finder.CluserByARN(conn, rs.Primary.ID) if err != nil { return err } for _, c := range out.Clusters { - if *c.ClusterArn == rs.Primary.ID && *c.Status != "INACTIVE" { + if aws.StringValue(c.ClusterArn) == rs.Primary.ID && aws.StringValue(c.Status) != "INACTIVE" { return fmt.Errorf("ECS cluster still exists:\n%s", c) } } @@ -412,16 +416,10 @@ func testAccCheckAWSEcsClusterExists(resourceName string, cluster *ecs.Cluster) } conn := testAccProvider.Meta().(*AWSClient).ecsconn - - input := &ecs.DescribeClustersInput{ - Clusters: []*string{aws.String(rs.Primary.ID)}, - Include: []*string{aws.String(ecs.ClusterFieldTags)}, - } - - output, err := conn.DescribeClusters(input) + output, err := finder.CluserByARN(conn, rs.Primary.ID) if err != nil { - return fmt.Errorf("error reading ECS Cluster (%s): %s", rs.Primary.ID, err) + return fmt.Errorf("error reading ECS Cluster (%s): %w", rs.Primary.ID, err) } for _, c := range output.Clusters { From 9dce09114933d0de9d2f54e3a95fee0a2c5fa6c3 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 14 Jun 2021 11:24:21 +0300 Subject: [PATCH 0411/1208] docs --- website/docs/r/ecs_cluster.html.markdown | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/website/docs/r/ecs_cluster.html.markdown b/website/docs/r/ecs_cluster.html.markdown index 03929a3f94e3..f9361a75551b 100644 --- a/website/docs/r/ecs_cluster.html.markdown +++ b/website/docs/r/ecs_cluster.html.markdown @@ -28,11 +28,30 @@ resource "aws_ecs_cluster" "foo" { The following arguments are supported: * `capacity_providers` - (Optional) List of short names of one or more capacity providers to associate with the cluster. Valid values also include `FARGATE` and `FARGATE_SPOT`. +* `configuration` - (Optional) The execute command configuration for the cluster. Detailed below. * `default_capacity_provider_strategy` - (Optional) Configuration block for capacity provider strategy to use by default for the cluster. Can be one or more. Detailed below. * `name` - (Required) Name of the cluster (up to 255 letters, numbers, hyphens, and underscores) * `setting` - (Optional) Configuration block(s) with cluster settings. For example, this can be used to enable CloudWatch Container Insights for a cluster. Detailed below. * `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +### `configuration` + +* `execute_command_configuration` - (Optional) The details of the execute command configuration. Detailed below. + +#### `execute_command_configuration` + +* `kms_key_id` - (Optional) The AWS Key Management Service key ID to encrypt the data between the local client and the container. +* `log_configuration` - (Optional) The log configuration for the results of the execute command actions Required when `logging` is `OVERRIDE`. Detailed below. +* `logging` - (Optional) The log setting to use for redirecting logs for your execute command results. Valid values are `NONE`, `DEFAULT`, and `OVERRIDE`. + +##### `log_configuration` + +* `cloud_watch_encryption_enabled` - (Optional) Whether or not to enable encryption on the CloudWatch logs. If not specified, encryption will be disabled. +* `cloud_watch_log_group_name` - (Optional) The name of the CloudWatch log group to send logs to. +* `s3_bucket_name` - (Optional) The name of the S3 bucket to send logs to. +* `s3_bucket_encryption_enabled` - (Optional) Whether or not to enable encryption on the logs sent to S3. If not specified, encryption will be disabled. +* `s3_key_prefix` - (Optional) An optional folder in the S3 bucket to place logs in. + ### `default_capacity_provider_strategy` * `capacity_provider` - (Required) The short name of the capacity provider. From 9566a6a2b593e0a47d1df9cf8a21f28e16dcae01 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 14 Jun 2021 11:26:11 +0300 Subject: [PATCH 0412/1208] docs --- website/docs/r/ecs_cluster.html.markdown | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/website/docs/r/ecs_cluster.html.markdown b/website/docs/r/ecs_cluster.html.markdown index f9361a75551b..0bd77e150963 100644 --- a/website/docs/r/ecs_cluster.html.markdown +++ b/website/docs/r/ecs_cluster.html.markdown @@ -23,6 +23,35 @@ resource "aws_ecs_cluster" "foo" { } ``` +## Example W/Log Configuration + +```terraform +resource "aws_kms_key" "example" { + description = "example" + deletion_window_in_days = 7 +} + +resource "aws_cloudwatch_log_group" "example" { + name = "example" +} + +resource "aws_ecs_cluster" "test" { + name = "example" + + configuration { + execute_command_configuration { + kms_key_id = aws_kms_key.example.arn + logging = "OVERRIDE" + + log_configuration { + cloud_watch_encryption_enabled = true + cloud_watch_log_group_name = aws_cloudwatch_log_group.example.name + } + } + } +} +``` + ## Argument Reference The following arguments are supported: From 3843046b0ade00bb6b046cea4322abd00952d817 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 14 Jun 2021 11:27:03 +0300 Subject: [PATCH 0413/1208] changelog --- .changelog/19785.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/19785.txt diff --git a/.changelog/19785.txt b/.changelog/19785.txt new file mode 100644 index 000000000000..1cd991f23063 --- /dev/null +++ b/.changelog/19785.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_ecs_cluster: Add support for `configuration`. +``` + +```release-note:enhancement +resource/aws_ecs_cluster: Add plan time validation for `name`. +``` \ No newline at end of file From e05971353ac0466a03543ddd730982479b981a70 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 14 Jun 2021 11:31:17 +0300 Subject: [PATCH 0414/1208] fmt --- aws/resource_aws_ecs_cluster_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_ecs_cluster_test.go b/aws/resource_aws_ecs_cluster_test.go index 7f599eedf6d8..fff6dc7c17e1 100644 --- a/aws/resource_aws_ecs_cluster_test.go +++ b/aws/resource_aws_ecs_cluster_test.go @@ -632,14 +632,14 @@ resource "aws_ecs_cluster" "test" { configuration { execute_command_configuration { - kms_key_id = aws_kms_key.test.arn - logging = "OVERRIDE" + kms_key_id = aws_kms_key.test.arn + logging = "OVERRIDE" - log_configuration { + log_configuration { cloud_watch_encryption_enabled = %[2]t - cloud_watch_log_group_name = aws_cloudwatch_log_group.test.name - } - } + cloud_watch_log_group_name = aws_cloudwatch_log_group.test.name + } + } } } `, rName, enable) From 84d8a3e0eda62b321c29f71ff2b7faa6077a9c26 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 14 Jun 2021 11:31:58 +0300 Subject: [PATCH 0415/1208] doc fmt --- website/docs/r/ecs_cluster.html.markdown | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/website/docs/r/ecs_cluster.html.markdown b/website/docs/r/ecs_cluster.html.markdown index 0bd77e150963..6c98cd825224 100644 --- a/website/docs/r/ecs_cluster.html.markdown +++ b/website/docs/r/ecs_cluster.html.markdown @@ -40,14 +40,14 @@ resource "aws_ecs_cluster" "test" { configuration { execute_command_configuration { - kms_key_id = aws_kms_key.example.arn - logging = "OVERRIDE" + kms_key_id = aws_kms_key.example.arn + logging = "OVERRIDE" - log_configuration { + log_configuration { cloud_watch_encryption_enabled = true - cloud_watch_log_group_name = aws_cloudwatch_log_group.example.name - } - } + cloud_watch_log_group_name = aws_cloudwatch_log_group.example.name + } + } } } ``` From b4d91b51d83825c05bedafbf3d5f94067d538aac Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 14 Jun 2021 11:25:54 -0400 Subject: [PATCH 0416/1208] Add a cautionary note for CMK-encrypted volumes (#12508) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This would have saved a little debugging time – see https://github.com/terraform-providers/terraform-provider-aws/issues/12507 --- website/docs/r/ebs_volume.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/ebs_volume.html.markdown b/website/docs/r/ebs_volume.html.markdown index 5383d6b1eb44..1a33a2616f6d 100644 --- a/website/docs/r/ebs_volume.html.markdown +++ b/website/docs/r/ebs_volume.html.markdown @@ -37,7 +37,7 @@ The following arguments are supported: * `snapshot_id` (Optional) A snapshot to base the EBS volume off of. * `outpost_arn` - (Optional) The Amazon Resource Name (ARN) of the Outpost. * `type` - (Optional) The type of EBS volume. Can be `standard`, `gp2`, `gp3`, `io1`, `io2`, `sc1` or `st1` (Default: `gp2`). -* `kms_key_id` - (Optional) The ARN for the KMS encryption key. When specifying `kms_key_id`, `encrypted` needs to be set to true. +* `kms_key_id` - (Optional) The ARN for the KMS encryption key. When specifying `kms_key_id`, `encrypted` needs to be set to true. Note: Terraform must be running with credentials which have the `GenerateDataKeyWithoutPlaintext` permission on the specified KMS key as required by the [EBS KMS CMK volume provisioning process](https://docs.aws.amazon.com/kms/latest/developerguide/services-ebs.html#ebs-cmk) to prevent a volume from being created and almost immediately deleted. * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. * `throughput` - (Optional) The throughput that the volume supports, in MiB/s. Only valid for `type` of `gp3`. From cfbed681d3c6a003afffc41262079b5eb3a72a1d Mon Sep 17 00:00:00 2001 From: Ichinose Shogo Date: Tue, 15 Jun 2021 00:51:13 +0900 Subject: [PATCH 0417/1208] fix docs: SSO credentials is now supported (#19770) Support for cached SSO credentials was added in [v3.26.0](https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md#3260-january-28-2021) of the Terraform AWS Provider. --- website/docs/index.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 3de4a40822c1..56cdd9e65793 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -126,7 +126,7 @@ provider "aws" { } ``` -Please note that the [AWS Go SDK](https://aws.amazon.com/sdk-for-go/), the underlying authentication handler used by the Terraform AWS Provider, does not support all AWS CLI features, such as Single Sign On (SSO) configuration or credentials. +Please note that the [AWS Go SDK](https://aws.amazon.com/sdk-for-go/), the underlying authentication handler used by the Terraform AWS Provider, does not support all AWS CLI features. ### CodeBuild, ECS, and EKS Roles From 567e9128d9263da8ecdf5cffdec114fd660ae304 Mon Sep 17 00:00:00 2001 From: kaito3desuyo Date: Tue, 15 Jun 2021 00:53:03 +0900 Subject: [PATCH 0418/1208] fix on_demand_percentage_above_base_capacity default value to 100 (#19685) --- website/docs/r/autoscaling_group.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/autoscaling_group.html.markdown b/website/docs/r/autoscaling_group.html.markdown index c6ed0cac317b..71ab767843f8 100644 --- a/website/docs/r/autoscaling_group.html.markdown +++ b/website/docs/r/autoscaling_group.html.markdown @@ -421,7 +421,7 @@ This configuration block supports the following: * `on_demand_allocation_strategy` - (Optional) Strategy to use when launching on-demand instances. Valid values: `prioritized`. Default: `prioritized`. * `on_demand_base_capacity` - (Optional) Absolute minimum amount of desired capacity that must be fulfilled by on-demand instances. Default: `0`. -* `on_demand_percentage_above_base_capacity` - (Optional) Percentage split between on-demand and Spot instances above the base on-demand capacity. Default: `0`. +* `on_demand_percentage_above_base_capacity` - (Optional) Percentage split between on-demand and Spot instances above the base on-demand capacity. Default: `100`. * `spot_allocation_strategy` - (Optional) How to allocate capacity across the Spot pools. Valid values: `lowest-price`, `capacity-optimized`, `capacity-optimized-prioritized`. Default: `lowest-price`. * `spot_instance_pools` - (Optional) Number of Spot pools per availability zone to allocate capacity. EC2 Auto Scaling selects the cheapest Spot pools and evenly allocates Spot capacity across the number of Spot pools that you specify. Default: `2`. * `spot_max_price` - (Optional) Maximum price per unit hour that the user is willing to pay for the Spot instances. Default: an empty string which means the on-demand price. From 32d4879669696b9130e6aff0cfd65523751aabc5 Mon Sep 17 00:00:00 2001 From: Patrick Hagan <56281590+glerb@users.noreply.github.com> Date: Mon, 14 Jun 2021 08:58:21 -0700 Subject: [PATCH 0419/1208] Clarify key policy vs IAM policy (#19271) * Clarify key policy vs IAM policy Key policies are not the same as IAM policies. While key policies are technically required for all KMS keys, KMS keys that are created programmatically are given a default policy that allows the `:root` of an account full access to the key, which allows IAM policies to be applied to the key. * Correction --- website/docs/r/kms_key.html.markdown | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/website/docs/r/kms_key.html.markdown b/website/docs/r/kms_key.html.markdown index e06851babb29..7248feffd5b2 100644 --- a/website/docs/r/kms_key.html.markdown +++ b/website/docs/r/kms_key.html.markdown @@ -28,7 +28,10 @@ The following arguments are supported: Defaults to `ENCRYPT_DECRYPT`. * `customer_master_key_spec` - (Optional) Specifies whether the key contains a symmetric key or an asymmetric key pair and the encryption algorithms or signing algorithms that the key supports. Valid values: `SYMMETRIC_DEFAULT`, `RSA_2048`, `RSA_3072`, `RSA_4096`, `ECC_NIST_P256`, `ECC_NIST_P384`, `ECC_NIST_P521`, or `ECC_SECG_P256K1`. Defaults to `SYMMETRIC_DEFAULT`. For help with choosing a key spec, see the [AWS KMS Developer Guide](https://docs.aws.amazon.com/kms/latest/developerguide/symm-asymm-choose.html). -* `policy` - (Optional) A valid policy JSON document. For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). +* `policy` - (Optional) A valid policy JSON document. Although this is a key policy, not an IAM policy, an [`aws_iam_policy_document`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document), in the form that designates a principal, can be used. For more information about building policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). + +~> **NOTE:** Note: All KMS keys must have a key policy. If a key policy is not specified, AWS gives the KMS key a [default key policy](https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default) that gives all principals in the owning account unlimited access to all KMS operations for the key. This default key policy effectively delegates all access control to IAM policies and KMS grants. + * `deletion_window_in_days` - (Optional) Duration in days after which the key is deleted after destruction of the resource, must be between 7 and 30 days. Defaults to 30 days. * `is_enabled` - (Optional) Specifies whether the key is enabled. Defaults to true. * `enable_key_rotation` - (Optional) Specifies whether [key rotation](http://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html) is enabled. Defaults to false. From 58d857b61f79b5254ee6cb2a7ca4c21fafd1431a Mon Sep 17 00:00:00 2001 From: Peter Mescalchin Date: Tue, 15 Jun 2021 02:06:56 +1000 Subject: [PATCH 0420/1208] aws_iam_policy_document.statement.principals.type allows asterisk as value (#19170) --- website/docs/d/iam_policy_document.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/iam_policy_document.html.markdown b/website/docs/d/iam_policy_document.html.markdown index 10f57f9537c9..69dec2886673 100644 --- a/website/docs/d/iam_policy_document.html.markdown +++ b/website/docs/d/iam_policy_document.html.markdown @@ -467,7 +467,7 @@ The `principals` and `not_principals` arguments define to whom a statement appli The following arguments are required: * `identifiers` (Required) List of identifiers for principals. When `type` is `AWS`, these are IAM principal ARNs, e.g. `arn:aws:iam::12345678901:role/yak-role`. When `type` is `Service`, these are AWS Service roles, e.g. `lambda.amazonaws.com`. When `type` is `Federated`, these are web identity users or SAML provider ARNs, e.g. `accounts.google.com` or `arn:aws:iam::12345678901:saml-provider/yak-saml-provider`. When `type` is `CanonicalUser`, these are [canonical user IDs](https://docs.aws.amazon.com/general/latest/gr/acct-identifiers.html#FindingCanonicalId), e.g. `79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be`. -* `type` (Required) Type of principal. Valid values include `AWS`, `Service`, `Federated`, and `CanonicalUser`. +* `type` (Required) Type of principal. Valid values include `AWS`, `Service`, `Federated`, `CanonicalUser` and `*`. ## Attributes Reference From 9f69c0aea4dad3fd681289f08e405e6308775315 Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Mon, 14 Jun 2021 18:10:44 +0200 Subject: [PATCH 0421/1208] chore: add codeowners to eventbridge (#19126) --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2704a39f9760..a9bc945781c2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -46,3 +46,6 @@ /aws/*_aws_emr_*.go @shuheiktgw @hashicorp/terraform-aws /website/**/emr* @shuheiktgw @hashicorp/terraform-aws + +/aws/*aws_cloudwatch_event_*.go @heitorlessa @sthulb @hashicorp/terraform-aws +/website/**/cloudwatch_event* @heitorlessa @sthulb @hashicorp/terraform-aws From 86c999f51c960b21940cc62e915aec7875e486c0 Mon Sep 17 00:00:00 2001 From: Simon Davis Date: Mon, 14 Jun 2021 10:52:11 -0700 Subject: [PATCH 0422/1208] remove defaults, and make whitespace consistent (#19791) --- .github/CODEOWNERS | 67 +++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a9bc945781c2..c6a62a4d54e2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,51 +1,50 @@ -# Default owner for all pull requests -* @hashicorp/terraform-aws +# There is no default owner for pull requests as reviews are scheduled based on community popularity. # Service specific owners -/aws/*apigatewayv2* @ewbankkit @hashicorp/terraform-aws -/website/**/apigatewayv2* @ewbankkit @hashicorp/terraform-aws +/aws/*apigatewayv2* @ewbankkit +/website/**/apigatewayv2* @ewbankkit -/aws/*appmesh* @ewbankkit @hashicorp/terraform-aws -/website/**/appmesh* @ewbankkit @hashicorp/terraform-aws +/aws/*appmesh* @ewbankkit +/website/**/appmesh* @ewbankkit -/aws/*backup* @ewbankkit @hashicorp/terraform-aws -/website/**/backup* @ewbankkit @hashicorp/terraform-aws +/aws/*backup* @ewbankkit +/website/**/backup* @ewbankkit -/aws/*_aws_codeartifact_*.go @DrFaust92 @hashicorp/terraform-aws -/website/**/codeartifact* @DrFaust92 @hashicorp/terraform-aws +/aws/*_aws_codeartifact_*.go @DrFaust92 +/website/**/codeartifact* @DrFaust92 -/aws/*_aws_fsx_*.go @DrFaust92 @hashicorp/terraform-aws -/website/**/fsx* @DrFaust92 @hashicorp/terraform-aws +/aws/*_aws_fsx_*.go @DrFaust92 +/website/**/fsx* @DrFaust92 -/aws/*globalaccelerator* @ewbankkit @hashicorp/terraform-aws -/website/**/globalaccelerator* @ewbankkit @hashicorp/terraform-aws +/aws/*globalaccelerator* @ewbankkit +/website/**/globalaccelerator* @ewbankkit -/aws/*_aws_glue_*.go @DrFaust92 @hashicorp/terraform-aws -/website/**/glue* @DrFaust92 @hashicorp/terraform-aws +/aws/*_aws_glue_*.go @DrFaust92 +/website/**/glue* @DrFaust92 -/aws/*kinesis_analytics* @ewbankkit @hashicorp/terraform-aws -/website/**/kinesis_analytics* @ewbankkit @hashicorp/terraform-aws +/aws/*kinesis_analytics* @ewbankkit +/website/**/kinesis_analytics* @ewbankkit -/aws/*kinesisanalyticsv2* @ewbankkit @hashicorp/terraform-aws -/website/**/kinesisanalyticsv2* @ewbankkit @hashicorp/terraform-aws +/aws/*kinesisanalyticsv2* @ewbankkit +/website/**/kinesisanalyticsv2* @ewbankkit -/aws/*route53_resolver* @ewbankkit @hashicorp/terraform-aws -/website/**/route53_resolver* @ewbankkit @hashicorp/terraform-aws +/aws/*route53_resolver* @ewbankkit +/website/**/route53_resolver* @ewbankkit -/aws/*_aws_storagegateway_*.go @DrFaust92 @hashicorp/terraform-aws -/website/**/storagegateway* @DrFaust92 @hashicorp/terraform-aws +/aws/*_aws_storagegateway_*.go @DrFaust92 +/website/**/storagegateway* @DrFaust92 -/aws/*_aws_sagemaker_*.go @DrFaust92 @hashicorp/terraform-aws -/website/**/sagemaker* @DrFaust92 @hashicorp/terraform-aws +/aws/*_aws_sagemaker_*.go @DrFaust92 +/website/**/sagemaker* @DrFaust92 -/aws/*_aws_workspaces_*.go @Tensho @hashicorp/terraform-aws -/website/**/workspaces* @Tensho @hashicorp/terraform-aws +/aws/*_aws_workspaces_*.go @Tensho +/website/**/workspaces* @Tensho -/aws/*_aws_mwaa_*.go @shuheiktgw @hashicorp/terraform-aws -/website/**/mwaa* @shuheiktgw @hashicorp/terraform-aws +/aws/*_aws_mwaa_*.go @shuheiktgw +/website/**/mwaa* @shuheiktgw -/aws/*_aws_emr_*.go @shuheiktgw @hashicorp/terraform-aws -/website/**/emr* @shuheiktgw @hashicorp/terraform-aws +/aws/*_aws_emr_*.go @shuheiktgw +/website/**/emr* @shuheiktgw -/aws/*aws_cloudwatch_event_*.go @heitorlessa @sthulb @hashicorp/terraform-aws -/website/**/cloudwatch_event* @heitorlessa @sthulb @hashicorp/terraform-aws +/aws/*aws_cloudwatch_event_*.go @heitorlessa @sthulb +/website/**/cloudwatch_event* @heitorlessa @sthulb From 39c4883a8e78cc251e92a43994cb1922fd52896e Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Mon, 14 Jun 2021 20:55:18 +0300 Subject: [PATCH 0423/1208] Apply suggestions from code review Co-authored-by: Kit Ewbank --- aws/internal/service/ecs/finder/finder.go | 2 +- aws/internal/service/ecs/waiter/status.go | 2 +- aws/resource_aws_ecs_cluster.go | 4 ++-- aws/resource_aws_ecs_cluster_test.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/internal/service/ecs/finder/finder.go b/aws/internal/service/ecs/finder/finder.go index f6a25ae29523..cfb22460a008 100644 --- a/aws/internal/service/ecs/finder/finder.go +++ b/aws/internal/service/ecs/finder/finder.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func CluserByARN(conn *ecs.ECS, arn string) (*ecs.DescribeClustersOutput, error) { +func ClusterByARN(conn *ecs.ECS, arn string) (*ecs.DescribeClustersOutput, error) { input := &ecs.DescribeClustersInput{ Clusters: []*string{aws.String(arn)}, Include: []*string{aws.String(ecs.ClusterFieldTags), aws.String(ecs.ClusterFieldConfigurations)}, diff --git a/aws/internal/service/ecs/waiter/status.go b/aws/internal/service/ecs/waiter/status.go index f84de77a123a..14d54c83e191 100644 --- a/aws/internal/service/ecs/waiter/status.go +++ b/aws/internal/service/ecs/waiter/status.go @@ -78,7 +78,7 @@ func ServiceStatus(conn *ecs.ECS, id, cluster string) resource.StateRefreshFunc func ClusterStatus(conn *ecs.ECS, arn string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := finder.CluserByARN(conn, arn) + output, err := finder.ClusterByARN(conn, arn) if tfawserr.ErrCodeEquals(err, ecs.ErrCodeClusterNotFoundException) { return nil, ClusterStatusNone, nil diff --git a/aws/resource_aws_ecs_cluster.go b/aws/resource_aws_ecs_cluster.go index 6f1172c26a72..d25cfab002de 100644 --- a/aws/resource_aws_ecs_cluster.go +++ b/aws/resource_aws_ecs_cluster.go @@ -240,7 +240,7 @@ func resourceAwsEcsClusterRead(d *schema.ResourceData, meta interface{}) error { var out *ecs.DescribeClustersOutput err := resource.Retry(2*time.Minute, func() *resource.RetryError { var err error - out, err = finder.CluserByARN(conn, d.Id()) + out, err = finder.ClusterByARN(conn, d.Id()) if err != nil { return resource.NonRetryableError(err) @@ -256,7 +256,7 @@ func resourceAwsEcsClusterRead(d *schema.ResourceData, meta interface{}) error { return nil }) if isResourceTimeoutError(err) { - out, err = finder.CluserByARN(conn, d.Id()) + out, err = finder.ClusterByARN(conn, d.Id()) } if isResourceNotFoundError(err) { diff --git a/aws/resource_aws_ecs_cluster_test.go b/aws/resource_aws_ecs_cluster_test.go index fff6dc7c17e1..cc1dcbb17017 100644 --- a/aws/resource_aws_ecs_cluster_test.go +++ b/aws/resource_aws_ecs_cluster_test.go @@ -392,7 +392,7 @@ func testAccCheckAWSEcsClusterDestroy(s *terraform.State) error { continue } - out, err := finder.CluserByARN(conn, rs.Primary.ID) + out, err := finder.ClusterByARN(conn, rs.Primary.ID) if err != nil { return err @@ -416,7 +416,7 @@ func testAccCheckAWSEcsClusterExists(resourceName string, cluster *ecs.Cluster) } conn := testAccProvider.Meta().(*AWSClient).ecsconn - output, err := finder.CluserByARN(conn, rs.Primary.ID) + output, err := finder.ClusterByARN(conn, rs.Primary.ID) if err != nil { return fmt.Errorf("error reading ECS Cluster (%s): %w", rs.Primary.ID, err) From 4f0153ddec349a01e797215b6d4d7915570a163b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 14 Jun 2021 14:37:01 -0400 Subject: [PATCH 0424/1208] r/aws_budgets_budget_action: Tweak waiter statuses. --- aws/internal/service/budgets/waiter/waiter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/internal/service/budgets/waiter/waiter.go b/aws/internal/service/budgets/waiter/waiter.go index 532ca43667a8..7aa9e7bc63b2 100644 --- a/aws/internal/service/budgets/waiter/waiter.go +++ b/aws/internal/service/budgets/waiter/waiter.go @@ -15,12 +15,12 @@ func ActionAvailable(conn *budgets.Budgets, id string) (*budgets.Action, error) stateConf := &resource.StateChangeConf{ Pending: []string{ budgets.ActionStatusExecutionInProgress, - budgets.ActionStatusPending, + budgets.ActionStatusStandby, }, Target: []string{ - budgets.ActionStatusStandby, budgets.ActionStatusExecutionSuccess, budgets.ActionStatusExecutionFailure, + budgets.ActionStatusPending, }, Refresh: ActionStatus(conn, id), Timeout: ActionAvailableTimeout, From 47855c0a5f0d60fb8ed3ecad9a380ace6d6363c3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 14 Jun 2021 14:54:24 -0400 Subject: [PATCH 0425/1208] Tweak AppMesh data source acceptance test names. --- aws/data_source_aws_appmesh_mesh_test.go | 6 +++--- aws/data_source_aws_appmesh_virtual_service_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/data_source_aws_appmesh_mesh_test.go b/aws/data_source_aws_appmesh_mesh_test.go index a5a6b8a7d135..f636fa8324bd 100644 --- a/aws/data_source_aws_appmesh_mesh_test.go +++ b/aws/data_source_aws_appmesh_mesh_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func TestAccAWSAppmeshMeshDataSource_basic(t *testing.T) { +func TestAccDataSourceAWSAppmeshMesh_basic(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appmesh_mesh.test" dataSourceName := "data.aws_appmesh_mesh.test" @@ -37,7 +37,7 @@ func TestAccAWSAppmeshMeshDataSource_basic(t *testing.T) { }) } -func TestAccAWSAppmeshMeshDataSource_meshOwner(t *testing.T) { +func TestAccDataSourceAWSAppmeshMesh_meshOwner(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appmesh_mesh.test" dataSourceName := "data.aws_appmesh_mesh.test" @@ -65,7 +65,7 @@ func TestAccAWSAppmeshMeshDataSource_meshOwner(t *testing.T) { }) } -func TestAccAWSAppmeshMeshDataSource_specAndTagsSet(t *testing.T) { +func TestAccDataSourceAWSAppmeshMesh_specAndTagsSet(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appmesh_mesh.test" dataSourceName := "data.aws_appmesh_mesh.test" diff --git a/aws/data_source_aws_appmesh_virtual_service_test.go b/aws/data_source_aws_appmesh_virtual_service_test.go index 365a3bf0ea8b..92c808acc7ff 100644 --- a/aws/data_source_aws_appmesh_virtual_service_test.go +++ b/aws/data_source_aws_appmesh_virtual_service_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func TestAccAWSAppmeshVirtualServiceDataSource_virtualNode(t *testing.T) { +func TestAccDataSourceAWSAppmeshVirtualService_virtualNode(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appmesh_virtual_service.test" dataSourceName := "data.aws_appmesh_virtual_service.test" @@ -39,7 +39,7 @@ func TestAccAWSAppmeshVirtualServiceDataSource_virtualNode(t *testing.T) { }) } -func TestAccAWSAppmeshVirtualServiceDataSource_virtualRouter(t *testing.T) { +func TestAccDataSourceAWSAppmeshVirtualService_virtualRouter(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appmesh_virtual_service.test" dataSourceName := "data.aws_appmesh_virtual_service.test" From 82ecf28b1f70e0def422c3c1047dc1a4a38ec7f2 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Mon, 14 Jun 2021 19:18:06 +0000 Subject: [PATCH 0426/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fc30cfd1bb1..b3db2e05ccc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,18 @@ ## 3.46.0 (Unreleased) + +FEATURES: + +* **New Data Source:** `aws_appmesh_virtual_service` ([#19774](https://github.com/hashicorp/terraform-provider-aws/issues/19774)) +* **New Resource:** `aws_budgets_budget_action` ([#19554](https://github.com/hashicorp/terraform-provider-aws/issues/19554)) + +ENHANCEMENTS: + +* resource/aws_datasync_location_nfs: Add `mount_options` argument. ([#19767](https://github.com/hashicorp/terraform-provider-aws/issues/19767)) +* resource/aws_datasync_location_nfs: Add plan time validation for `on_prem_config.agent_arns`, `server_hostname`, and `subdirectory`. ([#19767](https://github.com/hashicorp/terraform-provider-aws/issues/19767)) +* resource/aws_datasync_location_nfs: Add support for updating. ([#19767](https://github.com/hashicorp/terraform-provider-aws/issues/19767)) +* resource/aws_ecs_cluster: Add plan time validation for `name`. ([#19785](https://github.com/hashicorp/terraform-provider-aws/issues/19785)) +* resource/aws_ecs_cluster: Add support for `configuration`. ([#19785](https://github.com/hashicorp/terraform-provider-aws/issues/19785)) + ## 3.45.0 (June 10, 2021) FEATURES: From c8cae949b04dffe1f23287cb7c74a59d801fde67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Jun 2021 06:06:08 +0000 Subject: [PATCH 0427/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.59 to 1.38.61. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.59...v1.38.61) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 +- .../aws/aws-sdk-go/aws/endpoints/defaults.go | 70 ++++++++++++++++--- .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 65 insertions(+), 15 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 600f83ea5fcb..af2198430626 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.59 + github.com/aws/aws-sdk-go v1.38.61 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index ea4c498586ec..8946ff99ab3f 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.59 h1:rGEMmHdgXSjA2gkdo8Hdwai9mND5X0i+hZetYfABo7g= -github.com/aws/aws-sdk-go v1.38.59/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.61 h1:wizuqQZe0K4iYJ+Slrs0aSQ4P94FAwqBUHwk46Iz5UA= +github.com/aws/aws-sdk-go v1.38.61/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index 9d1266d5d4c9..a07649e9063b 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -1615,11 +1615,12 @@ var awsPartition = partition{ Region: "us-west-2", }, }, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, + "me-south-1": endpoint{}, + "sa-east-1": endpoint{}, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-1": endpoint{}, + "us-west-2": endpoint{}, }, }, "cognito-idp": service{ @@ -1660,11 +1661,12 @@ var awsPartition = partition{ Region: "us-west-2", }, }, - "sa-east-1": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-1": endpoint{}, - "us-west-2": endpoint{}, + "me-south-1": endpoint{}, + "sa-east-1": endpoint{}, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-1": endpoint{}, + "us-west-2": endpoint{}, }, }, "cognito-sync": service{ @@ -7171,6 +7173,12 @@ var awsPartition = partition{ Region: "ap-northeast-2", }, }, + "ap-northeast-3": endpoint{ + Hostname: "waf-regional.ap-northeast-3.amazonaws.com", + CredentialScope: credentialScope{ + Region: "ap-northeast-3", + }, + }, "ap-south-1": endpoint{ Hostname: "waf-regional.ap-south-1.amazonaws.com", CredentialScope: credentialScope{ @@ -7255,6 +7263,12 @@ var awsPartition = partition{ Region: "ap-northeast-2", }, }, + "fips-ap-northeast-3": endpoint{ + Hostname: "waf-regional-fips.ap-northeast-3.amazonaws.com", + CredentialScope: credentialScope{ + Region: "ap-northeast-3", + }, + }, "fips-ap-south-1": endpoint{ Hostname: "waf-regional-fips.ap-south-1.amazonaws.com", CredentialScope: credentialScope{ @@ -8391,6 +8405,42 @@ var awscnPartition = partition{ }, }, }, + "transfer": service{ + + Endpoints: endpoints{ + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, + }, + }, + "waf-regional": service{ + + Endpoints: endpoints{ + "cn-north-1": endpoint{ + Hostname: "waf-regional.cn-north-1.amazonaws.com.cn", + CredentialScope: credentialScope{ + Region: "cn-north-1", + }, + }, + "cn-northwest-1": endpoint{ + Hostname: "waf-regional.cn-northwest-1.amazonaws.com.cn", + CredentialScope: credentialScope{ + Region: "cn-northwest-1", + }, + }, + "fips-cn-north-1": endpoint{ + Hostname: "waf-regional-fips.cn-north-1.amazonaws.com.cn", + CredentialScope: credentialScope{ + Region: "cn-north-1", + }, + }, + "fips-cn-northwest-1": endpoint{ + Hostname: "waf-regional-fips.cn-northwest-1.amazonaws.com.cn", + CredentialScope: credentialScope{ + Region: "cn-northwest-1", + }, + }, + }, + }, "workspaces": service{ Endpoints: endpoints{ diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index 4626e63153af..ef8b3498c241 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.59" +const SDKVersion = "1.38.61" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index f35e2530610e..80713f01fa3f 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.59 +# github.com/aws/aws-sdk-go v1.38.61 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From a677b6a00b91af8ea172c5493705c9b45cdaa8b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Jun 2021 06:06:40 +0000 Subject: [PATCH 0428/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.59 to 1.38.61 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.59 to 1.38.61. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.59...v1.38.61) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a42f554c4865..96b8ff0dcd5e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.59 + github.com/aws/aws-sdk-go v1.38.61 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index 59d57865fd9a..fa0527d79983 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.59 h1:rGEMmHdgXSjA2gkdo8Hdwai9mND5X0i+hZetYfABo7g= -github.com/aws/aws-sdk-go v1.38.59/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.61 h1:wizuqQZe0K4iYJ+Slrs0aSQ4P94FAwqBUHwk46Iz5UA= +github.com/aws/aws-sdk-go v1.38.61/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 80a746570bb89485bafa86e16adfbff660d9f21e Mon Sep 17 00:00:00 2001 From: Nayo Akinyele Date: Tue, 15 Jun 2021 12:08:08 +0100 Subject: [PATCH 0429/1208] Add test for AWSCloudWatchEventBusPolicy_Disappears --- ...ce_aws_cloudwatch_event_bus_policy_test.go | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index d607c7fc956e..1bb8c1f01285 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -1,14 +1,17 @@ package aws import ( + // "encoding/json" "fmt" "testing" + // "time" "github.com/aws/aws-sdk-go/aws" events "github.com/aws/aws-sdk-go/service/cloudwatchevents" "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" + // tfevents "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents" ) func TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { @@ -96,3 +99,25 @@ resource "aws_cloudwatch_event_bus_policy" "test" { } `, name) } + +func TestAccAWSCloudWatchEventBusPolicy_Disappears(t *testing.T) { + resourceName := "aws_cloudwatch_event_bus_policy.test" + busName := acctest.RandomWithPrefix("tf-acc-test-bus") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventBusDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudwatchEventBusPolicyConfig(busName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchEventBusPolicy(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} From 7f87d7408f1297c876feaee039bdf0ff9cb5a4f8 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 15 Jun 2021 14:51:44 +0300 Subject: [PATCH 0430/1208] add unit and refactor --- ...source_aws_cloudwatch_log_metric_filter.go | 73 +++++++++++++++++-- ...e_aws_cloudwatch_log_metric_filter_test.go | 51 +++++++++---- aws/structure.go | 45 ------------ 3 files changed, 103 insertions(+), 66 deletions(-) diff --git a/aws/resource_aws_cloudwatch_log_metric_filter.go b/aws/resource_aws_cloudwatch_log_metric_filter.go index fff90aab0c9d..f6fac4c9e3df 100644 --- a/aws/resource_aws_cloudwatch_log_metric_filter.go +++ b/aws/resource_aws_cloudwatch_log_metric_filter.go @@ -3,10 +3,10 @@ package aws import ( "fmt" "log" + "strconv" "strings" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/cloudwatchlogs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -83,6 +83,12 @@ func resourceAwsCloudWatchLogMetricFilter() *schema.Resource { Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "unit": { + Type: schema.TypeString, + Optional: true, + Default: cloudwatchlogs.StandardUnitNone, + ValidateFunc: validation.StringInSlice(cloudwatchlogs.StandardUnit_Values(), false), + }, }, }, }, @@ -115,7 +121,7 @@ func resourceAwsCloudWatchLogMetricFilterUpdate(d *schema.ResourceData, meta int log.Printf("[DEBUG] Creating/Updating CloudWatch Log Metric Filter: %s", input) _, err := conn.PutMetricFilter(&input) if err != nil { - return fmt.Errorf("Creating/Updating CloudWatch Log Metric Filter failed: %s", err) + return fmt.Errorf("Creating/Updating CloudWatch Log Metric Filter failed: %w", err) } d.SetId(d.Get("name").(string)) @@ -137,7 +143,7 @@ func resourceAwsCloudWatchLogMetricFilterRead(d *schema.ResourceData, meta inter return nil } - return fmt.Errorf("Failed reading CloudWatch Log Metric Filter: %s", err) + return fmt.Errorf("Failed reading CloudWatch Log Metric Filter: %w", err) } log.Printf("[DEBUG] Found CloudWatch Log Metric Filter: %s", mf) @@ -145,7 +151,7 @@ func resourceAwsCloudWatchLogMetricFilterRead(d *schema.ResourceData, meta inter d.Set("name", mf.FilterName) d.Set("pattern", mf.FilterPattern) if err := d.Set("metric_transformation", flattenCloudWatchLogMetricTransformations(mf.MetricTransformations)); err != nil { - return fmt.Errorf("error setting metric_transformation: %s", err) + return fmt.Errorf("error setting metric_transformation: %w", err) } return nil @@ -162,7 +168,7 @@ func lookupCloudWatchLogMetricFilter(conn *cloudwatchlogs.CloudWatchLogs, log.Printf("[DEBUG] Reading CloudWatch Log Metric Filter: %s", input) resp, err := conn.DescribeMetricFilters(&input) if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" { + if isAWSErr(err, cloudwatchlogs.ErrCodeResourceNotFoundException, "") { return nil, &resource.NotFoundError{ Message: fmt.Sprintf("CloudWatch Log Metric Filter %q / %q not found via"+ " initial DescribeMetricFilters call", name, logGroupName), @@ -171,7 +177,7 @@ func lookupCloudWatchLogMetricFilter(conn *cloudwatchlogs.CloudWatchLogs, } } - return nil, fmt.Errorf("Failed describing CloudWatch Log Metric Filter: %s", err) + return nil, fmt.Errorf("Failed describing CloudWatch Log Metric Filter: %w", err) } for _, mf := range resp.MetricFilters { @@ -208,7 +214,7 @@ func resourceAwsCloudWatchLogMetricFilterDelete(d *schema.ResourceData, meta int log.Printf("[INFO] Deleting CloudWatch Log Metric Filter: %s", d.Id()) _, err := conn.DeleteMetricFilter(&input) if err != nil { - return fmt.Errorf("Error deleting CloudWatch Log Metric Filter: %s", err) + return fmt.Errorf("Error deleting CloudWatch Log Metric Filter: %w", err) } log.Println("[INFO] CloudWatch Log Metric Filter deleted") @@ -227,3 +233,56 @@ func resourceAwsCloudWatchLogMetricFilterImport(d *schema.ResourceData, meta int d.SetId(name) return []*schema.ResourceData{d}, nil } + +func expandCloudWatchLogMetricTransformations(m map[string]interface{}) []*cloudwatchlogs.MetricTransformation { + transformation := cloudwatchlogs.MetricTransformation{ + MetricName: aws.String(m["name"].(string)), + MetricNamespace: aws.String(m["namespace"].(string)), + MetricValue: aws.String(m["value"].(string)), + } + + if m["default_value"].(string) != "" { + value, _ := strconv.ParseFloat(m["default_value"].(string), 64) + transformation.DefaultValue = aws.Float64(value) + } + + if dims := m["dimensions"].(map[string]interface{}); len(dims) > 0 { + transformation.Dimensions = expandStringMap(dims) + } + + if v, ok := m["unit"].(string); ok && v != "" { + transformation.Unit = aws.String(v) + } + + return []*cloudwatchlogs.MetricTransformation{&transformation} +} + +func flattenCloudWatchLogMetricTransformations(ts []*cloudwatchlogs.MetricTransformation) []interface{} { + mts := make([]interface{}, 0) + m := make(map[string]interface{}) + + transform := ts[0] + m["name"] = aws.StringValue(transform.MetricName) + m["namespace"] = aws.StringValue(transform.MetricNamespace) + m["value"] = aws.StringValue(transform.MetricValue) + + if transform.DefaultValue == nil { + m["default_value"] = "" + } else { + m["default_value"] = strconv.FormatFloat(aws.Float64Value(transform.DefaultValue), 'f', -1, 64) + } + + if dims := transform.Dimensions; len(dims) > 0 { + m["dimensions"] = pointersMapToStringList(dims) + } else { + m["dimensions"] = nil + } + + if transform.Unit != nil { + m["unit"] = aws.StringValue(transform.Unit) + } + + mts = append(mts, m) + + return mts +} diff --git a/aws/resource_aws_cloudwatch_log_metric_filter_test.go b/aws/resource_aws_cloudwatch_log_metric_filter_test.go index 6823121a15d8..304dfa519313 100644 --- a/aws/resource_aws_cloudwatch_log_metric_filter_test.go +++ b/aws/resource_aws_cloudwatch_log_metric_filter_test.go @@ -14,7 +14,7 @@ import ( func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) { var mf cloudwatchlogs.MetricFilter rInt := acctest.RandInt() - resourceName := "aws_cloudwatch_log_metric_filter.foobar" + resourceName := "aws_cloudwatch_log_metric_filter.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -98,7 +98,30 @@ func TestAccAWSCloudWatchLogMetricFilter_basic(t *testing.T) { }, { Config: testAccAWSCloudwatchLogMetricFilterConfigMany(rInt), - Check: testAccCheckCloudwatchLogMetricFilterManyExist("aws_cloudwatch_log_metric_filter.count_dracula", &mf), + Check: testAccCheckCloudwatchLogMetricFilterManyExist("aws_cloudwatch_log_metric_filter.test", &mf), + }, + }, + }) +} + +func TestAccAWSCloudWatchLogMetricFilter_disappears(t *testing.T) { + var mf cloudwatchlogs.MetricFilter + rInt := acctest.RandInt() + resourceName := "aws_cloudwatch_log_metric_filter.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchlogs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchLogMetricFilterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchLogMetricFilterConfig(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchLogMetricFilterExists(resourceName, &mf), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchLogMetricFilter(), resourceName), + ), + ExpectNonEmptyPlan: true, }, }, }) @@ -233,10 +256,10 @@ func testAccCheckCloudwatchLogMetricFilterManyExist(basename string, mf *cloudwa func testAccAWSCloudWatchLogMetricFilterConfig(rInt int) string { return fmt.Sprintf(` -resource "aws_cloudwatch_log_metric_filter" "foobar" { +resource "aws_cloudwatch_log_metric_filter" "test" { name = "MyAppAccessCount-%d" pattern = "" - log_group_name = aws_cloudwatch_log_group.dada.name + log_group_name = aws_cloudwatch_log_group.test.name metric_transformation { name = "EventCount" @@ -245,7 +268,7 @@ resource "aws_cloudwatch_log_metric_filter" "foobar" { } } -resource "aws_cloudwatch_log_group" "dada" { +resource "aws_cloudwatch_log_group" "test" { name = "MyApp/access-%d.log" } `, rInt, rInt) @@ -253,7 +276,7 @@ resource "aws_cloudwatch_log_group" "dada" { func testAccAWSCloudWatchLogMetricFilterConfigModified(rInt int) string { return fmt.Sprintf(` -resource "aws_cloudwatch_log_metric_filter" "foobar" { +resource "aws_cloudwatch_log_metric_filter" "test" { name = "MyAppAccessCount-%d" pattern = < 0 { - transformation.Dimensions = expandStringMap(dims) - } - - return []*cloudwatchlogs.MetricTransformation{&transformation} -} - -func flattenCloudWatchLogMetricTransformations(ts []*cloudwatchlogs.MetricTransformation) []interface{} { - mts := make([]interface{}, 0) - m := make(map[string]interface{}) - - m["name"] = aws.StringValue(ts[0].MetricName) - m["namespace"] = aws.StringValue(ts[0].MetricNamespace) - m["value"] = aws.StringValue(ts[0].MetricValue) - - if ts[0].DefaultValue == nil { - m["default_value"] = "" - } else { - m["default_value"] = strconv.FormatFloat(aws.Float64Value(ts[0].DefaultValue), 'f', -1, 64) - } - - if dims := ts[0].Dimensions; len(dims) > 0 { - m["dimensions"] = pointersMapToStringList(dims) - } else { - m["dimensions"] = nil - } - - mts = append(mts, m) - - return mts -} - func flattenBeanstalkAsg(list []*elasticbeanstalk.AutoScalingGroup) []string { strs := make([]string, 0, len(list)) for _, r := range list { From 07ae50d4e97541a11e37f878694cb697fd2072c7 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 15 Jun 2021 14:59:05 +0300 Subject: [PATCH 0431/1208] docs --- website/docs/r/cloudwatch_log_metric_filter.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/cloudwatch_log_metric_filter.html.markdown b/website/docs/r/cloudwatch_log_metric_filter.html.markdown index 0d9721a5d869..e3c034090ba8 100644 --- a/website/docs/r/cloudwatch_log_metric_filter.html.markdown +++ b/website/docs/r/cloudwatch_log_metric_filter.html.markdown @@ -47,6 +47,7 @@ The `metric_transformation` block supports the following arguments: * `value` - (Required) What to publish to the metric. For example, if you're counting the occurrences of a particular term like "Error", the value will be "1" for each occurrence. If you're counting the bytes transferred the published value will be the value in the log event. * `default_value` - (Optional) The value to emit when a filter pattern does not match a log event. Conflicts with `dimensions`. * `dimensions` - (Optional) Map of fields to use as dimensions for the metric. Up to 3 dimensions are allowed. Conflicts with `default_value`. +* `unit` - (Optional) The unit to assign to the metric. If you omit this, the unit is set as `None`. ## Attributes Reference From 751c08f1256643e84177ba7a2cd1102c4242bdf3 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 15 Jun 2021 15:00:05 +0300 Subject: [PATCH 0432/1208] changelog --- .changelog/19804.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19804.txt diff --git a/.changelog/19804.txt b/.changelog/19804.txt new file mode 100644 index 000000000000..1cddbbd9d6ea --- /dev/null +++ b/.changelog/19804.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_cloudwatch_log_metric_filter: Add support for `unit` in the `metric_transformation` block. +``` \ No newline at end of file From f90bfec18db1486ccadbd40824bfb872491320a8 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 15 Jun 2021 15:00:24 +0300 Subject: [PATCH 0433/1208] extra test --- ...e_aws_cloudwatch_log_metric_filter_test.go | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/aws/resource_aws_cloudwatch_log_metric_filter_test.go b/aws/resource_aws_cloudwatch_log_metric_filter_test.go index 304dfa519313..2e2e5c7d6143 100644 --- a/aws/resource_aws_cloudwatch_log_metric_filter_test.go +++ b/aws/resource_aws_cloudwatch_log_metric_filter_test.go @@ -127,6 +127,29 @@ func TestAccAWSCloudWatchLogMetricFilter_disappears(t *testing.T) { }) } +func TestAccAWSCloudWatchLogMetricFilter_disappears_logGroup(t *testing.T) { + var mf cloudwatchlogs.MetricFilter + rInt := acctest.RandInt() + resourceName := "aws_cloudwatch_log_metric_filter.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, cloudwatchlogs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchLogMetricFilterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchLogMetricFilterConfig(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchLogMetricFilterExists(resourceName, &mf), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchLogGroup(), "aws_cloudwatch_log_group.test"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckCloudWatchLogMetricFilterName(mf *cloudwatchlogs.MetricFilter, name string) resource.TestCheckFunc { return func(s *terraform.State) error { if name != *mf.FilterName { From eb3106e0e9a18a0e1e55d34aca2a5de1c59ceb82 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 30 Mar 2021 09:38:42 -0400 Subject: [PATCH 0434/1208] Tidy up 'RouteTableStatus'. --- aws/internal/service/ec2/waiter/status.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/aws/internal/service/ec2/waiter/status.go b/aws/internal/service/ec2/waiter/status.go index c4ebc3d62265..6e444caa1791 100644 --- a/aws/internal/service/ec2/waiter/status.go +++ b/aws/internal/service/ec2/waiter/status.go @@ -247,8 +247,6 @@ func InstanceIamInstanceProfile(conn *ec2.EC2, id string) resource.StateRefreshF } const ( - ErrCodeInvalidRouteTableIDNotFound = "InvalidRouteTableID.NotFound" - RouteTableStatusReady = "ready" ) @@ -264,10 +262,6 @@ func RouteTableStatus(conn *ec2.EC2, id string) resource.StateRefreshFunc { return nil, "", err } - if output == nil { - return nil, "", nil - } - return output, RouteTableStatusReady, nil } } From 21838955b4b1af2dcaad4f4f675950c09669b468 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Apr 2021 10:34:11 -0400 Subject: [PATCH 0435/1208] Use 'finder.RouteTableByID' in acceptance test CheckExists and CheckDestroy functions. Acceptance test output: $ make testacc TEST=./aws/ TESTARGS='-run=TestAccAWSRoute_basic\|TestAccAWSRoute_disappears\|TestAccAWSDefaultRouteTable_basic\|TestAccAWSDefaultRouteTable_disappears\|TestAccAWSRouteTableAssociation_Subnet_basic\|TestAccAWSRouteTableAssociation_disappears' ACCTEST_PARALLELISM=2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 2 -run=TestAccAWSRoute_basic\|TestAccAWSRoute_disappears\|TestAccAWSDefaultRouteTable_basic\|TestAccAWSDefaultRouteTable_disappears\|TestAccAWSRouteTableAssociation_Subnet_basic\|TestAccAWSRouteTableAssociation_disappears -timeout 180m === RUN TestAccAWSDefaultRouteTable_basic === PAUSE TestAccAWSDefaultRouteTable_basic === RUN TestAccAWSDefaultRouteTable_disappears_Vpc === PAUSE TestAccAWSDefaultRouteTable_disappears_Vpc === RUN TestAccAWSRouteTableAssociation_Subnet_basic === PAUSE TestAccAWSRouteTableAssociation_Subnet_basic === RUN TestAccAWSRouteTableAssociation_disappears === PAUSE TestAccAWSRouteTableAssociation_disappears === RUN TestAccAWSRoute_basic === PAUSE TestAccAWSRoute_basic === RUN TestAccAWSRoute_disappears === PAUSE TestAccAWSRoute_disappears === RUN TestAccAWSRoute_disappears_RouteTable === PAUSE TestAccAWSRoute_disappears_RouteTable === CONT TestAccAWSDefaultRouteTable_basic === CONT TestAccAWSRoute_basic --- PASS: TestAccAWSDefaultRouteTable_basic (28.58s) === CONT TestAccAWSRoute_disappears_RouteTable --- PASS: TestAccAWSRoute_basic (36.75s) === CONT TestAccAWSRoute_disappears --- PASS: TestAccAWSRoute_disappears_RouteTable (33.95s) === CONT TestAccAWSRouteTableAssociation_Subnet_basic --- PASS: TestAccAWSRoute_disappears (33.06s) === CONT TestAccAWSRouteTableAssociation_disappears --- PASS: TestAccAWSRouteTableAssociation_Subnet_basic (39.37s) === CONT TestAccAWSDefaultRouteTable_disappears_Vpc --- PASS: TestAccAWSRouteTableAssociation_disappears (36.32s) --- PASS: TestAccAWSDefaultRouteTable_disappears_Vpc (14.72s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 116.707s --- aws/resource_aws_default_route_table_test.go | 20 +++---- ...source_aws_route_table_association_test.go | 56 +++++++------------ aws/resource_aws_route_table_test.go | 30 ++++------ 3 files changed, 39 insertions(+), 67 deletions(-) diff --git a/aws/resource_aws_default_route_table_test.go b/aws/resource_aws_default_route_table_test.go index a35e3e36d6f2..d40b73823dab 100644 --- a/aws/resource_aws_default_route_table_test.go +++ b/aws/resource_aws_default_route_table_test.go @@ -5,11 +5,12 @@ import ( "regexp" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestAccAWSDefaultRouteTable_basic(t *testing.T) { @@ -511,22 +512,17 @@ func testAccCheckDefaultRouteTableDestroy(s *terraform.State) error { continue } - // Try to find the resource - resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{ - RouteTableIds: []*string{aws.String(rs.Primary.ID)}, - }) - if err == nil { - if len(resp.RouteTables) > 0 { - return fmt.Errorf("still exist.") - } + _, err := finder.RouteTableByID(conn, rs.Primary.ID) - return nil + if tfresource.NotFound(err) { + continue } - // Verify the error is what we want - if !isAWSErr(err, "InvalidRouteTableID.NotFound", "") { + if err != nil { return err } + + return fmt.Errorf("Route table %s still exists", rs.Primary.ID) } return nil diff --git a/aws/resource_aws_route_table_association_test.go b/aws/resource_aws_route_table_association_test.go index 9f8658093741..f33aa25d0aee 100644 --- a/aws/resource_aws_route_table_association_test.go +++ b/aws/resource_aws_route_table_association_test.go @@ -5,10 +5,11 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestAccAWSRouteTableAssociation_Subnet_basic(t *testing.T) { @@ -240,26 +241,18 @@ func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error { continue } - // Try to find the resource - resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{ - RouteTableIds: []*string{aws.String(rs.Primary.Attributes["route_table_id"])}, - }) + routeTable, err := finder.RouteTableByID(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + if err != nil { - // Verify the error is what we want - ec2err, ok := err.(awserr.Error) - if !ok { - return err - } - if ec2err.Code() != "InvalidRouteTableID.NotFound" { - return err - } - return nil + return err } - rt := resp.RouteTables[0] - if len(rt.Associations) > 0 { - return fmt.Errorf( - "route table %s has associations", *rt.RouteTableId) + if len(routeTable.Associations) > 0 { + return fmt.Errorf("Route table %s has associations", aws.StringValue(routeTable.RouteTableId)) } } @@ -278,33 +271,22 @@ func testAccCheckRouteTableAssociationExists(n string, rta *ec2.RouteTableAssoci } conn := testAccProvider.Meta().(*AWSClient).ec2conn - resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{ - RouteTableIds: []*string{aws.String(rs.Primary.Attributes["route_table_id"])}, - }) + + routeTable, err := finder.RouteTableByID(conn, rs.Primary.Attributes["route_table_id"]) + if err != nil { return err } - if len(resp.RouteTables) == 0 { - return fmt.Errorf("Route Table not found") - } - if len(resp.RouteTables[0].Associations) == 0 { - return fmt.Errorf("no associations found for Route Table %q", rs.Primary.Attributes["route_table_id"]) - } - - found := false - for _, association := range resp.RouteTables[0].Associations { - if rs.Primary.ID == *association.RouteTableAssociationId { - found = true + for _, association := range routeTable.Associations { + if rs.Primary.ID == aws.StringValue(association.RouteTableAssociationId) { *rta = *association - break + + return nil } } - if !found { - return fmt.Errorf("Association %q not found on Route Table %q", rs.Primary.ID, rs.Primary.Attributes["route_table_id"]) - } - return nil + return fmt.Errorf("Association %q not found on Route Table %q", rs.Primary.ID, rs.Primary.Attributes["route_table_id"]) } } diff --git a/aws/resource_aws_route_table_test.go b/aws/resource_aws_route_table_test.go index e331af27ef85..fe046a1837fb 100644 --- a/aws/resource_aws_route_table_test.go +++ b/aws/resource_aws_route_table_test.go @@ -14,6 +14,8 @@ import ( "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -1083,17 +1085,14 @@ func testAccCheckRouteTableExists(n string, v *ec2.RouteTable) resource.TestChec } conn := testAccProvider.Meta().(*AWSClient).ec2conn - resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{ - RouteTableIds: []*string{aws.String(rs.Primary.ID)}, - }) + + routeTable, err := finder.RouteTableByID(conn, rs.Primary.ID) + if err != nil { return err } - if len(resp.RouteTables) == 0 { - return fmt.Errorf("RouteTable not found") - } - *v = *resp.RouteTables[0] + *v = *routeTable return nil } @@ -1107,22 +1106,17 @@ func testAccCheckRouteTableDestroy(s *terraform.State) error { continue } - // Try to find the resource - resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{ - RouteTableIds: []*string{aws.String(rs.Primary.ID)}, - }) - if err == nil { - if len(resp.RouteTables) > 0 { - return fmt.Errorf("still exist.") - } + _, err := finder.RouteTableByID(conn, rs.Primary.ID) - return nil + if tfresource.NotFound(err) { + continue } - // Verify the error is what we want - if !isAWSErr(err, "InvalidRouteTableID.NotFound", "") { + if err != nil { return err } + + return fmt.Errorf("Route table %s still exists", rs.Primary.ID) } return nil From 999fac869a732abb5b43af9e9cdf717165be4a8b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 4 May 2021 17:02:45 -0400 Subject: [PATCH 0436/1208] Add 'createRoute'. --- aws/resource_aws_route.go | 51 +++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/aws/resource_aws_route.go b/aws/resource_aws_route.go index 9465f48fce26..6ec5001ce26b 100644 --- a/aws/resource_aws_route.go +++ b/aws/resource_aws_route.go @@ -230,27 +230,7 @@ func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error { } log.Printf("[DEBUG] Creating Route: %s", input) - err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { - _, err = conn.CreateRoute(input) - - if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidParameterException) { - return resource.RetryableError(err) - } - - if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidTransitGatewayIDNotFound) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return nil - }) - - if tfresource.TimedOut(err) { - _, err = conn.CreateRoute(input) - } + err = createRoute(conn, input, d.Timeout(schema.TimeoutCreate)) if err != nil { return fmt.Errorf("error creating Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) @@ -523,3 +503,32 @@ func routeTargetAttribute(d *schema.ResourceData) (string, string, error) { return "", "", fmt.Errorf("route target attribute not specified") } + +// createRoute attempts to create a route. +// The specified eventual consistency timeout is respected. +// Any error is returned. +func createRoute(conn *ec2.EC2, input *ec2.CreateRouteInput, timeout time.Duration) error { + err := resource.Retry(timeout, func() *resource.RetryError { + _, err := conn.CreateRoute(input) + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidParameterException) { + return resource.RetryableError(err) + } + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidTransitGatewayIDNotFound) { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + _, err = conn.CreateRoute(input) + } + + return nil +} From f962e2b5a9ed4c4cbca1e27e1e84ce79664a85e1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 4 May 2021 17:05:43 -0400 Subject: [PATCH 0437/1208] Add 'CanonicalCIDRBlock' to 'internal/net' package and remove "local" 'canonicalCidrBlock' and 'cidrBlocksEqual'. --- aws/diff_suppress_funcs.go | 3 +- aws/ec2_transit_gateway.go | 5 +-- aws/internal/net/cidr.go | 11 ++++++ aws/internal/net/cidr_test.go | 17 ++++++++++ aws/resource_aws_route_table.go | 3 +- aws/resource_aws_wafv2_ip_set.go | 3 +- aws/validators.go | 37 +++------------------ aws/validators_test.go | 57 -------------------------------- 8 files changed, 41 insertions(+), 95 deletions(-) diff --git a/aws/diff_suppress_funcs.go b/aws/diff_suppress_funcs.go index bfa7146c7f5b..911559ea5a78 100644 --- a/aws/diff_suppress_funcs.go +++ b/aws/diff_suppress_funcs.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" awspolicy "github.com/jen20/awspolicyequivalence" + tfnet "github.com/terraform-providers/terraform-provider-aws/aws/internal/net" ) func suppressEquivalentAwsPolicyDiffs(k, old, new string, d *schema.ResourceData) bool { @@ -131,7 +132,7 @@ func suppressEquivalentJsonOrYamlDiffs(k, old, new string, d *schema.ResourceDat // suppressEqualCIDRBlockDiffs provides custom difference suppression for CIDR blocks // that have different string values but represent the same CIDR. func suppressEqualCIDRBlockDiffs(k, old, new string, d *schema.ResourceData) bool { - return cidrBlocksEqual(old, new) + return tfnet.CIDRBlocksEqual(old, new) } // suppressEquivalentTime suppresses differences for time values that represent the same diff --git a/aws/ec2_transit_gateway.go b/aws/ec2_transit_gateway.go index aa8bb57714c4..b8d211e4f24e 100644 --- a/aws/ec2_transit_gateway.go +++ b/aws/ec2_transit_gateway.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + tfnet "github.com/terraform-providers/terraform-provider-aws/aws/internal/net" ) func decodeEc2TransitGatewayRouteID(id string) (string, string, error) { @@ -109,8 +110,8 @@ func ec2DescribeTransitGatewayRoute(conn *ec2.EC2, transitGatewayRouteTableID, d if route == nil { continue } - if cidrBlocksEqual(aws.StringValue(route.DestinationCidrBlock), destination) { - cidrString := canonicalCidrBlock(aws.StringValue(route.DestinationCidrBlock)) + if tfnet.CIDRBlocksEqual(aws.StringValue(route.DestinationCidrBlock), destination) { + cidrString := tfnet.CanonicalCIDRBlock(aws.StringValue(route.DestinationCidrBlock)) route.DestinationCidrBlock = aws.String(cidrString) return route, nil } diff --git a/aws/internal/net/cidr.go b/aws/internal/net/cidr.go index 5d4e8db05259..77ac94522f2c 100644 --- a/aws/internal/net/cidr.go +++ b/aws/internal/net/cidr.go @@ -21,3 +21,14 @@ func CIDRBlocksEqual(cidr1, cidr2 string) bool { return ip2.String() == ip1.String() && ipnet2.String() == ipnet1.String() } + +// CanonicalCIDRBlock returns the canonical representation of a CIDR block. +// This function is especially useful for hash functions for sets which include IPv6 CIDR blocks. +func CanonicalCIDRBlock(cidr string) string { + _, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + return cidr + } + + return ipnet.String() +} diff --git a/aws/internal/net/cidr_test.go b/aws/internal/net/cidr_test.go index a557b64a5797..ce1ccefa3244 100644 --- a/aws/internal/net/cidr_test.go +++ b/aws/internal/net/cidr_test.go @@ -24,3 +24,20 @@ func Test_CIDRBlocksEqual(t *testing.T) { } } } + +func Test_CanonicalCIDRBlock(t *testing.T) { + for _, ts := range []struct { + cidr string + expected string + }{ + {"10.2.2.0/24", "10.2.2.0/24"}, + {"::/0", "::/0"}, + {"::0/0", "::/0"}, + {"", ""}, + } { + got := CanonicalCIDRBlock(ts.cidr) + if ts.expected != got { + t.Fatalf("CanonicalCIDRBlock(%q) should be: %q, got: %q", ts.cidr, ts.expected, got) + } + } +} diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index 3469147c8362..1bc78fe43535 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + tfnet "github.com/terraform-providers/terraform-provider-aws/aws/internal/net" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" @@ -574,7 +575,7 @@ func resourceAwsRouteTableHash(v interface{}) int { } if v, ok := m["ipv6_cidr_block"]; ok { - buf.WriteString(fmt.Sprintf("%s-", canonicalCidrBlock(v.(string)))) + buf.WriteString(fmt.Sprintf("%s-", tfnet.CanonicalCIDRBlock(v.(string)))) } if v, ok := m["cidr_block"]; ok { diff --git a/aws/resource_aws_wafv2_ip_set.go b/aws/resource_aws_wafv2_ip_set.go index 77d653cb6b96..adc2ee53e425 100644 --- a/aws/resource_aws_wafv2_ip_set.go +++ b/aws/resource_aws_wafv2_ip_set.go @@ -12,6 +12,7 @@ import ( "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" + tfnet "github.com/terraform-providers/terraform-provider-aws/aws/internal/net" ) func resourceAwsWafv2IPSet() *schema.Resource { @@ -50,7 +51,7 @@ func resourceAwsWafv2IPSet() *schema.Resource { for _, ov := range oldAddresses { hasAddress := false for _, nv := range newAddresses { - if cidrBlocksEqual(ov.(string), nv.(string)) { + if tfnet.CIDRBlocksEqual(ov.(string), nv.(string)) { hasAddress = true break } diff --git a/aws/validators.go b/aws/validators.go index f2b09daad567..f0b4b2a5aee6 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -20,6 +20,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + tfnet "github.com/terraform-providers/terraform-provider-aws/aws/internal/net" ) const ( @@ -833,7 +834,7 @@ func validateCIDRBlock(cidr string) error { return fmt.Errorf("%q is not a valid CIDR block: %w", cidr, err) } - if !cidrBlocksEqual(cidr, ipnet.String()) { + if !tfnet.CIDRBlocksEqual(cidr, ipnet.String()) { return fmt.Errorf("%q is not a valid CIDR block; did you mean %q?", cidr, ipnet) } @@ -855,7 +856,7 @@ func validateIpv4CIDRBlock(cidr string) error { return fmt.Errorf("%q is not a valid IPv4 CIDR block", cidr) } - if !cidrBlocksEqual(cidr, ipnet.String()) { + if !tfnet.CIDRBlocksEqual(cidr, ipnet.String()) { return fmt.Errorf("%q is not a valid IPv4 CIDR block; did you mean %q?", cidr, ipnet) } @@ -877,43 +878,13 @@ func validateIpv6CIDRBlock(cidr string) error { return fmt.Errorf("%q is not a valid IPv6 CIDR block", cidr) } - if !cidrBlocksEqual(cidr, ipnet.String()) { + if !tfnet.CIDRBlocksEqual(cidr, ipnet.String()) { return fmt.Errorf("%q is not a valid IPv6 CIDR block; did you mean %q?", cidr, ipnet) } return nil } -// TODO Replace with tfnet.CIDRBlocksEqual. -// cidrBlocksEqual returns whether or not two CIDR blocks are equal: -// - Both CIDR blocks parse to an IP address and network -// - The string representation of the IP addresses are equal -// - The string representation of the networks are equal -// This function is especially useful for IPv6 CIDR blocks which have multiple valid representations. -func cidrBlocksEqual(cidr1, cidr2 string) bool { - ip1, ipnet1, err := net.ParseCIDR(cidr1) - if err != nil { - return false - } - ip2, ipnet2, err := net.ParseCIDR(cidr2) - if err != nil { - return false - } - - return ip2.String() == ip1.String() && ipnet2.String() == ipnet1.String() -} - -// canonicalCidrBlock returns the canonical representation of a CIDR block. -// This function is especially useful for hash functions for sets which include IPv6 CIDR blocks. -func canonicalCidrBlock(cidr string) string { - _, ipnet, err := net.ParseCIDR(cidr) - if err != nil { - return cidr - } - - return ipnet.String() -} - func validateHTTPMethod() schema.SchemaValidateFunc { return validation.StringInSlice([]string{ "ANY", diff --git a/aws/validators_test.go b/aws/validators_test.go index 835ad78bc0b3..8ac81ed7b262 100644 --- a/aws/validators_test.go +++ b/aws/validators_test.go @@ -653,63 +653,6 @@ func TestValidateIpv6CIDRBlock(t *testing.T) { } } -func TestCidrBlocksEqual(t *testing.T) { - for _, ts := range []struct { - cidr1 string - cidr2 string - equal bool - }{ - {"10.2.2.0/24", "10.2.2.0/24", true}, - {"10.2.2.0/1234", "10.2.2.0/24", false}, - {"10.2.2.0/24", "10.2.2.0/1234", false}, - {"2001::/15", "2001::/15", true}, - {"::/0", "2001::/15", false}, - {"::/0", "::0/0", true}, - {"", "", false}, - } { - equal := cidrBlocksEqual(ts.cidr1, ts.cidr2) - if ts.equal != equal { - t.Fatalf("cidrBlocksEqual(%q, %q) should be: %t", ts.cidr1, ts.cidr2, ts.equal) - } - } -} -func TestCanonicalCidrBlock(t *testing.T) { - for _, ts := range []struct { - cidr string - expected string - }{ - {"10.2.2.0/24", "10.2.2.0/24"}, - {"10.2.2.5/24", "10.2.2.0/24"}, - {"::/0", "::/0"}, - {"::0/0", "::/0"}, - {"2001::/15", "2000::/15"}, - {"2001:db8::1/120", "2001:db8::/120"}, - {"", ""}, - } { - got := canonicalCidrBlock(ts.cidr) - if ts.expected != got { - t.Fatalf("canonicalCidrBlock(%q) should be: %q, got: %q", ts.cidr, ts.expected, got) - } - } -} - -func Test_canonicalCidrBlock(t *testing.T) { - for _, ts := range []struct { - cidr string - expected string - }{ - {"10.2.2.0/24", "10.2.2.0/24"}, - {"::/0", "::/0"}, - {"::0/0", "::/0"}, - {"", ""}, - } { - got := canonicalCidrBlock(ts.cidr) - if ts.expected != got { - t.Fatalf("canonicalCidrBlock(%q) should be: %q, got: %q", ts.cidr, ts.expected, got) - } - } -} - func TestValidateLogMetricFilterName(t *testing.T) { validNames := []string{ "YadaHereAndThere", From cfdcac206fa7d51c46047c234ae38dcb2c1e36d9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 11 May 2021 16:52:04 -0400 Subject: [PATCH 0438/1208] r/aws_route_table: Tidy up Create, Read and Delete. --- aws/internal/service/ec2/errors.go | 6 +- aws/resource_aws_route.go | 2 +- aws/resource_aws_route_table.go | 413 +++++++++++++++++++++-------- 3 files changed, 308 insertions(+), 113 deletions(-) diff --git a/aws/internal/service/ec2/errors.go b/aws/internal/service/ec2/errors.go index 169575c71ab2..f4f93f28cd10 100644 --- a/aws/internal/service/ec2/errors.go +++ b/aws/internal/service/ec2/errors.go @@ -9,8 +9,10 @@ import ( ) const ( - ErrCodeInvalidParameterException = "InvalidParameterException" - ErrCodeInvalidParameterValue = "InvalidParameterValue" + ErrCodeGatewayNotAttached = "Gateway.NotAttached" + ErrCodeInvalidAssociationIDNotFound = "InvalidAssociationID.NotFound" + ErrCodeInvalidParameterException = "InvalidParameterException" + ErrCodeInvalidParameterValue = "InvalidParameterValue" ) const ( diff --git a/aws/resource_aws_route.go b/aws/resource_aws_route.go index 6ec5001ce26b..3542ba991807 100644 --- a/aws/resource_aws_route.go +++ b/aws/resource_aws_route.go @@ -530,5 +530,5 @@ func createRoute(conn *ec2.EC2, input *ec2.CreateRouteInput, timeout time.Durati _, err = conn.CreateRoute(input) } - return nil + return err } diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index 1bc78fe43535..bdd398df4973 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -10,12 +10,14 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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/hashcode" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" tfnet "github.com/terraform-providers/terraform-provider-aws/aws/internal/net" + tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" @@ -32,12 +34,12 @@ var routeTableValidTargets = []string{ "egress_only_gateway_id", "gateway_id", "instance_id", - "nat_gateway_id", "local_gateway_id", + "nat_gateway_id", + "network_interface_id", "transit_gateway_id", "vpc_endpoint_id", "vpc_peering_connection_id", - "network_interface_id", } func resourceAwsRouteTable() *schema.Resource { @@ -55,10 +57,12 @@ func resourceAwsRouteTable() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "owner_id": { Type: schema.TypeString, Computed: true, }, + "propagating_vgws": { Type: schema.TypeSet, Optional: true, @@ -66,6 +70,7 @@ func resourceAwsRouteTable() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, + "route": { Type: schema.TypeSet, Computed: true, @@ -144,8 +149,10 @@ func resourceAwsRouteTable() *schema.Resource { }, Set: resourceAwsRouteTableHash, }, + "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), + "vpc_id": { Type: schema.TypeString, Required: true, @@ -162,30 +169,68 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) - // Create the routing table - createOpts := &ec2.CreateRouteTableInput{ + input := &ec2.CreateRouteTableInput{ VpcId: aws.String(d.Get("vpc_id").(string)), TagSpecifications: ec2TagSpecificationsFromKeyValueTags(tags, ec2.ResourceTypeRouteTable), } - log.Printf("[DEBUG] RouteTable create config: %#v", createOpts) - resp, err := conn.CreateRouteTable(createOpts) + log.Printf("[DEBUG] Creating Route Table: %s", input) + output, err := conn.CreateRouteTable(input) + if err != nil { - return fmt.Errorf("error creating route table: %w", err) + return fmt.Errorf("error creating Route Table: %w", err) } - // Get the ID and store it - rt := resp.RouteTable - d.SetId(aws.StringValue(rt.RouteTableId)) - log.Printf("[INFO] Route Table ID: %s", d.Id()) + d.SetId(aws.StringValue(output.RouteTable.RouteTableId)) - // Wait for the route table to become available - log.Printf("[DEBUG] Waiting for route table (%s) to become available", d.Id()) if _, err := waiter.RouteTableReady(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for route table (%s) to become available: %w", d.Id(), err) + return fmt.Errorf("error waiting for Route Table (%s) to become available: %w", d.Id(), err) } - return resourceAwsRouteTableUpdate(d, meta) + if v, ok := d.GetOk("propagating_vgws"); ok && v.(*schema.Set).Len() > 0 { + for _, v := range v.(*schema.Set).List() { + v := v.(string) + + log.Printf("[DEBUG] Enabling Route Table (%s) VPN Gateway (%s) route propagation", d.Id(), v) + err = enableVgwRoutePropagation(conn, d.Id(), v, waiter.PropagationTimeout) + + if err != nil { + return fmt.Errorf("error enabling Route Table (%s) VPN Gateway (%s) route propagation: %w", d.Id(), v, err) + } + } + } + + if v, ok := d.GetOk("route"); ok && v.(*schema.Set).Len() > 0 { + for _, v := range v.(*schema.Set).List() { + v := v.(map[string]interface{}) + + if err := validateNestedExactlyOneOf(v, routeTableValidDestinations); err != nil { + return fmt.Errorf("error creating route: %w", err) + } + if err := validateNestedExactlyOneOf(v, routeTableValidTargets); err != nil { + return fmt.Errorf("error creating route: %w", err) + } + + _, destination := routeTableRouteDestinationAttribute(v) + + input := expandEc2CreateRouteInput(v) + + if input == nil { + continue + } + + input.RouteTableId = aws.String(d.Id()) + + log.Printf("[DEBUG] Creating Route: %s", input) + err = createRoute(conn, input, waiter.PropagationTimeout) + + if err != nil { + return fmt.Errorf("error creating Route for Route Table (%s) with destination (%s): %w", d.Id(), destination, err) + } + } + } + + return resourceAwsRouteTableRead(d, meta) } func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error { @@ -196,88 +241,28 @@ func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error { routeTable, err := finder.RouteTableByID(conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { - log.Printf("[WARN] Route table (%s) not found, removing from state", d.Id()) + log.Printf("[WARN] Route Table (%s) not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error reading route table (%s): %w", d.Id(), err) + return fmt.Errorf("error reading Route Table (%s): %w", d.Id(), err) } d.Set("vpc_id", routeTable.VpcId) propagatingVGWs := make([]string, 0, len(routeTable.PropagatingVgws)) - for _, vgw := range routeTable.PropagatingVgws { - propagatingVGWs = append(propagatingVGWs, aws.StringValue(vgw.GatewayId)) + for _, v := range routeTable.PropagatingVgws { + propagatingVGWs = append(propagatingVGWs, aws.StringValue(v.GatewayId)) + } + if err := d.Set("propagating_vgws", propagatingVGWs); err != nil { + return fmt.Errorf("error setting propagating_vgws: %w", err) } - d.Set("propagating_vgws", propagatingVGWs) - - // Create an empty schema.Set to hold all routes - route := &schema.Set{F: resourceAwsRouteTableHash} - - // Loop through the routes and add them to the set - for _, r := range routeTable.Routes { - if aws.StringValue(r.GatewayId) == "local" { - continue - } - - if aws.StringValue(r.Origin) == ec2.RouteOriginEnableVgwRoutePropagation { - continue - } - - if r.DestinationPrefixListId != nil && strings.HasPrefix(aws.StringValue(r.GatewayId), "vpce-") { - // Skipping because VPC endpoint routes are handled separately - // See aws_vpc_endpoint - continue - } - - m := make(map[string]interface{}) - - if r.DestinationCidrBlock != nil { - m["cidr_block"] = aws.StringValue(r.DestinationCidrBlock) - } - if r.DestinationIpv6CidrBlock != nil { - m["ipv6_cidr_block"] = aws.StringValue(r.DestinationIpv6CidrBlock) - } - if r.DestinationPrefixListId != nil { - m["destination_prefix_list_id"] = aws.StringValue(r.DestinationPrefixListId) - } - if r.CarrierGatewayId != nil { - m["carrier_gateway_id"] = aws.StringValue(r.CarrierGatewayId) - } - if r.EgressOnlyInternetGatewayId != nil { - m["egress_only_gateway_id"] = aws.StringValue(r.EgressOnlyInternetGatewayId) - } - if r.GatewayId != nil { - if strings.HasPrefix(aws.StringValue(r.GatewayId), "vpce-") { - m["vpc_endpoint_id"] = aws.StringValue(r.GatewayId) - } else { - m["gateway_id"] = aws.StringValue(r.GatewayId) - } - } - if r.NatGatewayId != nil { - m["nat_gateway_id"] = aws.StringValue(r.NatGatewayId) - } - if r.LocalGatewayId != nil { - m["local_gateway_id"] = aws.StringValue(r.LocalGatewayId) - } - if r.InstanceId != nil { - m["instance_id"] = aws.StringValue(r.InstanceId) - } - if r.TransitGatewayId != nil { - m["transit_gateway_id"] = aws.StringValue(r.TransitGatewayId) - } - if r.VpcPeeringConnectionId != nil { - m["vpc_peering_connection_id"] = aws.StringValue(r.VpcPeeringConnectionId) - } - if r.NetworkInterfaceId != nil { - m["network_interface_id"] = aws.StringValue(r.NetworkInterfaceId) - } - route.Add(m) + if err := d.Set("route", flattenEc2Routes(routeTable.Routes)); err != nil { + return fmt.Errorf("error setting route: %w", err) } - d.Set("route", route) // Tags tags := keyvaluetags.Ec2KeyValueTags(routeTable.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -518,50 +503,38 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - // First request the routing table since we'll have to disassociate - // all the subnets first. - rt, err := waiter.RouteTableReady(conn, d.Id()) + routeTable, err := finder.RouteTableByID(conn, d.Id()) if err != nil { - return fmt.Errorf("error getting route table (%s) prior to disassociating associations: %w", d.Id(), err) + return fmt.Errorf("error reading Route Table (%s): %w", d.Id(), err) } // Do all the disassociations - for _, a := range rt.Associations { - log.Printf("[INFO] Disassociating association: %s", aws.StringValue(a.RouteTableAssociationId)) - _, err := conn.DisassociateRouteTable(&ec2.DisassociateRouteTableInput{ - AssociationId: a.RouteTableAssociationId, - }) - if err != nil { - // First check if the association ID is not found. If this - // is the case, then it was already disassociated somehow, - // and that is okay. - if isAWSErr(err, "InvalidAssociationID.NotFound", "") { - err = nil - } - } - if err != nil { - return err + for _, v := range routeTable.Associations { + v := aws.StringValue(v.RouteTableAssociationId) + + if err := disassociateRouteTable(conn, v); err != nil { + return fmt.Errorf("error disassociating Route Table (%s) %s: %w", d.Id(), v, err) } } - // Delete the route table log.Printf("[INFO] Deleting Route Table: %s", d.Id()) _, err = conn.DeleteRouteTable(&ec2.DeleteRouteTableInput{ RouteTableId: aws.String(d.Id()), }) - if err != nil { - if isAWSErr(err, "InvalidRouteTableID.NotFound", "") { - return nil - } - return fmt.Errorf("error deleting route table: %w", err) + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidRouteTableIDNotFound) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Route Table (%s): %w", d.Id(), err) } // Wait for the route table to really destroy log.Printf("[DEBUG] Waiting for route table (%s) deletion", d.Id()) if _, err := waiter.RouteTableDeleted(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for route table (%s) deletion: %w", d.Id(), err) + return fmt.Errorf("error waiting for Route Table (%s) deletion: %w", d.Id(), err) } return nil @@ -632,3 +605,223 @@ func resourceAwsRouteTableHash(v interface{}) int { return hashcode.String(buf.String()) } + +func disassociateRouteTable(conn *ec2.EC2, associationID string) error { + _, err := conn.DisassociateRouteTable(&ec2.DisassociateRouteTableInput{ + AssociationId: aws.String(associationID), + }) + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidAssociationIDNotFound) { + return nil + } + + return nil +} + +// enableVgwRoutePropagation attempts to enable VGW route propagation. +// The specified eventual consistency timeout is respected. +// Any error is returned. +func enableVgwRoutePropagation(conn *ec2.EC2, routeTableID, gatewayID string, timeout time.Duration) error { + input := &ec2.EnableVgwRoutePropagationInput{ + GatewayId: aws.String(gatewayID), + RouteTableId: aws.String(routeTableID), + } + + err := resource.Retry(timeout, func() *resource.RetryError { + _, err := conn.EnableVgwRoutePropagation(input) + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeGatewayNotAttached) { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + _, err = conn.EnableVgwRoutePropagation(input) + } + + return err +} + +func expandEc2CreateRouteInput(tfMap map[string]interface{}) *ec2.CreateRouteInput { + if tfMap == nil { + return nil + } + + apiObject := &ec2.CreateRouteInput{} + + if v, ok := tfMap["cidr_block"].(string); ok && v != "" { + apiObject.DestinationCidrBlock = aws.String(v) + } + + if v, ok := tfMap["ipv6_cidr_block"].(string); ok && v != "" { + apiObject.DestinationIpv6CidrBlock = aws.String(v) + } + + if v, ok := tfMap["destination_prefix_list_id"].(string); ok && v != "" { + apiObject.DestinationPrefixListId = aws.String(v) + } + + if v, ok := tfMap["carrier_gateway_id"].(string); ok && v != "" { + apiObject.CarrierGatewayId = aws.String(v) + } + + if v, ok := tfMap["egress_only_gateway_id"].(string); ok && v != "" { + apiObject.EgressOnlyInternetGatewayId = aws.String(v) + } + + if v, ok := tfMap["gateway_id"].(string); ok && v != "" { + apiObject.GatewayId = aws.String(v) + } + + if v, ok := tfMap["instance_id"].(string); ok && v != "" { + apiObject.InstanceId = aws.String(v) + } + + if v, ok := tfMap["local_gateway_id"].(string); ok && v != "" { + apiObject.LocalGatewayId = aws.String(v) + } + + if v, ok := tfMap["nat_gateway_id"].(string); ok && v != "" { + apiObject.NatGatewayId = aws.String(v) + } + + if v, ok := tfMap["network_interface_id"].(string); ok && v != "" { + apiObject.NetworkInterfaceId = aws.String(v) + } + + if v, ok := tfMap["transit_gateway_id"].(string); ok && v != "" { + apiObject.TransitGatewayId = aws.String(v) + } + + if v, ok := tfMap["vpc_endpoint_id"].(string); ok && v != "" { + apiObject.VpcEndpointId = aws.String(v) + } + + if v, ok := tfMap["vpc_peering_connection_id"].(string); ok && v != "" { + apiObject.VpcPeeringConnectionId = aws.String(v) + } + + return apiObject +} + +func flattenEc2Route(apiObject *ec2.Route) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.DestinationCidrBlock; v != nil { + tfMap["cidr_block"] = aws.StringValue(v) + } + + if v := apiObject.DestinationIpv6CidrBlock; v != nil { + tfMap["ipv6_cidr_block"] = aws.StringValue(v) + } + + if v := apiObject.DestinationPrefixListId; v != nil { + tfMap["destination_prefix_list_id"] = aws.StringValue(v) + } + + if v := apiObject.CarrierGatewayId; v != nil { + tfMap["carrier_gateway_id"] = aws.StringValue(v) + } + + if v := apiObject.EgressOnlyInternetGatewayId; v != nil { + tfMap["egress_only_gateway_id"] = aws.StringValue(v) + } + + if v := apiObject.GatewayId; v != nil { + if strings.HasPrefix(aws.StringValue(v), "vpce-") { + tfMap["vpc_endpoint_id"] = aws.StringValue(v) + } else { + tfMap["gateway_id"] = aws.StringValue(v) + } + } + + if v := apiObject.InstanceId; v != nil { + tfMap["instance_id"] = aws.StringValue(v) + } + + if v := apiObject.LocalGatewayId; v != nil { + tfMap["local_gateway_id"] = aws.StringValue(v) + } + + if v := apiObject.NetworkInterfaceId; v != nil { + tfMap["nat_gateway_id"] = aws.StringValue(v) + } + + if v := apiObject.TransitGatewayId; v != nil { + tfMap["network_interface_id"] = aws.StringValue(v) + } + + if v := apiObject.TransitGatewayId; v != nil { + tfMap["transit_gateway_id"] = aws.StringValue(v) + } + + if v := apiObject.VpcPeeringConnectionId; v != nil { + tfMap["vpc_peering_connection_id"] = aws.StringValue(v) + } + + return tfMap +} + +func flattenEc2Routes(apiObjects []*ec2.Route) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var tfList []interface{} + + for _, apiObject := range apiObjects { + if apiObject == nil { + continue + } + + if aws.StringValue(apiObject.GatewayId) == "local" { + continue + } + + if aws.StringValue(apiObject.Origin) == ec2.RouteOriginEnableVgwRoutePropagation { + continue + } + + if apiObject.DestinationPrefixListId != nil && strings.HasPrefix(aws.StringValue(apiObject.GatewayId), "vpce-") { + // Skipping because VPC endpoint routes are handled separately + // See aws_vpc_endpoint + continue + } + + tfList = append(tfList, flattenEc2Route(apiObject)) + } + + return tfList +} + +// routeTableRouteDestinationAttribute returns the attribute key and value of the route table route's destination. +func routeTableRouteDestinationAttribute(m map[string]interface{}) (string, string) { + for _, key := range routeTableValidDestinations { + if v, ok := m[key].(string); ok && v != "" { + return key, v + } + } + + return "", "" +} + +// routeTableRouteTargetAttribute returns the attribute key and value of the route table route's target. +func routeTableRouteTargetAttribute(m map[string]interface{}) (string, string) { + for _, key := range routeTableValidTargets { + if v, ok := m[key].(string); ok && v != "" { + return key, v + } + } + + return "", "" +} From 87464d3b155efa55e5061981ac739cb19458c112 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 12 May 2021 09:35:35 -0400 Subject: [PATCH 0439/1208] r/aws_route_table: Simplify route table disassociation. --- aws/resource_aws_route_table.go | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index bdd398df4973..09ac9bcadbe8 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -513,8 +513,12 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error for _, v := range routeTable.Associations { v := aws.StringValue(v.RouteTableAssociationId) - if err := disassociateRouteTable(conn, v); err != nil { - return fmt.Errorf("error disassociating Route Table (%s) %s: %w", d.Id(), v, err) + r := resourceAwsRouteTableAssociation() + d := r.Data(nil) + d.SetId(v) + + if err := r.Delete(d, meta); err != nil { + return err } } @@ -606,18 +610,6 @@ func resourceAwsRouteTableHash(v interface{}) int { return hashcode.String(buf.String()) } -func disassociateRouteTable(conn *ec2.EC2, associationID string) error { - _, err := conn.DisassociateRouteTable(&ec2.DisassociateRouteTableInput{ - AssociationId: aws.String(associationID), - }) - - if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidAssociationIDNotFound) { - return nil - } - - return nil -} - // enableVgwRoutePropagation attempts to enable VGW route propagation. // The specified eventual consistency timeout is respected. // Any error is returned. From c1d877de77353f1f655d5301447c11cca19e5aee Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 7 Jun 2021 17:22:49 -0400 Subject: [PATCH 0440/1208] Add and use 'tfresource.Delete'. --- aws/aws_sweeper_test.go | 3 +- aws/internal/tfresource/errors_test.go | 7 +- aws/internal/tfresource/resource.go | 34 +++++++++ aws/internal/tfresource/resource_test.go | 88 ++++++++++++++++++++++++ aws/provider_test.go | 26 +------ aws/resource_aws_route_table.go | 4 +- 6 files changed, 132 insertions(+), 30 deletions(-) create mode 100644 aws/internal/tfresource/resource.go create mode 100644 aws/internal/tfresource/resource_test.go diff --git a/aws/aws_sweeper_test.go b/aws/aws_sweeper_test.go index a16da090e850..4fda020dd9e1 100644 --- a/aws/aws_sweeper_test.go +++ b/aws/aws_sweeper_test.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/envvar" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) // sweeperAwsClients is a shared cache of regional AWSClient @@ -77,7 +78,7 @@ func testSweepResourceOrchestrator(sweepResources []*testSweepResource) error { sweepResource := sweepResource g.Go(func() error { - return testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) + return tfresource.Delete(sweepResource.resource, sweepResource.d, sweepResource.meta) }) } diff --git a/aws/internal/tfresource/errors_test.go b/aws/internal/tfresource/errors_test.go index 175ef5150cd9..da75f2cec9e2 100644 --- a/aws/internal/tfresource/errors_test.go +++ b/aws/internal/tfresource/errors_test.go @@ -1,4 +1,4 @@ -package tfresource +package tfresource_test import ( "errors" @@ -6,6 +6,7 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestNotFound(t *testing.T) { @@ -40,7 +41,7 @@ func TestNotFound(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.Name, func(t *testing.T) { - got := NotFound(testCase.Err) + got := tfresource.NotFound(testCase.Err) if got != testCase.Expected { t.Errorf("got %t, expected %t", got, testCase.Expected) @@ -88,7 +89,7 @@ func TestTimedOut(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.Name, func(t *testing.T) { - got := TimedOut(testCase.Err) + got := tfresource.TimedOut(testCase.Err) if got != testCase.Expected { t.Errorf("got %t, expected %t", got, testCase.Expected) diff --git a/aws/internal/tfresource/resource.go b/aws/internal/tfresource/resource.go new file mode 100644 index 000000000000..8b8a765c05e8 --- /dev/null +++ b/aws/internal/tfresource/resource.go @@ -0,0 +1,34 @@ +package tfresource + +import ( + "context" + "errors" + + multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Delete calls the specified resource's delete handler. +func Delete(resource *schema.Resource, d *schema.ResourceData, meta interface{}) error { + if resource.DeleteContext != nil || resource.DeleteWithoutTimeout != nil { + var diags diag.Diagnostics + var err *multierror.Error + + if resource.DeleteContext != nil { + diags = resource.DeleteContext(context.Background(), d, meta) + } else { + diags = resource.DeleteWithoutTimeout(context.Background(), d, meta) + } + + for i := range diags { + if diags[i].Severity == diag.Error { + err = multierror.Append(err, errors.New(diags[i].Summary)) + } + } + + return err.ErrorOrNil() + } + + return resource.Delete(d, meta) +} diff --git a/aws/internal/tfresource/resource_test.go b/aws/internal/tfresource/resource_test.go new file mode 100644 index 000000000000..266691e618f6 --- /dev/null +++ b/aws/internal/tfresource/resource_test.go @@ -0,0 +1,88 @@ +package tfresource_test + +import ( + "context" + "errors" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func TestDeleteNoError(t *testing.T) { + theError := errors.New("fail") + + testCases := []struct { + Name string + Resource *schema.Resource + ExpectError bool + }{ + { + Name: "no error Delete function", + Resource: &schema.Resource{ + Delete: func(rd *schema.ResourceData, i interface{}) error { + return nil + }, + }, + }, + { + Name: "no error DeleteContext function", + Resource: &schema.Resource{ + DeleteContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + return nil + }, + }, + }, + { + Name: "no error DeleteWithoutTimeout function", + Resource: &schema.Resource{ + DeleteWithoutTimeout: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + return nil + }, + }, + }, + { + Name: "error Delete function", + Resource: &schema.Resource{ + Delete: func(rd *schema.ResourceData, i interface{}) error { + return theError + }, + }, + ExpectError: true, + }, + { + Name: "error DeleteContext function", + Resource: &schema.Resource{ + DeleteContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + return diag.FromErr(theError) + }, + }, + ExpectError: true, + }, + { + Name: "error DeleteWithoutTimeout function", + Resource: &schema.Resource{ + DeleteWithoutTimeout: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + return diag.FromErr(theError) + }, + }, + ExpectError: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + r := testCase.Resource + d := r.Data(nil) + + err := tfresource.Delete(r, d, nil) + + if testCase.ExpectError && err == nil { + t.Fatal("expected error") + } else if !testCase.ExpectError && err != nil { + t.Fatalf("unexpected error: %s", err) + } + }) + } +} diff --git a/aws/provider_test.go b/aws/provider_test.go index de8c51422524..38998ba6ce95 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -18,7 +18,6 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/organizations" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" @@ -26,6 +25,7 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/envvar" organizationsfinder "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/organizations/finder" stsfinder "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sts/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -1035,28 +1035,6 @@ func testAccAwsRegionProviderFunc(region string, providers *[]*schema.Provider) } } -func testAccDeleteResource(resource *schema.Resource, d *schema.ResourceData, meta interface{}) error { - if resource.DeleteContext != nil || resource.DeleteWithoutTimeout != nil { - var diags diag.Diagnostics - - if resource.DeleteContext != nil { - diags = resource.DeleteContext(context.Background(), d, meta) - } else { - diags = resource.DeleteWithoutTimeout(context.Background(), d, meta) - } - - for i := range diags { - if diags[i].Severity == diag.Error { - return fmt.Errorf("error deleting resource: %s", diags[i].Summary) - } - } - - return nil - } - - return resource.Delete(d, meta) -} - func testAccCheckResourceDisappears(provider *schema.Provider, resource *schema.Resource, resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { resourceState, ok := s.RootModule().Resources[resourceName] @@ -1069,7 +1047,7 @@ func testAccCheckResourceDisappears(provider *schema.Provider, resource *schema. return fmt.Errorf("resource ID missing: %s", resourceName) } - return testAccDeleteResource(resource, resource.Data(resourceState.Primary), provider.Meta()) + return tfresource.Delete(resource, resource.Data(resourceState.Primary), provider.Meta()) } } diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index 09ac9bcadbe8..f11f816fb7b8 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -517,7 +517,7 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error d := r.Data(nil) d.SetId(v) - if err := r.Delete(d, meta); err != nil { + if err := tfresource.Delete(r, d, meta); err != nil { return err } } @@ -538,7 +538,7 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error // Wait for the route table to really destroy log.Printf("[DEBUG] Waiting for route table (%s) deletion", d.Id()) if _, err := waiter.RouteTableDeleted(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for Route Table (%s) deletion: %w", d.Id(), err) + return fmt.Errorf("error waiting for Route Table (%s) to delete: %w", d.Id(), err) } return nil From 34659d066389114e2f31e19a242bb17f4cb0f789 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 11 Jun 2021 14:43:16 -0400 Subject: [PATCH 0441/1208] Add 'tfresource.RetryWhenAwsErrCodeEquals'. --- aws/internal/tfresource/retry.go | 41 +++++++++++++++ aws/internal/tfresource/retry_test.go | 73 +++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 aws/internal/tfresource/retry.go create mode 100644 aws/internal/tfresource/retry_test.go diff --git a/aws/internal/tfresource/retry.go b/aws/internal/tfresource/retry.go new file mode 100644 index 000000000000..517a6b219334 --- /dev/null +++ b/aws/internal/tfresource/retry.go @@ -0,0 +1,41 @@ +package tfresource + +import ( + "time" + + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// RetryWhenAwsErrCodeEquals retries the specified function when it returns one of the specified AWS error code. +func RetryWhenAwsErrCodeEquals(timeout time.Duration, f func() (interface{}, error), codes ...string) (interface{}, error) { + var output interface{} + + err := resource.Retry(timeout, func() *resource.RetryError { + var err error + + output, err = f() + + for _, code := range codes { + if tfawserr.ErrCodeEquals(err, code) { + return resource.RetryableError(err) + } + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if TimedOut(err) { + output, err = f() + } + + if err != nil { + return nil, err + } + + return output, nil +} diff --git a/aws/internal/tfresource/retry_test.go b/aws/internal/tfresource/retry_test.go new file mode 100644 index 000000000000..8a396b9e3de5 --- /dev/null +++ b/aws/internal/tfresource/retry_test.go @@ -0,0 +1,73 @@ +package tfresource_test + +import ( + "errors" + "sync/atomic" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func TestRetryWhenAwsErrCodeEquals(t *testing.T) { + var retryCount int32 + + testCases := []struct { + Name string + F func() (interface{}, error) + ExpectError bool + }{ + { + Name: "no error", + F: func() (interface{}, error) { + return nil, nil + }, + }, + { + Name: "non-retryable other error", + F: func() (interface{}, error) { + return nil, errors.New("TestCode") + }, + ExpectError: true, + }, + { + Name: "non-retryable AWS error", + F: func() (interface{}, error) { + return nil, awserr.New("Testing", "Testing", nil) + }, + ExpectError: true, + }, + { + Name: "retryable AWS error timeout", + F: func() (interface{}, error) { + return nil, awserr.New("TestCode1", "TestMessage", nil) + }, + ExpectError: true, + }, + { + Name: "retryable AWS error success", + F: func() (interface{}, error) { + if atomic.CompareAndSwapInt32(&retryCount, 0, 1) { + return nil, awserr.New("TestCode2", "TestMessage", nil) + } + + return nil, nil + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + retryCount = 0 + + _, err := tfresource.RetryWhenAwsErrCodeEquals(5*time.Second, testCase.F, "TestCode1", "TestCode2") + + if testCase.ExpectError && err == nil { + t.Fatal("expected error") + } else if !testCase.ExpectError && err != nil { + t.Fatalf("unexpected error: %s", err) + } + }) + } +} From 39a1614d8a3a541ef7efcfd5b81ca1def0b685a1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 11 Jun 2021 15:57:43 -0400 Subject: [PATCH 0442/1208] Add and use 'waiter.RouteReady'. --- aws/internal/service/ec2/waiter/status.go | 20 ++++++ aws/internal/service/ec2/waiter/waiter.go | 21 +++++- aws/resource_aws_route.go | 78 +++++++---------------- aws/resource_aws_route_table.go | 33 ++++++++-- 4 files changed, 93 insertions(+), 59 deletions(-) diff --git a/aws/internal/service/ec2/waiter/status.go b/aws/internal/service/ec2/waiter/status.go index 6e444caa1791..70f884f1ad54 100644 --- a/aws/internal/service/ec2/waiter/status.go +++ b/aws/internal/service/ec2/waiter/status.go @@ -246,6 +246,26 @@ func InstanceIamInstanceProfile(conn *ec2.EC2, id string) resource.StateRefreshF } } +const ( + RouteStatusReady = "ready" +) + +func RouteStatus(conn *ec2.EC2, routeFinder finder.RouteFinder, routeTableID, destination string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := routeFinder(conn, routeTableID, destination) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, RouteStatusReady, nil + } +} + const ( RouteTableStatusReady = "ready" ) diff --git a/aws/internal/service/ec2/waiter/waiter.go b/aws/internal/service/ec2/waiter/waiter.go index 985f0a891942..3151cb8a4c18 100644 --- a/aws/internal/service/ec2/waiter/waiter.go +++ b/aws/internal/service/ec2/waiter/waiter.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" ) const ( @@ -257,10 +258,28 @@ const ( NetworkAclEntryPropagationTimeout = 5 * time.Minute ) +func RouteReady(conn *ec2.EC2, routeFinder finder.RouteFinder, routeTableID, destination string) (*ec2.Route, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{}, + Target: []string{RouteStatusReady}, + Refresh: RouteStatus(conn, routeFinder, routeTableID, destination), + Timeout: PropagationTimeout, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*ec2.Route); ok { + return output, err + } + + return nil, err +} + const ( RouteTableReadyTimeout = 10 * time.Minute RouteTableDeletedTimeout = 5 * time.Minute - RouteTableUpdateTimeout = 5 * time.Minute + RouteTableUpdatedTimeout = 5 * time.Minute RouteTableNotFoundChecks = 40 ) diff --git a/aws/resource_aws_route.go b/aws/resource_aws_route.go index 3542ba991807..e6740315dcbc 100644 --- a/aws/resource_aws_route.go +++ b/aws/resource_aws_route.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -230,36 +231,23 @@ func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error { } log.Printf("[DEBUG] Creating Route: %s", input) - err = createRoute(conn, input, d.Timeout(schema.TimeoutCreate)) + _, err = tfresource.RetryWhenAwsErrCodeEquals( + d.Timeout(schema.TimeoutCreate), + func() (interface{}, error) { + return conn.CreateRoute(input) + }, + tfec2.ErrCodeInvalidParameterException, + tfec2.ErrCodeInvalidTransitGatewayIDNotFound, + ) if err != nil { return fmt.Errorf("error creating Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) } - err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { - _, err = routeFinder(conn, routeTableID, destination) - - if err != nil { - return resource.RetryableError(err) - } - - if tfresource.NotFound(err) { - return resource.RetryableError(fmt.Errorf("route not found")) - } - - return nil - }) - - if tfresource.TimedOut(err) { - _, err = routeFinder(conn, routeTableID, destination) - } + _, err = waiter.RouteReady(conn, routeFinder, routeTableID, destination) if err != nil { - return fmt.Errorf("error reading Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) - } - - if tfresource.NotFound(err) { - return fmt.Errorf("route in Route Table (%s) with destination (%s) not found", routeTableID, destination) + return fmt.Errorf("error waiting for Route in Route Table (%s) with destination (%s) to become available: %w", routeTableID, destination, err) } d.SetId(tfec2.RouteCreateID(routeTableID, destination)) @@ -349,13 +337,18 @@ func resourceAwsRouteUpdate(d *schema.ResourceData, meta interface{}) error { RouteTableId: aws.String(routeTableID), } + var routeFinder finder.RouteFinder + switch destination := aws.String(destination); destinationAttributeKey { case "destination_cidr_block": input.DestinationCidrBlock = destination + routeFinder = finder.RouteByIPv4Destination case "destination_ipv6_cidr_block": input.DestinationIpv6CidrBlock = destination + routeFinder = finder.RouteByIPv6Destination case "destination_prefix_list_id": input.DestinationPrefixListId = destination + routeFinder = finder.RouteByPrefixListIDDestination default: return fmt.Errorf("error updating Route: unexpected route destination attribute: %q", destinationAttributeKey) } @@ -392,6 +385,12 @@ func resourceAwsRouteUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error updating Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) } + _, err = waiter.RouteReady(conn, routeFinder, routeTableID, destination) + + if err != nil { + return fmt.Errorf("error waiting for Route in Route Table (%s) with destination (%s) to become available: %w", routeTableID, destination, err) + } + return resourceAwsRouteRead(d, meta) } @@ -420,9 +419,10 @@ func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error deleting Route: unexpected route destination attribute: %q", destinationAttributeKey) } + log.Printf("[DEBUG] Deleting Route (%s)", d.Id()) err = resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError { - log.Printf("[DEBUG] Deleting Route (%s)", d.Id()) _, err = conn.DeleteRoute(input) + if err == nil { return nil } @@ -444,7 +444,6 @@ func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error { }) if tfresource.TimedOut(err) { - log.Printf("[DEBUG] Deleting Route (%s)", d.Id()) _, err = conn.DeleteRoute(input) } @@ -503,32 +502,3 @@ func routeTargetAttribute(d *schema.ResourceData) (string, string, error) { return "", "", fmt.Errorf("route target attribute not specified") } - -// createRoute attempts to create a route. -// The specified eventual consistency timeout is respected. -// Any error is returned. -func createRoute(conn *ec2.EC2, input *ec2.CreateRouteInput, timeout time.Duration) error { - err := resource.Retry(timeout, func() *resource.RetryError { - _, err := conn.CreateRoute(input) - - if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidParameterException) { - return resource.RetryableError(err) - } - - if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidTransitGatewayIDNotFound) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return nil - }) - - if tfresource.TimedOut(err) { - _, err = conn.CreateRoute(input) - } - - return err -} diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index f11f816fb7b8..35190c082d93 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -211,7 +211,20 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error creating route: %w", err) } - _, destination := routeTableRouteDestinationAttribute(v) + destinationAttributeKey, destination := routeTableRouteDestinationAttribute(v) + + var routeFinder finder.RouteFinder + + switch destinationAttributeKey { + case "cidr_block": + routeFinder = finder.RouteByIPv4Destination + case "ipv6_cidr_block": + routeFinder = finder.RouteByIPv6Destination + case "destination_prefix_list_id": + routeFinder = finder.RouteByPrefixListIDDestination + default: + return fmt.Errorf("error creating Route: unexpected route destination attribute: %q", destinationAttributeKey) + } input := expandEc2CreateRouteInput(v) @@ -222,11 +235,24 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error input.RouteTableId = aws.String(d.Id()) log.Printf("[DEBUG] Creating Route: %s", input) - err = createRoute(conn, input, waiter.PropagationTimeout) + _, err = tfresource.RetryWhenAwsErrCodeEquals( + waiter.PropagationTimeout, + func() (interface{}, error) { + return conn.CreateRoute(input) + }, + tfec2.ErrCodeInvalidParameterException, + tfec2.ErrCodeInvalidTransitGatewayIDNotFound, + ) if err != nil { return fmt.Errorf("error creating Route for Route Table (%s) with destination (%s): %w", d.Id(), destination, err) } + + _, err = waiter.RouteReady(conn, routeFinder, d.Id(), destination) + + if err != nil { + return fmt.Errorf("error waiting for Route in Route Table (%s) with destination (%s) to become available: %w", d.Id(), destination, err) + } } } @@ -264,7 +290,6 @@ func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting route: %w", err) } - // Tags tags := keyvaluetags.Ec2KeyValueTags(routeTable.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 @@ -461,7 +486,7 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error } log.Printf("[INFO] Creating route for %s: %#v", d.Id(), opts) - err := resource.Retry(waiter.RouteTableUpdateTimeout, func() *resource.RetryError { + err := resource.Retry(waiter.RouteTableUpdatedTimeout, func() *resource.RetryError { _, err := conn.CreateRoute(&opts) if isAWSErr(err, "InvalidRouteTableID.NotFound", "") { From 576a9f5a841959f7587e2918d19316cfe91797c5 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 11 Jun 2021 16:22:44 -0400 Subject: [PATCH 0443/1208] Simplify VGW route propagation. --- aws/resource_aws_route_table.go | 94 ++++++++++++--------------------- 1 file changed, 35 insertions(+), 59 deletions(-) diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index 35190c082d93..0db9e2c81437 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -5,7 +5,6 @@ import ( "fmt" "log" "strings" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" @@ -192,7 +191,7 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error v := v.(string) log.Printf("[DEBUG] Enabling Route Table (%s) VPN Gateway (%s) route propagation", d.Id(), v) - err = enableVgwRoutePropagation(conn, d.Id(), v, waiter.PropagationTimeout) + err = enableVgwRoutePropagation(conn, d.Id(), v) if err != nil { return fmt.Errorf("error enabling Route Table (%s) VPN Gateway (%s) route propagation: %w", d.Id(), v, err) @@ -322,57 +321,31 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error o, n := d.GetChange("propagating_vgws") os := o.(*schema.Set) ns := n.(*schema.Set) - remove := os.Difference(ns).List() + del := os.Difference(ns).List() add := ns.Difference(os).List() // Now first loop through all the old propagations and disable any obsolete ones - for _, vgw := range remove { - id := vgw.(string) + for _, v := range del { + v := v.(string) + + log.Printf("[DEBUG] Disabling Route Table (%s) VPN Gateway (%s) route propagation", d.Id(), v) + err := disableVgwRoutePropagation(conn, d.Id(), v) - // Disable the propagation as it no longer exists in the config - log.Printf("[INFO] Deleting VGW propagation from %s: %s", d.Id(), id) - _, err := conn.DisableVgwRoutePropagation(&ec2.DisableVgwRoutePropagationInput{ - RouteTableId: aws.String(d.Id()), - GatewayId: aws.String(id), - }) if err != nil { - return err + return fmt.Errorf("error disabling Route Table (%s) VPN Gateway (%s) route propagation: %w", d.Id(), v, err) } } - // Make sure we save the state of the currently configured rules - propagatingVGWs := os.Intersection(ns) - d.Set("propagating_vgws", propagatingVGWs) - // Then loop through all the newly configured propagations and enable them - for _, vgw := range add { - id := vgw.(string) - - var err error - for i := 0; i < 5; i++ { - log.Printf("[INFO] Enabling VGW propagation for %s: %s", d.Id(), id) - _, err = conn.EnableVgwRoutePropagation(&ec2.EnableVgwRoutePropagationInput{ - RouteTableId: aws.String(d.Id()), - GatewayId: aws.String(id), - }) - if err == nil { - break - } + for _, v := range add { + v := v.(string) + + log.Printf("[DEBUG] Enabling Route Table (%s) VPN Gateway (%s) route propagation", d.Id(), v) + err := enableVgwRoutePropagation(conn, d.Id(), v) - // If we get a Gateway.NotAttached, it is usually some - // eventually consistency stuff. So we have to just wait a - // bit... - if isAWSErr(err, "Gateway.NotAttached", "") { - time.Sleep(20 * time.Second) - continue - } - } if err != nil { - return err + return fmt.Errorf("error enabling Route Table (%s) VPN Gateway (%s) route propagation: %w", d.Id(), v, err) } - - propagatingVGWs.Add(vgw) - d.Set("propagating_vgws", propagatingVGWs) } } @@ -635,33 +608,36 @@ func resourceAwsRouteTableHash(v interface{}) int { return hashcode.String(buf.String()) } -// enableVgwRoutePropagation attempts to enable VGW route propagation. -// The specified eventual consistency timeout is respected. +// disableVgwRoutePropagation attempts to disable VGW route propagation. // Any error is returned. -func enableVgwRoutePropagation(conn *ec2.EC2, routeTableID, gatewayID string, timeout time.Duration) error { - input := &ec2.EnableVgwRoutePropagationInput{ +func disableVgwRoutePropagation(conn *ec2.EC2, routeTableID, gatewayID string) error { + input := &ec2.DisableVgwRoutePropagationInput{ GatewayId: aws.String(gatewayID), RouteTableId: aws.String(routeTableID), } - err := resource.Retry(timeout, func() *resource.RetryError { - _, err := conn.EnableVgwRoutePropagation(input) - - if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeGatewayNotAttached) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } + _, err := conn.DisableVgwRoutePropagation(input) - return nil - }) + return err +} - if tfresource.TimedOut(err) { - _, err = conn.EnableVgwRoutePropagation(input) +// enableVgwRoutePropagation attempts to enable VGW route propagation. +// The specified eventual consistency timeout is respected. +// Any error is returned. +func enableVgwRoutePropagation(conn *ec2.EC2, routeTableID, gatewayID string) error { + input := &ec2.EnableVgwRoutePropagationInput{ + GatewayId: aws.String(gatewayID), + RouteTableId: aws.String(routeTableID), } + _, err := tfresource.RetryWhenAwsErrCodeEquals( + waiter.PropagationTimeout, + func() (interface{}, error) { + return conn.EnableVgwRoutePropagation(input) + }, + tfec2.ErrCodeGatewayNotAttached, + ) + return err } From ca6a234647802531581b70bd9ca3394dfb304684 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 11 Jun 2021 16:31:49 -0400 Subject: [PATCH 0444/1208] Add and use 'waiter.RouteDeleted'. --- aws/internal/service/ec2/waiter/waiter.go | 18 ++++++++++++++++++ aws/resource_aws_route.go | 11 +++++++++++ 2 files changed, 29 insertions(+) diff --git a/aws/internal/service/ec2/waiter/waiter.go b/aws/internal/service/ec2/waiter/waiter.go index 3151cb8a4c18..7330192f77f6 100644 --- a/aws/internal/service/ec2/waiter/waiter.go +++ b/aws/internal/service/ec2/waiter/waiter.go @@ -258,6 +258,24 @@ const ( NetworkAclEntryPropagationTimeout = 5 * time.Minute ) +func RouteDeleted(conn *ec2.EC2, routeFinder finder.RouteFinder, routeTableID, destination string) (*ec2.Route, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{RouteStatusReady}, + Target: []string{}, + Refresh: RouteStatus(conn, routeFinder, routeTableID, destination), + Timeout: PropagationTimeout, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*ec2.Route); ok { + return output, err + } + + return nil, err +} + func RouteReady(conn *ec2.EC2, routeFinder finder.RouteFinder, routeTableID, destination string) (*ec2.Route, error) { stateConf := &resource.StateChangeConf{ Pending: []string{}, diff --git a/aws/resource_aws_route.go b/aws/resource_aws_route.go index e6740315dcbc..9cb44186f652 100644 --- a/aws/resource_aws_route.go +++ b/aws/resource_aws_route.go @@ -408,13 +408,18 @@ func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error { RouteTableId: aws.String(routeTableID), } + var routeFinder finder.RouteFinder + switch destination := aws.String(destination); destinationAttributeKey { case "destination_cidr_block": input.DestinationCidrBlock = destination + routeFinder = finder.RouteByIPv4Destination case "destination_ipv6_cidr_block": input.DestinationIpv6CidrBlock = destination + routeFinder = finder.RouteByIPv6Destination case "destination_prefix_list_id": input.DestinationPrefixListId = destination + routeFinder = finder.RouteByPrefixListIDDestination default: return fmt.Errorf("error deleting Route: unexpected route destination attribute: %q", destinationAttributeKey) } @@ -455,6 +460,12 @@ func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error deleting Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) } + _, err = waiter.RouteDeleted(conn, routeFinder, routeTableID, destination) + + if err != nil { + return fmt.Errorf("error waiting for Route in Route Table (%s) with destination (%s) to delete: %w", routeTableID, destination, err) + } + return nil } From 3e638dd6f8acc4a1a62a6af43d939b937fbfb3b0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 13 Jun 2021 17:14:07 -0400 Subject: [PATCH 0445/1208] r/aws_route_table: Simplify route update. --- aws/resource_aws_route.go | 2 +- aws/resource_aws_route_table.go | 451 ++++++++++++++++----------- aws/resource_aws_route_table_test.go | 4 +- 3 files changed, 270 insertions(+), 187 deletions(-) diff --git a/aws/resource_aws_route.go b/aws/resource_aws_route.go index 9cb44186f652..7568e953d9fd 100644 --- a/aws/resource_aws_route.go +++ b/aws/resource_aws_route.go @@ -424,7 +424,7 @@ func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error deleting Route: unexpected route destination attribute: %q", destinationAttributeKey) } - log.Printf("[DEBUG] Deleting Route (%s)", d.Id()) + log.Printf("[DEBUG] Deleting Route: %s", input) err = resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError { _, err = conn.DeleteRoute(input) diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index 0db9e2c81437..3259e7033816 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -10,7 +10,6 @@ import ( "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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/hashcode" @@ -190,11 +189,8 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error for _, v := range v.(*schema.Set).List() { v := v.(string) - log.Printf("[DEBUG] Enabling Route Table (%s) VPN Gateway (%s) route propagation", d.Id(), v) - err = enableVgwRoutePropagation(conn, d.Id(), v) - - if err != nil { - return fmt.Errorf("error enabling Route Table (%s) VPN Gateway (%s) route propagation: %w", d.Id(), v, err) + if err := ec2RouteTableEnableVgwRoutePropagation(conn, d.Id(), v); err != nil { + return err } } } @@ -203,54 +199,8 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error for _, v := range v.(*schema.Set).List() { v := v.(map[string]interface{}) - if err := validateNestedExactlyOneOf(v, routeTableValidDestinations); err != nil { - return fmt.Errorf("error creating route: %w", err) - } - if err := validateNestedExactlyOneOf(v, routeTableValidTargets); err != nil { - return fmt.Errorf("error creating route: %w", err) - } - - destinationAttributeKey, destination := routeTableRouteDestinationAttribute(v) - - var routeFinder finder.RouteFinder - - switch destinationAttributeKey { - case "cidr_block": - routeFinder = finder.RouteByIPv4Destination - case "ipv6_cidr_block": - routeFinder = finder.RouteByIPv6Destination - case "destination_prefix_list_id": - routeFinder = finder.RouteByPrefixListIDDestination - default: - return fmt.Errorf("error creating Route: unexpected route destination attribute: %q", destinationAttributeKey) - } - - input := expandEc2CreateRouteInput(v) - - if input == nil { - continue - } - - input.RouteTableId = aws.String(d.Id()) - - log.Printf("[DEBUG] Creating Route: %s", input) - _, err = tfresource.RetryWhenAwsErrCodeEquals( - waiter.PropagationTimeout, - func() (interface{}, error) { - return conn.CreateRoute(input) - }, - tfec2.ErrCodeInvalidParameterException, - tfec2.ErrCodeInvalidTransitGatewayIDNotFound, - ) - - if err != nil { - return fmt.Errorf("error creating Route for Route Table (%s) with destination (%s): %w", d.Id(), destination, err) - } - - _, err = waiter.RouteReady(conn, routeFinder, d.Id(), destination) - - if err != nil { - return fmt.Errorf("error waiting for Route in Route Table (%s) with destination (%s) to become available: %w", d.Id(), destination, err) + if err := ec2RouteTableAddRoute(conn, d.Id(), v); err != nil { + return err } } } @@ -324,166 +274,80 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error del := os.Difference(ns).List() add := ns.Difference(os).List() - // Now first loop through all the old propagations and disable any obsolete ones for _, v := range del { v := v.(string) - log.Printf("[DEBUG] Disabling Route Table (%s) VPN Gateway (%s) route propagation", d.Id(), v) - err := disableVgwRoutePropagation(conn, d.Id(), v) - - if err != nil { - return fmt.Errorf("error disabling Route Table (%s) VPN Gateway (%s) route propagation: %w", d.Id(), v, err) + if err := ec2RouteTableDisableVgwRoutePropagation(conn, d.Id(), v); err != nil { + return err } } - // Then loop through all the newly configured propagations and enable them for _, v := range add { v := v.(string) - log.Printf("[DEBUG] Enabling Route Table (%s) VPN Gateway (%s) route propagation", d.Id(), v) - err := enableVgwRoutePropagation(conn, d.Id(), v) - - if err != nil { - return fmt.Errorf("error enabling Route Table (%s) VPN Gateway (%s) route propagation: %w", d.Id(), v, err) + if err := ec2RouteTableEnableVgwRoutePropagation(conn, d.Id(), v); err != nil { + return err } } } - // Check if the route set as a whole has changed if d.HasChange("route") { o, n := d.GetChange("route") - ors := o.(*schema.Set).Difference(n.(*schema.Set)) - nrs := n.(*schema.Set).Difference(o.(*schema.Set)) - // Now first loop through all the old routes and delete any obsolete ones - for _, route := range ors.List() { - m := route.(map[string]interface{}) + for _, new := range n.(*schema.Set).List() { + vNew := new.(map[string]interface{}) - deleteOpts := &ec2.DeleteRouteInput{ - RouteTableId: aws.String(d.Id()), - } + _, newDestination := routeTableRouteDestinationAttribute(vNew) + _, newTarget := routeTableRouteTargetAttribute(vNew) - if s, ok := m["ipv6_cidr_block"].(string); ok && s != "" { - deleteOpts.DestinationIpv6CidrBlock = aws.String(s) + addRoute := true - log.Printf("[INFO] Deleting route from %s: %s", d.Id(), m["ipv6_cidr_block"].(string)) - } + for _, old := range o.(*schema.Set).List() { + vOld := old.(map[string]interface{}) - if s, ok := m["cidr_block"].(string); ok && s != "" { - deleteOpts.DestinationCidrBlock = aws.String(s) + _, oldDestination := routeTableRouteDestinationAttribute(vOld) + _, oldTarget := routeTableRouteTargetAttribute(vOld) - log.Printf("[INFO] Deleting route from %s: %s", d.Id(), m["cidr_block"].(string)) - } + if oldDestination == newDestination { + addRoute = false - if s, ok := m["destination_prefix_list_id"].(string); ok && s != "" { - deleteOpts.DestinationPrefixListId = aws.String(s) - - log.Printf("[INFO] Deleting route from %s: %s", d.Id(), m["destination_prefix_list_id"].(string)) + if oldTarget != newTarget { + if err := ec2RouteTableUpdateRoute(conn, d.Id(), vNew); err != nil { + return err + } + } + } } - _, err := conn.DeleteRoute(deleteOpts) - if err != nil { - return err + if addRoute { + if err := ec2RouteTableAddRoute(conn, d.Id(), vNew); err != nil { + return err + } } } - // Make sure we save the state of the currently configured rules - routes := o.(*schema.Set).Intersection(n.(*schema.Set)) - d.Set("route", routes) - - // Then loop through all the newly configured routes and create them - for _, route := range nrs.List() { - m := route.(map[string]interface{}) - - if err := validateNestedExactlyOneOf(m, routeTableValidDestinations); err != nil { - return fmt.Errorf("error creating route: %w", err) - } - if err := validateNestedExactlyOneOf(m, routeTableValidTargets); err != nil { - return fmt.Errorf("error creating route: %w", err) - } - - opts := ec2.CreateRouteInput{ - RouteTableId: aws.String(d.Id()), - } - - if s, ok := m["transit_gateway_id"].(string); ok && s != "" { - opts.TransitGatewayId = aws.String(s) - } - - if s, ok := m["vpc_endpoint_id"].(string); ok && s != "" { - opts.VpcEndpointId = aws.String(s) - } - - if s, ok := m["vpc_peering_connection_id"].(string); ok && s != "" { - opts.VpcPeeringConnectionId = aws.String(s) - } - - if s, ok := m["network_interface_id"].(string); ok && s != "" { - opts.NetworkInterfaceId = aws.String(s) - } - - if s, ok := m["instance_id"].(string); ok && s != "" { - opts.InstanceId = aws.String(s) - } - - if s, ok := m["ipv6_cidr_block"].(string); ok && s != "" { - opts.DestinationIpv6CidrBlock = aws.String(s) - } - - if s, ok := m["cidr_block"].(string); ok && s != "" { - opts.DestinationCidrBlock = aws.String(s) - } - - if s, ok := m["destination_prefix_list_id"].(string); ok && s != "" { - opts.DestinationPrefixListId = aws.String(s) - } + for _, old := range o.(*schema.Set).List() { + vOld := old.(map[string]interface{}) - if s, ok := m["gateway_id"].(string); ok && s != "" { - opts.GatewayId = aws.String(s) - } + _, oldDestination := routeTableRouteDestinationAttribute(vOld) - if s, ok := m["carrier_gateway_id"].(string); ok && s != "" { - opts.CarrierGatewayId = aws.String(s) - } + delRoute := true - if s, ok := m["egress_only_gateway_id"].(string); ok && s != "" { - opts.EgressOnlyInternetGatewayId = aws.String(s) - } + for _, new := range n.(*schema.Set).List() { + vNew := new.(map[string]interface{}) - if s, ok := m["nat_gateway_id"].(string); ok && s != "" { - opts.NatGatewayId = aws.String(s) - } - - if s, ok := m["local_gateway_id"].(string); ok && s != "" { - opts.LocalGatewayId = aws.String(s) - } + _, newDestination := routeTableRouteDestinationAttribute(vNew) - log.Printf("[INFO] Creating route for %s: %#v", d.Id(), opts) - err := resource.Retry(waiter.RouteTableUpdatedTimeout, func() *resource.RetryError { - _, err := conn.CreateRoute(&opts) - - if isAWSErr(err, "InvalidRouteTableID.NotFound", "") { - return resource.RetryableError(err) - } - - if isAWSErr(err, "InvalidTransitGatewayID.NotFound", "") { - return resource.RetryableError(err) + if newDestination == oldDestination { + delRoute = false } + } - if err != nil { - return resource.NonRetryableError(err) + if delRoute { + if err := ec2RouteTableDeleteRoute(conn, d.Id(), vOld); err != nil { + return err } - return nil - }) - if isResourceTimeoutError(err) { - _, err = conn.CreateRoute(&opts) - } - if err != nil { - return fmt.Errorf("error creating route: %w", err) } - - routes.Add(route) - d.Set("route", routes) } } @@ -608,28 +472,181 @@ func resourceAwsRouteTableHash(v interface{}) int { return hashcode.String(buf.String()) } -// disableVgwRoutePropagation attempts to disable VGW route propagation. +// ec2RouteTableAddRoute adds a route to the specified route table. +func ec2RouteTableAddRoute(conn *ec2.EC2, routeTableID string, tfMap map[string]interface{}) error { + if err := validateNestedExactlyOneOf(tfMap, routeTableValidDestinations); err != nil { + return fmt.Errorf("error creating route: %w", err) + } + if err := validateNestedExactlyOneOf(tfMap, routeTableValidTargets); err != nil { + return fmt.Errorf("error creating route: %w", err) + } + + destinationAttributeKey, destination := routeTableRouteDestinationAttribute(tfMap) + + var routeFinder finder.RouteFinder + + switch destinationAttributeKey { + case "cidr_block": + routeFinder = finder.RouteByIPv4Destination + case "ipv6_cidr_block": + routeFinder = finder.RouteByIPv6Destination + case "destination_prefix_list_id": + routeFinder = finder.RouteByPrefixListIDDestination + default: + return fmt.Errorf("error creating Route: unexpected route destination attribute: %q", destinationAttributeKey) + } + + input := expandEc2CreateRouteInput(tfMap) + + if input == nil { + return nil + } + + input.RouteTableId = aws.String(routeTableID) + + log.Printf("[DEBUG] Creating Route: %s", input) + _, err := tfresource.RetryWhenAwsErrCodeEquals( + waiter.PropagationTimeout, + func() (interface{}, error) { + return conn.CreateRoute(input) + }, + tfec2.ErrCodeInvalidParameterException, + tfec2.ErrCodeInvalidTransitGatewayIDNotFound, + ) + + if err != nil { + return fmt.Errorf("error creating Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) + } + + _, err = waiter.RouteReady(conn, routeFinder, routeTableID, destination) + + if err != nil { + return fmt.Errorf("error waiting for Route in Route Table (%s) with destination (%s) to become available: %w", routeTableID, destination, err) + } + + return nil +} + +// ec2RouteTableDeleteRoute deletes a route from the specified route table. +func ec2RouteTableDeleteRoute(conn *ec2.EC2, routeTableID string, tfMap map[string]interface{}) error { + destinationAttributeKey, destination := routeTableRouteDestinationAttribute(tfMap) + + input := &ec2.DeleteRouteInput{ + RouteTableId: aws.String(routeTableID), + } + + var routeFinder finder.RouteFinder + + switch destination := aws.String(destination); destinationAttributeKey { + case "cidr_block": + input.DestinationCidrBlock = destination + routeFinder = finder.RouteByIPv4Destination + case "ipv6_cidr_block": + input.DestinationIpv6CidrBlock = destination + routeFinder = finder.RouteByIPv6Destination + case "destination_prefix_list_id": + input.DestinationPrefixListId = destination + routeFinder = finder.RouteByPrefixListIDDestination + default: + return fmt.Errorf("error deleting Route: unexpected route destination attribute: %q", destinationAttributeKey) + } + + log.Printf("[DEBUG] Deleting Route: %s", input) + _, err := conn.DeleteRoute(input) + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidRouteNotFound) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) + } + + _, err = waiter.RouteDeleted(conn, routeFinder, routeTableID, destination) + + if err != nil { + return fmt.Errorf("error waiting for Route in Route Table (%s) with destination (%s) to delete: %w", routeTableID, destination, err) + } + + return nil +} + +// ec2RouteTableUpdateRoute updates a route in the specified route table. +func ec2RouteTableUpdateRoute(conn *ec2.EC2, routeTableID string, tfMap map[string]interface{}) error { + if err := validateNestedExactlyOneOf(tfMap, routeTableValidDestinations); err != nil { + return fmt.Errorf("error updating route: %w", err) + } + if err := validateNestedExactlyOneOf(tfMap, routeTableValidTargets); err != nil { + return fmt.Errorf("error updating route: %w", err) + } + + destinationAttributeKey, destination := routeTableRouteDestinationAttribute(tfMap) + + var routeFinder finder.RouteFinder + + switch destinationAttributeKey { + case "cidr_block": + routeFinder = finder.RouteByIPv4Destination + case "ipv6_cidr_block": + routeFinder = finder.RouteByIPv6Destination + case "destination_prefix_list_id": + routeFinder = finder.RouteByPrefixListIDDestination + default: + return fmt.Errorf("error creating Route: unexpected route destination attribute: %q", destinationAttributeKey) + } + + input := expandEc2ReplaceRouteInput(tfMap) + + if input == nil { + return nil + } + + input.RouteTableId = aws.String(routeTableID) + + log.Printf("[DEBUG] Updating Route: %s", input) + _, err := conn.ReplaceRoute(input) + + if err != nil { + return fmt.Errorf("error updating Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) + } + + _, err = waiter.RouteReady(conn, routeFinder, routeTableID, destination) + + if err != nil { + return fmt.Errorf("error waiting for Route in Route Table (%s) with destination (%s) to become available: %w", routeTableID, destination, err) + } + + return nil +} + +// ec2RouteTableDisableVgwRoutePropagation attempts to disable VGW route propagation. // Any error is returned. -func disableVgwRoutePropagation(conn *ec2.EC2, routeTableID, gatewayID string) error { +func ec2RouteTableDisableVgwRoutePropagation(conn *ec2.EC2, routeTableID, gatewayID string) error { input := &ec2.DisableVgwRoutePropagationInput{ GatewayId: aws.String(gatewayID), RouteTableId: aws.String(routeTableID), } + log.Printf("[DEBUG] Disabling Route Table (%s) VPN Gateway (%s) route propagation", routeTableID, gatewayID) _, err := conn.DisableVgwRoutePropagation(input) - return err + if err != nil { + return fmt.Errorf("error disabling Route Table (%s) VPN Gateway (%s) route propagation: %w", routeTableID, gatewayID, err) + } + + return nil } -// enableVgwRoutePropagation attempts to enable VGW route propagation. +// ec2RouteTableEnableVgwRoutePropagation attempts to enable VGW route propagation. // The specified eventual consistency timeout is respected. // Any error is returned. -func enableVgwRoutePropagation(conn *ec2.EC2, routeTableID, gatewayID string) error { +func ec2RouteTableEnableVgwRoutePropagation(conn *ec2.EC2, routeTableID, gatewayID string) error { input := &ec2.EnableVgwRoutePropagationInput{ GatewayId: aws.String(gatewayID), RouteTableId: aws.String(routeTableID), } + log.Printf("[DEBUG] Enabling Route Table (%s) VPN Gateway (%s) route propagation", routeTableID, gatewayID) _, err := tfresource.RetryWhenAwsErrCodeEquals( waiter.PropagationTimeout, func() (interface{}, error) { @@ -638,7 +655,11 @@ func enableVgwRoutePropagation(conn *ec2.EC2, routeTableID, gatewayID string) er tfec2.ErrCodeGatewayNotAttached, ) - return err + if err != nil { + return fmt.Errorf("error enabling Route Table (%s) VPN Gateway (%s) route propagation: %w", routeTableID, gatewayID, err) + } + + return nil } func expandEc2CreateRouteInput(tfMap map[string]interface{}) *ec2.CreateRouteInput { @@ -703,6 +724,68 @@ func expandEc2CreateRouteInput(tfMap map[string]interface{}) *ec2.CreateRouteInp return apiObject } +func expandEc2ReplaceRouteInput(tfMap map[string]interface{}) *ec2.ReplaceRouteInput { + if tfMap == nil { + return nil + } + + apiObject := &ec2.ReplaceRouteInput{} + + if v, ok := tfMap["cidr_block"].(string); ok && v != "" { + apiObject.DestinationCidrBlock = aws.String(v) + } + + if v, ok := tfMap["ipv6_cidr_block"].(string); ok && v != "" { + apiObject.DestinationIpv6CidrBlock = aws.String(v) + } + + if v, ok := tfMap["destination_prefix_list_id"].(string); ok && v != "" { + apiObject.DestinationPrefixListId = aws.String(v) + } + + if v, ok := tfMap["carrier_gateway_id"].(string); ok && v != "" { + apiObject.CarrierGatewayId = aws.String(v) + } + + if v, ok := tfMap["egress_only_gateway_id"].(string); ok && v != "" { + apiObject.EgressOnlyInternetGatewayId = aws.String(v) + } + + if v, ok := tfMap["gateway_id"].(string); ok && v != "" { + apiObject.GatewayId = aws.String(v) + } + + if v, ok := tfMap["instance_id"].(string); ok && v != "" { + apiObject.InstanceId = aws.String(v) + } + + if v, ok := tfMap["local_gateway_id"].(string); ok && v != "" { + apiObject.LocalGatewayId = aws.String(v) + } + + if v, ok := tfMap["nat_gateway_id"].(string); ok && v != "" { + apiObject.NatGatewayId = aws.String(v) + } + + if v, ok := tfMap["network_interface_id"].(string); ok && v != "" { + apiObject.NetworkInterfaceId = aws.String(v) + } + + if v, ok := tfMap["transit_gateway_id"].(string); ok && v != "" { + apiObject.TransitGatewayId = aws.String(v) + } + + if v, ok := tfMap["vpc_endpoint_id"].(string); ok && v != "" { + apiObject.VpcEndpointId = aws.String(v) + } + + if v, ok := tfMap["vpc_peering_connection_id"].(string); ok && v != "" { + apiObject.VpcPeeringConnectionId = aws.String(v) + } + + return apiObject +} + func flattenEc2Route(apiObject *ec2.Route) map[string]interface{} { if apiObject == nil { return nil diff --git a/aws/resource_aws_route_table_test.go b/aws/resource_aws_route_table_test.go index fe046a1837fb..f0c7742a486e 100644 --- a/aws/resource_aws_route_table_test.go +++ b/aws/resource_aws_route_table_test.go @@ -353,7 +353,7 @@ func TestAccAWSRouteTable_IPv6_To_EgressOnlyInternetGateway(t *testing.T) { }) } -func TestAccAWSRouteTable_tags(t *testing.T) { +func TestAccAWSRouteTable_Tags(t *testing.T) { var routeTable ec2.RouteTable resourceName := "aws_route_table.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -688,7 +688,7 @@ func TestAccAWSRouteTable_IPv4_To_VpcPeeringConnection(t *testing.T) { }) } -func TestAccAWSRouteTable_vgwRoutePropagation(t *testing.T) { +func TestAccAWSRouteTable_VgwRoutePropagation(t *testing.T) { var routeTable ec2.RouteTable resourceName := "aws_route_table.test" vgwResourceName1 := "aws_vpn_gateway.test1" From ccd9fd6149b5f1354a3a9e1aadbb2446eec26403 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 13 Jun 2021 17:53:28 -0400 Subject: [PATCH 0446/1208] Add 'TestAccAWSRouteTable_IPv4_To_NetworkInterfaces_Unattached'. --- aws/resource_aws_route_table.go | 4 +- aws/resource_aws_route_table_test.go | 134 +++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index 3259e7033816..838477e1d057 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -829,11 +829,11 @@ func flattenEc2Route(apiObject *ec2.Route) map[string]interface{} { tfMap["local_gateway_id"] = aws.StringValue(v) } - if v := apiObject.NetworkInterfaceId; v != nil { + if v := apiObject.NatGatewayId; v != nil { tfMap["nat_gateway_id"] = aws.StringValue(v) } - if v := apiObject.TransitGatewayId; v != nil { + if v := apiObject.NetworkInterfaceId; v != nil { tfMap["network_interface_id"] = aws.StringValue(v) } diff --git a/aws/resource_aws_route_table_test.go b/aws/resource_aws_route_table_test.go index f0c7742a486e..663fee82be60 100644 --- a/aws/resource_aws_route_table_test.go +++ b/aws/resource_aws_route_table_test.go @@ -847,6 +847,85 @@ func TestAccAWSRouteTable_IPv6_To_NetworkInterface_Unattached(t *testing.T) { }) } +func TestAccAWSRouteTable_IPv4_To_NetworkInterfaces_Unattached(t *testing.T) { + var routeTable ec2.RouteTable + resourceName := "aws_route_table.test" + eni1ResourceName := "aws_network_interface.test1" + eni2ResourceName := "aws_network_interface.test2" + rName := acctest.RandomWithPrefix("tf-acc-test") + destinationCidr1 := "10.2.0.0/16" + destinationCidr2 := "10.3.0.0/16" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckRouteTableDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRouteTableConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckRouteTableExists(resourceName, &routeTable), + testAccCheckAWSRouteTableNumberOfRoutes(&routeTable, 1), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`route-table/.+$`)), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttr(resourceName, "propagating_vgws.#", "0"), + resource.TestCheckResourceAttr(resourceName, "route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + Config: testAccAWSRouteTableConfigIpv4TwoNetworkInterfacesUnattached(rName, destinationCidr1, destinationCidr2), + Check: resource.ComposeTestCheckFunc( + testAccCheckRouteTableExists(resourceName, &routeTable), + testAccCheckAWSRouteTableNumberOfRoutes(&routeTable, 3), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`route-table/.+$`)), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttr(resourceName, "propagating_vgws.#", "0"), + resource.TestCheckResourceAttr(resourceName, "route.#", "2"), + testAccCheckAWSRouteTableRoute(resourceName, "cidr_block", destinationCidr1, "network_interface_id", eni1ResourceName, "id"), + testAccCheckAWSRouteTableRoute(resourceName, "cidr_block", destinationCidr2, "network_interface_id", eni2ResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSRouteTableConfigIpv4TwoNetworkInterfacesUnattached(rName, destinationCidr2, destinationCidr1), + Check: resource.ComposeTestCheckFunc( + testAccCheckRouteTableExists(resourceName, &routeTable), + testAccCheckAWSRouteTableNumberOfRoutes(&routeTable, 3), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`route-table/.+$`)), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttr(resourceName, "propagating_vgws.#", "0"), + resource.TestCheckResourceAttr(resourceName, "route.#", "2"), + testAccCheckAWSRouteTableRoute(resourceName, "cidr_block", destinationCidr2, "network_interface_id", eni1ResourceName, "id"), + testAccCheckAWSRouteTableRoute(resourceName, "cidr_block", destinationCidr1, "network_interface_id", eni2ResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + ), + }, + { + Config: testAccAWSRouteTableConfigRouteConfigModeZeroed(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckRouteTableExists(resourceName, &routeTable), + testAccCheckAWSRouteTableNumberOfRoutes(&routeTable, 1), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`route-table/.+$`)), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttr(resourceName, "propagating_vgws.#", "0"), + resource.TestCheckResourceAttr(resourceName, "route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + ), + }, + }, + }) +} + func TestAccAWSRouteTable_VpcMultipleCidrs(t *testing.T) { var routeTable ec2.RouteTable resourceName := "aws_route_table.test" @@ -2009,6 +2088,61 @@ resource "aws_route_table" "test" { `, rName, destinationCidr) } +func testAccAWSRouteTableConfigIpv4TwoNetworkInterfacesUnattached(rName, destinationCidr1, destinationCidr2 string) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test" { + cidr_block = "10.1.1.0/24" + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_network_interface" "test1" { + subnet_id = aws_subnet.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_network_interface" "test2" { + subnet_id = aws_subnet.test.id + + tags = { + Name = %[1]q + } + } + +resource "aws_route_table" "test" { + vpc_id = aws_vpc.test.id + + route { + cidr_block = %[2]q + network_interface_id = aws_network_interface.test1.id + } + + route { + cidr_block = %[3]q + network_interface_id = aws_network_interface.test2.id + } + + tags = { + Name = %[1]q + } +} +`, rName, destinationCidr1, destinationCidr2) +} + func testAccAWSRouteTableConfigVpcMultipleCidrs(rName string) string { return fmt.Sprintf(` resource "aws_vpc" "test" { From e0c7144a7e3d4602659197bc39d3ca1626051713 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 13 Jun 2021 18:22:33 -0400 Subject: [PATCH 0447/1208] Tweak error message. --- aws/resource_aws_route.go | 8 ++++---- aws/resource_aws_route_table.go | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_route.go b/aws/resource_aws_route.go index 7568e953d9fd..3ec120e060bf 100644 --- a/aws/resource_aws_route.go +++ b/aws/resource_aws_route.go @@ -241,7 +241,7 @@ func resourceAwsRouteCreate(d *schema.ResourceData, meta interface{}) error { ) if err != nil { - return fmt.Errorf("error creating Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) + return fmt.Errorf("error creating Route in Route Table (%s) with destination (%s): %w", routeTableID, destination, err) } _, err = waiter.RouteReady(conn, routeFinder, routeTableID, destination) @@ -288,7 +288,7 @@ func resourceAwsRouteRead(d *schema.ResourceData, meta interface{}) error { } if err != nil { - return fmt.Errorf("error reading Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) + return fmt.Errorf("error reading Route in Route Table (%s) with destination (%s): %w", routeTableID, destination, err) } d.Set("carrier_gateway_id", route.CarrierGatewayId) @@ -382,7 +382,7 @@ func resourceAwsRouteUpdate(d *schema.ResourceData, meta interface{}) error { _, err = conn.ReplaceRoute(input) if err != nil { - return fmt.Errorf("error updating Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) + return fmt.Errorf("error updating Route in Route Table (%s) with destination (%s): %w", routeTableID, destination, err) } _, err = waiter.RouteReady(conn, routeFinder, routeTableID, destination) @@ -457,7 +457,7 @@ func resourceAwsRouteDelete(d *schema.ResourceData, meta interface{}) error { } if err != nil { - return fmt.Errorf("error deleting Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) + return fmt.Errorf("error deleting Route in Route Table (%s) with destination (%s): %w", routeTableID, destination, err) } _, err = waiter.RouteDeleted(conn, routeFinder, routeTableID, destination) diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index 838477e1d057..e5b32d2e2a71 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -515,7 +515,7 @@ func ec2RouteTableAddRoute(conn *ec2.EC2, routeTableID string, tfMap map[string] ) if err != nil { - return fmt.Errorf("error creating Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) + return fmt.Errorf("error creating Route in Route Table (%s) with destination (%s): %w", routeTableID, destination, err) } _, err = waiter.RouteReady(conn, routeFinder, routeTableID, destination) @@ -559,7 +559,7 @@ func ec2RouteTableDeleteRoute(conn *ec2.EC2, routeTableID string, tfMap map[stri } if err != nil { - return fmt.Errorf("error deleting Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) + return fmt.Errorf("error deleting Route in Route Table (%s) with destination (%s): %w", routeTableID, destination, err) } _, err = waiter.RouteDeleted(conn, routeFinder, routeTableID, destination) @@ -607,7 +607,7 @@ func ec2RouteTableUpdateRoute(conn *ec2.EC2, routeTableID string, tfMap map[stri _, err := conn.ReplaceRoute(input) if err != nil { - return fmt.Errorf("error updating Route for Route Table (%s) with destination (%s): %w", routeTableID, destination, err) + return fmt.Errorf("error updating Route in Route Table (%s) with destination (%s): %w", routeTableID, destination, err) } _, err = waiter.RouteReady(conn, routeFinder, routeTableID, destination) From e6bd0b5f1f87c2eeef03fedb8da19650d908aef0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 13 Jun 2021 18:23:32 -0400 Subject: [PATCH 0448/1208] r/aws-default_route_table: Simplify read. --- aws/internal/service/ec2/finder/finder.go | 13 ++ aws/resource_aws_default_route_table.go | 231 +++++++++---------- aws/resource_aws_default_route_table_test.go | 2 +- 3 files changed, 125 insertions(+), 121 deletions(-) diff --git a/aws/internal/service/ec2/finder/finder.go b/aws/internal/service/ec2/finder/finder.go index 6aaab05915fa..f2e11b8c6f4a 100644 --- a/aws/internal/service/ec2/finder/finder.go +++ b/aws/internal/service/ec2/finder/finder.go @@ -235,6 +235,19 @@ func NetworkInterfaceSecurityGroup(conn *ec2.EC2, networkInterfaceID string, sec return result, err } +// MainRouteTableByVpcID returns the main route table for the specified VPC. +// Returns NotFoundError if no route table is found. +func MainRouteTableByVpcID(conn *ec2.EC2, vpcID string) (*ec2.RouteTable, error) { + input := &ec2.DescribeRouteTablesInput{ + Filters: tfec2.BuildAttributeFilterList(map[string]string{ + "association.main": "true", + "vpc-id": vpcID, + }), + } + + return RouteTable(conn, input) +} + // RouteTableByID returns the route table corresponding to the specified identifier. // Returns NotFoundError if no route table is found. func RouteTableByID(conn *ec2.EC2, routeTableID string) (*ec2.RouteTable, error) { diff --git a/aws/resource_aws_default_route_table.go b/aws/resource_aws_default_route_table.go index c61c9dfb954e..0d400f4c2008 100644 --- a/aws/resource_aws_default_route_table.go +++ b/aws/resource_aws_default_route_table.go @@ -7,10 +7,13 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "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" + tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" ) func resourceAwsDefaultRouteTable() *schema.Resource { @@ -19,21 +22,27 @@ func resourceAwsDefaultRouteTable() *schema.Resource { Read: resourceAwsDefaultRouteTableRead, Update: resourceAwsRouteTableUpdate, Delete: resourceAwsDefaultRouteTableDelete, + Importer: &schema.ResourceImporter{ - State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - d.Set("vpc_id", d.Id()) - return []*schema.ResourceData{d}, nil - }, + State: resourceAwsDefaultRouteTableImport, }, + // + // The top-level attributes must be a superset of the aws_route_table resource's attributes as common CRUD handlers are used. + // Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "default_route_table_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "vpc_id": { + "owner_id": { Type: schema.TypeString, Computed: true, }, @@ -63,7 +72,10 @@ func resourceAwsDefaultRouteTable() *schema.Resource { validateIpv4CIDRNetworkAddress, ), }, - + "destination_prefix_list_id": { + Type: schema.TypeString, + Optional: true, + }, "ipv6_cidr_block": { Type: schema.TypeString, Optional: true, @@ -73,49 +85,39 @@ func resourceAwsDefaultRouteTable() *schema.Resource { ), }, - "destination_prefix_list_id": { - Type: schema.TypeString, - Optional: true, - }, - // // Targets. + // These target attributes are a subset of the aws_route_table resource's target attributes + // as there are some targets that are not allowed in the default route table for a VPC. // "egress_only_gateway_id": { Type: schema.TypeString, Optional: true, }, - "gateway_id": { Type: schema.TypeString, Optional: true, }, - "instance_id": { Type: schema.TypeString, Optional: true, }, - "nat_gateway_id": { Type: schema.TypeString, Optional: true, }, - "network_interface_id": { Type: schema.TypeString, Optional: true, }, - "transit_gateway_id": { Type: schema.TypeString, Optional: true, }, - "vpc_endpoint_id": { Type: schema.TypeString, Optional: true, }, - "vpc_peering_connection_id": { Type: schema.TypeString, Optional: true, @@ -128,12 +130,7 @@ func resourceAwsDefaultRouteTable() *schema.Resource { "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), - "arn": { - Type: schema.TypeString, - Computed: true, - }, - - "owner_id": { + "vpc_id": { Type: schema.TypeString, Computed: true, }, @@ -147,6 +144,7 @@ func resourceAwsDefaultRouteTableCreate(d *schema.ResourceData, meta interface{} conn := meta.(*AWSClient).ec2conn defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) + routeTableID := d.Get("default_route_table_id").(string) routeTable, err := finder.RouteTableByID(conn, routeTableID) @@ -155,132 +153,125 @@ func resourceAwsDefaultRouteTableCreate(d *schema.ResourceData, meta interface{} return fmt.Errorf("error reading EC2 Default Route Table (%s): %w", routeTableID, err) } - d.SetId(routeTableID) - d.Set("vpc_id", routeTable.VpcId) - - // revoke all default and pre-existing routes on the default route table. - // In the UPDATE method, we'll apply only the rules in the configuration. - log.Printf("[DEBUG] Revoking default routes for Default Route Table for %s", d.Id()) - if err := revokeAllRouteTableRules(conn, routeTable); err != nil { - return err - } - - if len(tags) > 0 { - if err := keyvaluetags.Ec2CreateTags(conn, d.Id(), tags); err != nil { - return fmt.Errorf("error adding tags: %w", err) - } - } - - return resourceAwsRouteTableUpdate(d, meta) -} - -func resourceAwsDefaultRouteTableRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AWSClient).ec2conn - // look up default route table for VPC - filter1 := &ec2.Filter{ - Name: aws.String("association.main"), - Values: []*string{aws.String("true")}, - } - filter2 := &ec2.Filter{ - Name: aws.String("vpc-id"), - Values: []*string{aws.String(d.Get("vpc_id").(string))}, - } - - findOpts := &ec2.DescribeRouteTablesInput{ - Filters: []*ec2.Filter{filter1, filter2}, - } - - resp, err := conn.DescribeRouteTables(findOpts) - if err != nil { - return err - } - - if len(resp.RouteTables) < 1 || resp.RouteTables[0] == nil { - log.Printf("[WARN] EC2 Default Route Table (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - - rt := resp.RouteTables[0] - - d.Set("default_route_table_id", rt.RouteTableId) - d.SetId(aws.StringValue(rt.RouteTableId)) - - // re-use regular AWS Route Table READ. This is an extra API call but saves us - // from trying to manually keep parity - return resourceAwsRouteTableRead(d, meta) -} - -func resourceAwsDefaultRouteTableDelete(d *schema.ResourceData, meta interface{}) error { - log.Printf("[WARN] Cannot destroy Default Route Table. Terraform will remove this resource from the state file, however resources may remain.") - return nil -} - -// revokeAllRouteTableRules revoke all routes on the Default Route Table -// This should only be ran once at creation time of this resource -func revokeAllRouteTableRules(conn *ec2.EC2, routeTable *ec2.RouteTable) error { - // Remove all Gateway association - for _, r := range routeTable.PropagatingVgws { - _, err := conn.DisableVgwRoutePropagation(&ec2.DisableVgwRoutePropagationInput{ - RouteTableId: routeTable.RouteTableId, - GatewayId: r.GatewayId, - }) + d.SetId(aws.StringValue(routeTable.RouteTableId)) - if err != nil { + // Remove all existing VGW associations. + for _, v := range routeTable.PropagatingVgws { + if err := ec2RouteTableDisableVgwRoutePropagation(conn, d.Id(), aws.StringValue(v.GatewayId)); err != nil { return err } } - // Delete all routes - for _, r := range routeTable.Routes { + // Delete all existing routes. + for _, v := range routeTable.Routes { // you cannot delete the local route - if aws.StringValue(r.GatewayId) == "local" { + if aws.StringValue(v.GatewayId) == "local" { continue } - if aws.StringValue(r.Origin) == ec2.RouteOriginEnableVgwRoutePropagation { + if aws.StringValue(v.Origin) == ec2.RouteOriginEnableVgwRoutePropagation { continue } - if r.DestinationPrefixListId != nil && strings.HasPrefix(aws.StringValue(r.GatewayId), "vpce-") { + if v.DestinationPrefixListId != nil && strings.HasPrefix(aws.StringValue(v.GatewayId), "vpce-") { // Skipping because VPC endpoint routes are handled separately // See aws_vpc_endpoint continue } - if r.DestinationCidrBlock != nil { - _, err := conn.DeleteRoute(&ec2.DeleteRouteInput{ - RouteTableId: routeTable.RouteTableId, - DestinationCidrBlock: r.DestinationCidrBlock, - }) + input := &ec2.DeleteRouteInput{ + RouteTableId: aws.String(d.Id()), + } - if err != nil { - return err - } + var destination string + var routeFinder finder.RouteFinder + + if v.DestinationCidrBlock != nil { + input.DestinationCidrBlock = v.DestinationCidrBlock + destination = aws.StringValue(v.DestinationCidrBlock) + routeFinder = finder.RouteByIPv4Destination + } else if v.DestinationIpv6CidrBlock != nil { + input.DestinationIpv6CidrBlock = v.DestinationIpv6CidrBlock + destination = aws.StringValue(v.DestinationIpv6CidrBlock) + routeFinder = finder.RouteByIPv6Destination + } else if v.DestinationPrefixListId != nil { + input.DestinationPrefixListId = v.DestinationPrefixListId + destination = aws.StringValue(v.DestinationPrefixListId) + routeFinder = finder.RouteByPrefixListIDDestination + } + + log.Printf("[DEBUG] Deleting Route: %s", input) + _, err := conn.DeleteRoute(input) + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidRouteNotFound) { + continue + } + + if err != nil { + return fmt.Errorf("error deleting Route in EC2 Default Route Table (%s) with destination (%s): %w", d.Id(), destination, err) + } + + _, err = waiter.RouteDeleted(conn, routeFinder, routeTableID, destination) + + if err != nil { + return fmt.Errorf("error waiting for Route in EC2 Default Route Table (%s) with destination (%s) to delete: %w", d.Id(), destination, err) } + } - if r.DestinationIpv6CidrBlock != nil { - _, err := conn.DeleteRoute(&ec2.DeleteRouteInput{ - RouteTableId: routeTable.RouteTableId, - DestinationIpv6CidrBlock: r.DestinationIpv6CidrBlock, - }) + // Add new VGW associations. + if v, ok := d.GetOk("propagating_vgws"); ok && v.(*schema.Set).Len() > 0 { + for _, v := range v.(*schema.Set).List() { + v := v.(string) - if err != nil { + if err := ec2RouteTableEnableVgwRoutePropagation(conn, d.Id(), v); err != nil { return err } } + } - if r.DestinationPrefixListId != nil { - _, err := conn.DeleteRoute(&ec2.DeleteRouteInput{ - RouteTableId: routeTable.RouteTableId, - DestinationPrefixListId: r.DestinationPrefixListId, - }) + // Add new routes. + if v, ok := d.GetOk("route"); ok && v.(*schema.Set).Len() > 0 { + for _, v := range v.(*schema.Set).List() { + v := v.(map[string]interface{}) - if err != nil { + if err := ec2RouteTableAddRoute(conn, d.Id(), v); err != nil { return err } } } + if len(tags) > 0 { + if err := keyvaluetags.Ec2CreateTags(conn, d.Id(), tags); err != nil { + return fmt.Errorf("error adding tags: %w", err) + } + } + + return resourceAwsDefaultRouteTableRead(d, meta) +} + +func resourceAwsDefaultRouteTableRead(d *schema.ResourceData, meta interface{}) error { + d.Set("default_route_table_id", d.Id()) + + // re-use regular AWS Route Table READ. This is an extra API call but saves us + // from trying to manually keep parity + return resourceAwsRouteTableRead(d, meta) +} + +func resourceAwsDefaultRouteTableDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[WARN] Cannot destroy Default Route Table. Terraform will remove this resource from the state file, however resources may remain.") return nil } + +func resourceAwsDefaultRouteTableImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + conn := meta.(*AWSClient).ec2conn + + routeTable, err := finder.MainRouteTableByVpcID(conn, d.Id()) + + if err != nil { + return nil, err + } + + d.SetId(aws.StringValue(routeTable.RouteTableId)) + + return []*schema.ResourceData{d}, nil +} diff --git a/aws/resource_aws_default_route_table_test.go b/aws/resource_aws_default_route_table_test.go index d40b73823dab..d055aab53a44 100644 --- a/aws/resource_aws_default_route_table_test.go +++ b/aws/resource_aws_default_route_table_test.go @@ -324,7 +324,7 @@ func TestAccAWSDefaultRouteTable_VpcEndpointAssociation(t *testing.T) { }) } -func TestAccAWSDefaultRouteTable_tags(t *testing.T) { +func TestAccAWSDefaultRouteTable_Tags(t *testing.T) { var routeTable ec2.RouteTable resourceName := "aws_default_route_table.test" rName := acctest.RandomWithPrefix("tf-acc-test") From 82e54764c199b06f55b0eff3330bff285baafdbc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 14 Jun 2021 09:27:29 -0400 Subject: [PATCH 0449/1208] Revert "Add and use 'tfresource.Delete'." This reverts commit 3ce6f12091c6f96a723fa735e38963324a579be4. --- aws/aws_sweeper_test.go | 3 +- aws/internal/tfresource/errors_test.go | 7 +- aws/internal/tfresource/resource.go | 34 --------- aws/internal/tfresource/resource_test.go | 88 ------------------------ aws/provider_test.go | 26 ++++++- aws/resource_aws_route_table.go | 4 +- 6 files changed, 30 insertions(+), 132 deletions(-) delete mode 100644 aws/internal/tfresource/resource.go delete mode 100644 aws/internal/tfresource/resource_test.go diff --git a/aws/aws_sweeper_test.go b/aws/aws_sweeper_test.go index 4fda020dd9e1..a16da090e850 100644 --- a/aws/aws_sweeper_test.go +++ b/aws/aws_sweeper_test.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/envvar" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) // sweeperAwsClients is a shared cache of regional AWSClient @@ -78,7 +77,7 @@ func testSweepResourceOrchestrator(sweepResources []*testSweepResource) error { sweepResource := sweepResource g.Go(func() error { - return tfresource.Delete(sweepResource.resource, sweepResource.d, sweepResource.meta) + return testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) }) } diff --git a/aws/internal/tfresource/errors_test.go b/aws/internal/tfresource/errors_test.go index da75f2cec9e2..175ef5150cd9 100644 --- a/aws/internal/tfresource/errors_test.go +++ b/aws/internal/tfresource/errors_test.go @@ -1,4 +1,4 @@ -package tfresource_test +package tfresource import ( "errors" @@ -6,7 +6,6 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestNotFound(t *testing.T) { @@ -41,7 +40,7 @@ func TestNotFound(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.Name, func(t *testing.T) { - got := tfresource.NotFound(testCase.Err) + got := NotFound(testCase.Err) if got != testCase.Expected { t.Errorf("got %t, expected %t", got, testCase.Expected) @@ -89,7 +88,7 @@ func TestTimedOut(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.Name, func(t *testing.T) { - got := tfresource.TimedOut(testCase.Err) + got := TimedOut(testCase.Err) if got != testCase.Expected { t.Errorf("got %t, expected %t", got, testCase.Expected) diff --git a/aws/internal/tfresource/resource.go b/aws/internal/tfresource/resource.go deleted file mode 100644 index 8b8a765c05e8..000000000000 --- a/aws/internal/tfresource/resource.go +++ /dev/null @@ -1,34 +0,0 @@ -package tfresource - -import ( - "context" - "errors" - - multierror "github.com/hashicorp/go-multierror" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -// Delete calls the specified resource's delete handler. -func Delete(resource *schema.Resource, d *schema.ResourceData, meta interface{}) error { - if resource.DeleteContext != nil || resource.DeleteWithoutTimeout != nil { - var diags diag.Diagnostics - var err *multierror.Error - - if resource.DeleteContext != nil { - diags = resource.DeleteContext(context.Background(), d, meta) - } else { - diags = resource.DeleteWithoutTimeout(context.Background(), d, meta) - } - - for i := range diags { - if diags[i].Severity == diag.Error { - err = multierror.Append(err, errors.New(diags[i].Summary)) - } - } - - return err.ErrorOrNil() - } - - return resource.Delete(d, meta) -} diff --git a/aws/internal/tfresource/resource_test.go b/aws/internal/tfresource/resource_test.go deleted file mode 100644 index 266691e618f6..000000000000 --- a/aws/internal/tfresource/resource_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package tfresource_test - -import ( - "context" - "errors" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" -) - -func TestDeleteNoError(t *testing.T) { - theError := errors.New("fail") - - testCases := []struct { - Name string - Resource *schema.Resource - ExpectError bool - }{ - { - Name: "no error Delete function", - Resource: &schema.Resource{ - Delete: func(rd *schema.ResourceData, i interface{}) error { - return nil - }, - }, - }, - { - Name: "no error DeleteContext function", - Resource: &schema.Resource{ - DeleteContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { - return nil - }, - }, - }, - { - Name: "no error DeleteWithoutTimeout function", - Resource: &schema.Resource{ - DeleteWithoutTimeout: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { - return nil - }, - }, - }, - { - Name: "error Delete function", - Resource: &schema.Resource{ - Delete: func(rd *schema.ResourceData, i interface{}) error { - return theError - }, - }, - ExpectError: true, - }, - { - Name: "error DeleteContext function", - Resource: &schema.Resource{ - DeleteContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { - return diag.FromErr(theError) - }, - }, - ExpectError: true, - }, - { - Name: "error DeleteWithoutTimeout function", - Resource: &schema.Resource{ - DeleteWithoutTimeout: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { - return diag.FromErr(theError) - }, - }, - ExpectError: true, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.Name, func(t *testing.T) { - r := testCase.Resource - d := r.Data(nil) - - err := tfresource.Delete(r, d, nil) - - if testCase.ExpectError && err == nil { - t.Fatal("expected error") - } else if !testCase.ExpectError && err != nil { - t.Fatalf("unexpected error: %s", err) - } - }) - } -} diff --git a/aws/provider_test.go b/aws/provider_test.go index 38998ba6ce95..de8c51422524 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -18,6 +18,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/organizations" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" @@ -25,7 +26,6 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/envvar" organizationsfinder "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/organizations/finder" stsfinder "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sts/finder" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -1035,6 +1035,28 @@ func testAccAwsRegionProviderFunc(region string, providers *[]*schema.Provider) } } +func testAccDeleteResource(resource *schema.Resource, d *schema.ResourceData, meta interface{}) error { + if resource.DeleteContext != nil || resource.DeleteWithoutTimeout != nil { + var diags diag.Diagnostics + + if resource.DeleteContext != nil { + diags = resource.DeleteContext(context.Background(), d, meta) + } else { + diags = resource.DeleteWithoutTimeout(context.Background(), d, meta) + } + + for i := range diags { + if diags[i].Severity == diag.Error { + return fmt.Errorf("error deleting resource: %s", diags[i].Summary) + } + } + + return nil + } + + return resource.Delete(d, meta) +} + func testAccCheckResourceDisappears(provider *schema.Provider, resource *schema.Resource, resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { resourceState, ok := s.RootModule().Resources[resourceName] @@ -1047,7 +1069,7 @@ func testAccCheckResourceDisappears(provider *schema.Provider, resource *schema. return fmt.Errorf("resource ID missing: %s", resourceName) } - return tfresource.Delete(resource, resource.Data(resourceState.Primary), provider.Meta()) + return testAccDeleteResource(resource, resource.Data(resourceState.Primary), provider.Meta()) } } diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index e5b32d2e2a71..18b93d0a9137 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -379,7 +379,7 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error d := r.Data(nil) d.SetId(v) - if err := tfresource.Delete(r, d, meta); err != nil { + if err := r.Delete(d, meta); err != nil { return err } } @@ -400,7 +400,7 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error // Wait for the route table to really destroy log.Printf("[DEBUG] Waiting for route table (%s) deletion", d.Id()) if _, err := waiter.RouteTableDeleted(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for Route Table (%s) to delete: %w", d.Id(), err) + return fmt.Errorf("error waiting for Route Table (%s) deletion: %w", d.Id(), err) } return nil From baccf09bfc0583287106c743559e25411212502b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 14 Jun 2021 09:30:06 -0400 Subject: [PATCH 0450/1208] Move tests to '_test' package. --- aws/internal/tfresource/errors_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/aws/internal/tfresource/errors_test.go b/aws/internal/tfresource/errors_test.go index 175ef5150cd9..da75f2cec9e2 100644 --- a/aws/internal/tfresource/errors_test.go +++ b/aws/internal/tfresource/errors_test.go @@ -1,4 +1,4 @@ -package tfresource +package tfresource_test import ( "errors" @@ -6,6 +6,7 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestNotFound(t *testing.T) { @@ -40,7 +41,7 @@ func TestNotFound(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.Name, func(t *testing.T) { - got := NotFound(testCase.Err) + got := tfresource.NotFound(testCase.Err) if got != testCase.Expected { t.Errorf("got %t, expected %t", got, testCase.Expected) @@ -88,7 +89,7 @@ func TestTimedOut(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.Name, func(t *testing.T) { - got := TimedOut(testCase.Err) + got := tfresource.TimedOut(testCase.Err) if got != testCase.Expected { t.Errorf("got %t, expected %t", got, testCase.Expected) From 36aa2a54b893699ab686bb8b4da670b90eb9c424 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 14 Jun 2021 12:43:29 -0400 Subject: [PATCH 0451/1208] r/aws_route_table_association: Add waiters. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSRouteTableAssociation_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSRouteTableAssociation_ -timeout 180m === RUN TestAccAWSRouteTableAssociation_Subnet_basic === PAUSE TestAccAWSRouteTableAssociation_Subnet_basic === RUN TestAccAWSRouteTableAssociation_Subnet_ChangeRouteTable === PAUSE TestAccAWSRouteTableAssociation_Subnet_ChangeRouteTable === RUN TestAccAWSRouteTableAssociation_Gateway_basic === PAUSE TestAccAWSRouteTableAssociation_Gateway_basic === RUN TestAccAWSRouteTableAssociation_Gateway_ChangeRouteTable === PAUSE TestAccAWSRouteTableAssociation_Gateway_ChangeRouteTable === RUN TestAccAWSRouteTableAssociation_disappears === PAUSE TestAccAWSRouteTableAssociation_disappears === CONT TestAccAWSRouteTableAssociation_Subnet_basic === CONT TestAccAWSRouteTableAssociation_Gateway_ChangeRouteTable === CONT TestAccAWSRouteTableAssociation_disappears === CONT TestAccAWSRouteTableAssociation_Gateway_basic === CONT TestAccAWSRouteTableAssociation_Subnet_ChangeRouteTable --- PASS: TestAccAWSRouteTableAssociation_disappears (41.23s) --- PASS: TestAccAWSRouteTableAssociation_Subnet_basic (43.44s) --- PASS: TestAccAWSRouteTableAssociation_Subnet_ChangeRouteTable (64.12s) --- PASS: TestAccAWSRouteTableAssociation_Gateway_basic (74.27s) --- PASS: TestAccAWSRouteTableAssociation_Gateway_ChangeRouteTable (94.98s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 98.235s --- aws/internal/service/ec2/finder/finder.go | 28 ++ aws/internal/service/ec2/waiter/status.go | 16 + aws/internal/service/ec2/waiter/waiter.go | 72 ++++ aws/resource_aws_route_table.go | 6 +- aws/resource_aws_route_table_association.go | 233 +++++------ ...source_aws_route_table_association_test.go | 396 ++++++------------ 6 files changed, 346 insertions(+), 405 deletions(-) diff --git a/aws/internal/service/ec2/finder/finder.go b/aws/internal/service/ec2/finder/finder.go index f2e11b8c6f4a..4bf913ffca19 100644 --- a/aws/internal/service/ec2/finder/finder.go +++ b/aws/internal/service/ec2/finder/finder.go @@ -235,6 +235,34 @@ func NetworkInterfaceSecurityGroup(conn *ec2.EC2, networkInterfaceID string, sec return result, err } +// RouteTableAssociationByID returns the route table association corresponding to the specified identifier. +// Returns NotFoundError if no route table association is found. +func RouteTableAssociationByID(conn *ec2.EC2, associationID string) (*ec2.RouteTableAssociation, error) { + input := &ec2.DescribeRouteTablesInput{ + Filters: tfec2.BuildAttributeFilterList(map[string]string{ + "association.route-table-association-id": associationID, + }), + } + + routeTable, err := RouteTable(conn, input) + + if err != nil { + return nil, err + } + + for _, association := range routeTable.Associations { + if aws.StringValue(association.RouteTableAssociationId) == associationID { + if state := aws.StringValue(association.AssociationState.State); state == ec2.RouteTableAssociationStateCodeDisassociated { + return nil, &resource.NotFoundError{Message: state} + } + + return association, nil + } + } + + return nil, &resource.NotFoundError{} +} + // MainRouteTableByVpcID returns the main route table for the specified VPC. // Returns NotFoundError if no route table is found. func MainRouteTableByVpcID(conn *ec2.EC2, vpcID string) (*ec2.RouteTable, error) { diff --git a/aws/internal/service/ec2/waiter/status.go b/aws/internal/service/ec2/waiter/status.go index 70f884f1ad54..8b8ffde410c6 100644 --- a/aws/internal/service/ec2/waiter/status.go +++ b/aws/internal/service/ec2/waiter/status.go @@ -286,6 +286,22 @@ func RouteTableStatus(conn *ec2.EC2, id string) resource.StateRefreshFunc { } } +func RouteTableAssociationState(conn *ec2.EC2, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.RouteTableAssociationByID(conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output.AssociationState, aws.StringValue(output.AssociationState.State), nil + } +} + const ( SecurityGroupStatusCreated = "Created" diff --git a/aws/internal/service/ec2/waiter/waiter.go b/aws/internal/service/ec2/waiter/waiter.go index 7330192f77f6..b119c2fdb779 100644 --- a/aws/internal/service/ec2/waiter/waiter.go +++ b/aws/internal/service/ec2/waiter/waiter.go @@ -1,14 +1,17 @@ package waiter import ( + "errors" "strconv" "time" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -295,6 +298,12 @@ func RouteReady(conn *ec2.EC2, routeFinder finder.RouteFinder, routeTableID, des } const ( + RouteTableAssociationPropagationTimeout = 5 * time.Minute + + RouteTableAssociationCreatedTimeout = 5 * time.Minute + RouteTableAssociationUpdatedTimeout = 5 * time.Minute + RouteTableAssociationDeletedTimeout = 5 * time.Minute + RouteTableReadyTimeout = 10 * time.Minute RouteTableDeletedTimeout = 5 * time.Minute RouteTableUpdatedTimeout = 5 * time.Minute @@ -337,6 +346,69 @@ func RouteTableDeleted(conn *ec2.EC2, id string) (*ec2.RouteTable, error) { return nil, err } +func RouteTableAssociationCreated(conn *ec2.EC2, id string) (*ec2.RouteTableAssociationState, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ec2.RouteTableAssociationStateCodeAssociating}, + Target: []string{ec2.RouteTableAssociationStateCodeAssociated}, + Refresh: RouteTableAssociationState(conn, id), + Timeout: RouteTableAssociationCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*ec2.RouteTableAssociationState); ok { + if output != nil && aws.StringValue(output.State) == ec2.RouteTableAssociationStateCodeFailed { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusMessage))) + } + + return output, err + } + + return nil, err +} + +func RouteTableAssociationDeleted(conn *ec2.EC2, id string) (*ec2.RouteTableAssociationState, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ec2.RouteTableAssociationStateCodeDisassociating}, + Target: []string{}, + Refresh: RouteTableAssociationState(conn, id), + Timeout: RouteTableAssociationDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*ec2.RouteTableAssociationState); ok { + if output != nil && aws.StringValue(output.State) == ec2.RouteTableAssociationStateCodeFailed { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusMessage))) + } + + return output, err + } + + return nil, err +} + +func RouteTableAssociationUpdated(conn *ec2.EC2, id string) (*ec2.RouteTableAssociationState, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ec2.RouteTableAssociationStateCodeAssociating}, + Target: []string{ec2.RouteTableAssociationStateCodeAssociated}, + Refresh: RouteTableAssociationState(conn, id), + Timeout: RouteTableAssociationUpdatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*ec2.RouteTableAssociationState); ok { + if output != nil && aws.StringValue(output.State) == ec2.RouteTableAssociationStateCodeFailed { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusMessage))) + } + + return output, err + } + + return nil, err +} + func SecurityGroupCreated(conn *ec2.EC2, id string, timeout time.Duration) (*ec2.SecurityGroup, error) { stateConf := &resource.StateChangeConf{ Pending: []string{SecurityGroupStatusNotFound}, diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index 18b93d0a9137..7844a32a4033 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -375,11 +375,7 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error for _, v := range routeTable.Associations { v := aws.StringValue(v.RouteTableAssociationId) - r := resourceAwsRouteTableAssociation() - d := r.Data(nil) - d.SetId(v) - - if err := r.Delete(d, meta); err != nil { + if err := ec2RouteTableAssociationDelete(conn, v); err != nil { return err } } diff --git a/aws/resource_aws_route_table_association.go b/aws/resource_aws_route_table_association.go index 3b970da09dd6..552dad00db1c 100644 --- a/aws/resource_aws_route_table_association.go +++ b/aws/resource_aws_route_table_association.go @@ -4,13 +4,13 @@ import ( "fmt" "log" "strings" - "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -26,23 +26,24 @@ func resourceAwsRouteTableAssociation() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "subnet_id": { - Type: schema.TypeString, - Optional: true, - ExactlyOneOf: []string{"subnet_id", "gateway_id"}, - ForceNew: true, - }, "gateway_id": { Type: schema.TypeString, Optional: true, - ExactlyOneOf: []string{"subnet_id", "gateway_id"}, ForceNew: true, + ExactlyOneOf: []string{"subnet_id", "gateway_id"}, }, "route_table_id": { Type: schema.TypeString, Required: true, }, + + "subnet_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ExactlyOneOf: []string{"subnet_id", "gateway_id"}, + }, }, } } @@ -50,89 +51,60 @@ func resourceAwsRouteTableAssociation() *schema.Resource { func resourceAwsRouteTableAssociationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - associationOpts := ec2.AssociateRouteTableInput{ - RouteTableId: aws.String(d.Get("route_table_id").(string)), + routeTableID := d.Get("route_table_id").(string) + input := &ec2.AssociateRouteTableInput{ + RouteTableId: aws.String(routeTableID), } - if len(d.Get("subnet_id").(string)) > 0 { - log.Printf( - "[INFO] Creating route table association: %s => %s", - d.Get("subnet_id").(string), - d.Get("route_table_id").(string)) - associationOpts.SubnetId = aws.String(d.Get("subnet_id").(string)) - } else if len(d.Get("gateway_id").(string)) > 0 { - log.Printf( - "[INFO] Creating route table association: %s => %s", - d.Get("gateway_id").(string), - d.Get("route_table_id").(string)) - associationOpts.GatewayId = aws.String(d.Get("gateway_id").(string)) + + if v, ok := d.GetOk("gateway_id"); ok { + input.GatewayId = aws.String(v.(string)) } - var associationID string - var resp *ec2.AssociateRouteTableOutput - err := resource.Retry(5*time.Minute, func() *resource.RetryError { - var err error - resp, err = conn.AssociateRouteTable(&associationOpts) - if err != nil { - if awsErr, ok := err.(awserr.Error); ok { - if awsErr.Code() == "InvalidRouteTableID.NotFound" { - return resource.RetryableError(awsErr) - } - } - return resource.NonRetryableError(err) - } - associationID = *resp.AssociationId - return nil - }) - if isResourceTimeoutError(err) { - resp, err = conn.AssociateRouteTable(&associationOpts) + if v, ok := d.GetOk("subnet_id"); ok { + input.SubnetId = aws.String(v.(string)) } + + log.Printf("[DEBUG] Creating Route Table Association: %s", input) + output, err := tfresource.RetryWhenAwsErrCodeEquals( + waiter.RouteTableAssociationPropagationTimeout, + func() (interface{}, error) { + return conn.AssociateRouteTable(input) + }, + tfec2.ErrCodeInvalidRouteTableIDNotFound, + ) + if err != nil { - return fmt.Errorf("Error creating route table association: %s", err) + return fmt.Errorf("error creating Route Table (%s) Association: %w", routeTableID, err) } - // Set the ID and return - d.SetId(associationID) - log.Printf("[INFO] Association ID: %s", d.Id()) + d.SetId(aws.StringValue(output.(*ec2.AssociateRouteTableOutput).AssociationId)) - return nil + log.Printf("[DEBUG] Waiting for Route Table Association (%s) creation", d.Id()) + if _, err := waiter.RouteTableAssociationCreated(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Route Table Association (%s) create: %w", d.Id(), err) + } + + return resourceAwsRouteTableAssociationRead(d, meta) } func resourceAwsRouteTableAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - // Get the routing table that this association belongs to - rtID := d.Get("route_table_id").(string) - rt, err := waiter.RouteTableReady(conn, rtID) + association, err := finder.RouteTableAssociationByID(conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { - log.Printf("[WARN] Route table (%s) not found, removing route table association (%s) from state", rtID, d.Id()) + log.Printf("[WARN] Route Table Association (%s) not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error getting route table (%s) status while reading route table association: %w", rtID, err) - } - - // Inspect that the association exists - found := false - for _, a := range rt.Associations { - if *a.RouteTableAssociationId == d.Id() { - found = true - if a.SubnetId != nil { - d.Set("subnet_id", a.SubnetId) - } - if a.GatewayId != nil { - d.Set("gateway_id", a.GatewayId) - } - break - } + return fmt.Errorf("error reading Route Table Association (%s): %w", d.Id(), err) } - if !found { - // It seems it doesn't exist anymore, so clear the ID - d.SetId("") - } + d.Set("gateway_id", association.GatewayId) + d.Set("route_table_id", association.RouteTableId) + d.Set("subnet_id", association.SubnetId) return nil } @@ -140,51 +112,43 @@ func resourceAwsRouteTableAssociationRead(d *schema.ResourceData, meta interface func resourceAwsRouteTableAssociationUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - log.Printf( - "[INFO] Creating route table association: %s => %s", - d.Get("subnet_id").(string), - d.Get("route_table_id").(string)) - - req := &ec2.ReplaceRouteTableAssociationInput{ + input := &ec2.ReplaceRouteTableAssociationInput{ AssociationId: aws.String(d.Id()), RouteTableId: aws.String(d.Get("route_table_id").(string)), } - resp, err := conn.ReplaceRouteTableAssociation(req) - if err != nil { - ec2err, ok := err.(awserr.Error) - if ok && ec2err.Code() == "InvalidAssociationID.NotFound" { - // Not found, so just create a new one - return resourceAwsRouteTableAssociationCreate(d, meta) - } + log.Printf("[DEBUG] Updating Route Table Association: %s", input) + output, err := conn.ReplaceRouteTableAssociation(input) + + // This whole thing with the resource ID being changed on update seems unsustainable. + // Keeping it here for backwards compatibilty... + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidAssociationIDNotFound) { + // Not found, so just create a new one + return resourceAwsRouteTableAssociationCreate(d, meta) + } - return err + if err != nil { + return fmt.Errorf("error updating Route Table Association (%s): %w", d.Id(), err) } - // Update the ID - d.SetId(aws.StringValue(resp.NewAssociationId)) - log.Printf("[INFO] Association ID: %s", d.Id()) + // I don't think we'll ever reach this code for a subnet/gateway route table association. + // It would only come in to play for a VPC main route table association. - return nil + d.SetId(aws.StringValue(output.NewAssociationId)) + + log.Printf("[DEBUG] Waiting for Route Table Association (%s) update", d.Id()) + if _, err := waiter.RouteTableAssociationUpdated(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Route Table Association (%s) update: %w", d.Id(), err) + } + + return resourceAwsRouteTableAssociationRead(d, meta) } func resourceAwsRouteTableAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - log.Printf("[INFO] Deleting route table association: %s", d.Id()) - _, err := conn.DisassociateRouteTable(&ec2.DisassociateRouteTableInput{ - AssociationId: aws.String(d.Id()), - }) - if err != nil { - ec2err, ok := err.(awserr.Error) - if ok && ec2err.Code() == "InvalidAssociationID.NotFound" { - return nil - } - - return fmt.Errorf("Error deleting route table association: %s", err) - } - - return nil + return ec2RouteTableAssociationDelete(conn, d.Id()) } func resourceAwsRouteTableAssociationImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { @@ -200,48 +164,59 @@ func resourceAwsRouteTableAssociationImport(d *schema.ResourceData, meta interfa conn := meta.(*AWSClient).ec2conn - input := &ec2.DescribeRouteTablesInput{} - input.Filters = buildEC2AttributeFilterList( - map[string]string{ - "association.route-table-id": routeTableID, - }, - ) + routeTable, err := finder.RouteTableByID(conn, routeTableID) - output, err := conn.DescribeRouteTables(input) if err != nil { - return nil, fmt.Errorf("Error finding route table: %s", err) - } - if len(output.RouteTables) == 0 { - return nil, fmt.Errorf("No route table found with ID %s", routeTableID) + return nil, err } - rt := output.RouteTables[0] - - var targetType string var associationID string - for _, a := range rt.Associations { - if aws.StringValue(a.SubnetId) == targetID { - targetType = "subnet" - associationID = aws.StringValue(a.RouteTableAssociationId) + + for _, association := range routeTable.Associations { + if aws.StringValue(association.SubnetId) == targetID { + d.Set("subnet_id", targetID) + associationID = aws.StringValue(association.RouteTableAssociationId) + break } - if aws.StringValue(a.SubnetId) == targetID || aws.StringValue(a.GatewayId) == targetID { - targetType = "gateway" - associationID = aws.StringValue(a.RouteTableAssociationId) + + if aws.StringValue(association.GatewayId) == targetID { + d.Set("gateway_id", targetID) + associationID = aws.StringValue(association.RouteTableAssociationId) + break } } + if associationID == "" { return nil, fmt.Errorf("No association found between route table ID %s and target ID %s", routeTableID, targetID) } d.SetId(associationID) - if targetType == "subnet" { - d.Set("subnet_id", targetID) - } else if targetType == "gateway" { - d.Set("gateway_id", targetID) - } d.Set("route_table_id", routeTableID) return []*schema.ResourceData{d}, nil } + +// ec2RouteTableAssociationDelete attempts to delete a route table association. +func ec2RouteTableAssociationDelete(conn *ec2.EC2, associationID string) error { + log.Printf("[INFO] Deleting Route Table Association: %s", associationID) + _, err := conn.DisassociateRouteTable(&ec2.DisassociateRouteTableInput{ + AssociationId: aws.String(associationID), + }) + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidAssociationIDNotFound) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Route Table Association (%s): %w", associationID, err) + } + + log.Printf("[DEBUG] Waiting for Route Table Association (%s) deletion", associationID) + if _, err := waiter.RouteTableAssociationDeleted(conn, associationID); err != nil { + return fmt.Errorf("error waiting for Route Table Association (%s) delete: %w", associationID, err) + } + + return nil +} diff --git a/aws/resource_aws_route_table_association_test.go b/aws/resource_aws_route_table_association_test.go index f33aa25d0aee..e0017635d4ee 100644 --- a/aws/resource_aws_route_table_association_test.go +++ b/aws/resource_aws_route_table_association_test.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "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" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" @@ -14,10 +14,10 @@ import ( func TestAccAWSRouteTableAssociation_Subnet_basic(t *testing.T) { var rta ec2.RouteTableAssociation - - resourceNameAssoc := "aws_route_table_association.foo" - resourceNameRouteTable := "aws_route_table.foo" - resourceNameSubnet := "aws_subnet.foo" + resourceName := "aws_route_table_association.test" + resourceNameRouteTable := "aws_route_table.test" + resourceNameSubnet := "aws_subnet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -26,17 +26,17 @@ func TestAccAWSRouteTableAssociation_Subnet_basic(t *testing.T) { CheckDestroy: testAccCheckRouteTableAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRouteTableAssociationSubnetConfig, + Config: testAccRouteTableAssociationConfigSubnet(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "route_table_id", resourceNameRouteTable, "id"), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "subnet_id", resourceNameSubnet, "id"), + testAccCheckRouteTableAssociationExists(resourceName, &rta), + resource.TestCheckResourceAttrPair(resourceName, "route_table_id", resourceNameRouteTable, "id"), + resource.TestCheckResourceAttrPair(resourceName, "subnet_id", resourceNameSubnet, "id"), ), }, { - ResourceName: resourceNameAssoc, + ResourceName: resourceName, ImportState: true, - ImportStateIdFunc: testAccAWSRouteTabAssocImportStateIdFunc(resourceNameAssoc), + ImportStateIdFunc: testAccAWSRouteTabAssocImportStateIdFunc(resourceName), ImportStateVerify: true, }, }, @@ -44,46 +44,12 @@ func TestAccAWSRouteTableAssociation_Subnet_basic(t *testing.T) { } func TestAccAWSRouteTableAssociation_Subnet_ChangeRouteTable(t *testing.T) { - var rta1, rta2 ec2.RouteTableAssociation - - resourceNameAssoc := "aws_route_table_association.foo" - resourceNameRouteTable1 := "aws_route_table.foo" - resourceNameRouteTable2 := "aws_route_table.bar" - resourceNameSubnet := "aws_subnet.foo" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckRouteTableAssociationDestroy, - Steps: []resource.TestStep{ - { - Config: testAccRouteTableAssociationSubnetConfig, - Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta1), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "route_table_id", resourceNameRouteTable1, "id"), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "subnet_id", resourceNameSubnet, "id"), - ), - }, - { - Config: testAccRouteTableAssociationSubnetConfig_ChangeRouteTable, - Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta2), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "route_table_id", resourceNameRouteTable2, "id"), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "subnet_id", resourceNameSubnet, "id"), - ), - }, - }, - }) -} - -func TestAccAWSRouteTableAssociation_Subnet_ChangeSubnet(t *testing.T) { - var rta1, rta2 ec2.RouteTableAssociation - - resourceNameAssoc := "aws_route_table_association.foo" - resourceNameRouteTable := "aws_route_table.foo" - resourceNameSubnet1 := "aws_subnet.foo" - resourceNameSubnet2 := "aws_subnet.bar" + var rta ec2.RouteTableAssociation + resourceName := "aws_route_table_association.test" + resourceNameRouteTable1 := "aws_route_table.test" + resourceNameRouteTable2 := "aws_route_table.test2" + resourceNameSubnet := "aws_subnet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -92,19 +58,19 @@ func TestAccAWSRouteTableAssociation_Subnet_ChangeSubnet(t *testing.T) { CheckDestroy: testAccCheckRouteTableAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRouteTableAssociationSubnetConfig, + Config: testAccRouteTableAssociationConfigSubnet(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta1), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "route_table_id", resourceNameRouteTable, "id"), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "subnet_id", resourceNameSubnet1, "id"), + testAccCheckRouteTableAssociationExists(resourceName, &rta), + resource.TestCheckResourceAttrPair(resourceName, "route_table_id", resourceNameRouteTable1, "id"), + resource.TestCheckResourceAttrPair(resourceName, "subnet_id", resourceNameSubnet, "id"), ), }, { - Config: testAccRouteTableAssociationSubnetConfig_ChangeSubnet, + Config: testAccRouteTableAssociationConfigSubnetChangeRouteTable(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta2), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "route_table_id", resourceNameRouteTable, "id"), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "subnet_id", resourceNameSubnet2, "id"), + testAccCheckRouteTableAssociationExists(resourceName, &rta), + resource.TestCheckResourceAttrPair(resourceName, "route_table_id", resourceNameRouteTable2, "id"), + resource.TestCheckResourceAttrPair(resourceName, "subnet_id", resourceNameSubnet, "id"), ), }, }, @@ -113,10 +79,10 @@ func TestAccAWSRouteTableAssociation_Subnet_ChangeSubnet(t *testing.T) { func TestAccAWSRouteTableAssociation_Gateway_basic(t *testing.T) { var rta ec2.RouteTableAssociation - - resourceNameAssoc := "aws_route_table_association.foo" - resourceNameRouteTable := "aws_route_table.foo" - resourceNameGateway := "aws_internet_gateway.foo" + resourceName := "aws_route_table_association.test" + resourceNameRouteTable := "aws_route_table.test" + resourceNameGateway := "aws_internet_gateway.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -125,17 +91,17 @@ func TestAccAWSRouteTableAssociation_Gateway_basic(t *testing.T) { CheckDestroy: testAccCheckRouteTableAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRouteTableAssociationGatewayConfig, + Config: testAccRouteTableAssociationConfigGateway(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "route_table_id", resourceNameRouteTable, "id"), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "gateway_id", resourceNameGateway, "id"), + testAccCheckRouteTableAssociationExists(resourceName, &rta), + resource.TestCheckResourceAttrPair(resourceName, "route_table_id", resourceNameRouteTable, "id"), + resource.TestCheckResourceAttrPair(resourceName, "gateway_id", resourceNameGateway, "id"), ), }, { - ResourceName: resourceNameAssoc, + ResourceName: resourceName, ImportState: true, - ImportStateIdFunc: testAccAWSRouteTabAssocImportStateIdFunc(resourceNameAssoc), + ImportStateIdFunc: testAccAWSRouteTabAssocImportStateIdFunc(resourceName), ImportStateVerify: true, }, }, @@ -143,46 +109,12 @@ func TestAccAWSRouteTableAssociation_Gateway_basic(t *testing.T) { } func TestAccAWSRouteTableAssociation_Gateway_ChangeRouteTable(t *testing.T) { - var rta1, rta2 ec2.RouteTableAssociation - - resourceNameAssoc := "aws_route_table_association.foo" - resourceNameRouteTable1 := "aws_route_table.foo" - resourceNameRouteTable2 := "aws_route_table.bar" - resourceNameGateway := "aws_internet_gateway.foo" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckRouteTableAssociationDestroy, - Steps: []resource.TestStep{ - { - Config: testAccRouteTableAssociationGatewayConfig, - Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta1), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "route_table_id", resourceNameRouteTable1, "id"), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "gateway_id", resourceNameGateway, "id"), - ), - }, - { - Config: testAccRouteTableAssociationGatewayConfig_ChangeRouteTable, - Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta2), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "route_table_id", resourceNameRouteTable2, "id"), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "gateway_id", resourceNameGateway, "id"), - ), - }, - }, - }) -} - -func TestAccAWSRouteTableAssociation_Gateway_ChangeGateway(t *testing.T) { - var rta1, rta2 ec2.RouteTableAssociation - - resourceNameAssoc := "aws_route_table_association.foo" - resourceNameRouteTable := "aws_route_table.foo" - resourceNameGateway1 := "aws_internet_gateway.foo" - resourceNameGateway2 := "aws_vpn_gateway.bar" + var rta ec2.RouteTableAssociation + resourceName := "aws_route_table_association.test" + resourceNameRouteTable1 := "aws_route_table.test" + resourceNameRouteTable2 := "aws_route_table.test2" + resourceNameGateway := "aws_internet_gateway.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -191,19 +123,19 @@ func TestAccAWSRouteTableAssociation_Gateway_ChangeGateway(t *testing.T) { CheckDestroy: testAccCheckRouteTableAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRouteTableAssociationGatewayConfig, + Config: testAccRouteTableAssociationConfigGateway(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta1), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "route_table_id", resourceNameRouteTable, "id"), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "gateway_id", resourceNameGateway1, "id"), + testAccCheckRouteTableAssociationExists(resourceName, &rta), + resource.TestCheckResourceAttrPair(resourceName, "route_table_id", resourceNameRouteTable1, "id"), + resource.TestCheckResourceAttrPair(resourceName, "gateway_id", resourceNameGateway, "id"), ), }, { - Config: testAccRouteTableAssociationGatewayConfig_ChangeGateway, + Config: testAccRouteTableAssociationConfigGatewayChangeRouteTable(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta2), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "route_table_id", resourceNameRouteTable, "id"), - resource.TestCheckResourceAttrPair(resourceNameAssoc, "gateway_id", resourceNameGateway2, "id"), + testAccCheckRouteTableAssociationExists(resourceName, &rta), + resource.TestCheckResourceAttrPair(resourceName, "route_table_id", resourceNameRouteTable2, "id"), + resource.TestCheckResourceAttrPair(resourceName, "gateway_id", resourceNameGateway, "id"), ), }, }, @@ -212,8 +144,8 @@ func TestAccAWSRouteTableAssociation_Gateway_ChangeGateway(t *testing.T) { func TestAccAWSRouteTableAssociation_disappears(t *testing.T) { var rta ec2.RouteTableAssociation - - resourceNameAssoc := "aws_route_table_association.foo" + resourceName := "aws_route_table_association.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -222,10 +154,10 @@ func TestAccAWSRouteTableAssociation_disappears(t *testing.T) { CheckDestroy: testAccCheckRouteTableAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRouteTableAssociationSubnetConfig, + Config: testAccRouteTableAssociationConfigSubnet(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckRouteTableAssociationExists(resourceNameAssoc, &rta), - testAccCheckRouteTableAssociationDisappears(&rta), + testAccCheckRouteTableAssociationExists(resourceName, &rta), + testAccCheckResourceDisappears(testAccProvider, resourceAwsRouteTableAssociation(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -241,7 +173,7 @@ func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error { continue } - routeTable, err := finder.RouteTableByID(conn, rs.Primary.ID) + _, err := finder.RouteTableAssociationByID(conn, rs.Primary.ID) if tfresource.NotFound(err) { continue @@ -251,15 +183,13 @@ func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error { return err } - if len(routeTable.Associations) > 0 { - return fmt.Errorf("Route table %s has associations", aws.StringValue(routeTable.RouteTableId)) - } + return fmt.Errorf("Route table association %s still exists", rs.Primary.ID) } return nil } -func testAccCheckRouteTableAssociationExists(n string, rta *ec2.RouteTableAssociation) resource.TestCheckFunc { +func testAccCheckRouteTableAssociationExists(n string, v *ec2.RouteTableAssociation) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -272,21 +202,15 @@ func testAccCheckRouteTableAssociationExists(n string, rta *ec2.RouteTableAssoci conn := testAccProvider.Meta().(*AWSClient).ec2conn - routeTable, err := finder.RouteTableByID(conn, rs.Primary.Attributes["route_table_id"]) + association, err := finder.RouteTableAssociationByID(conn, rs.Primary.ID) if err != nil { return err } - for _, association := range routeTable.Associations { - if rs.Primary.ID == aws.StringValue(association.RouteTableAssociationId) { - *rta = *association - - return nil - } - } + *v = *association - return fmt.Errorf("Association %q not found on Route Table %q", rs.Primary.ID, rs.Primary.Attributes["route_table_id"]) + return nil } } @@ -318,205 +242,135 @@ func testAccAWSRouteTabAssocImportStateIdFunc(resourceName string) resource.Impo } } -const testAccRouteTableAssociationSubnetConfig = testAccRouteTableAssociatonCommonVpcConfig + ` -resource "aws_route_table" "foo" { - vpc_id = aws_vpc.foo.id - - route { - cidr_block = "10.0.0.0/8" - gateway_id = aws_internet_gateway.foo.id - } +func testAccRouteTableAssociationConfigBaseVPC(rName string) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" tags = { - Name = "tf-acc-route-table-assoc" + Name = %[1]q } } -resource "aws_route_table_association" "foo" { - route_table_id = aws_route_table.foo.id - subnet_id = aws_subnet.foo.id -} -` - -const testAccRouteTableAssociationSubnetConfig_ChangeRouteTable = testAccRouteTableAssociatonCommonVpcConfig + ` -resource "aws_route_table" "bar" { - vpc_id = aws_vpc.foo.id +resource "aws_subnet" "test" { + vpc_id = aws_vpc.test.id + cidr_block = "10.1.1.0/24" - route { - cidr_block = "10.0.0.0/8" - gateway_id = aws_internet_gateway.foo.id + tags = { + Name = %[1]q } +} + +resource "aws_internet_gateway" "test" { + vpc_id = aws_vpc.test.id tags = { - Name = "tf-acc-route-update-table-assoc" + Name = %[1]q } } - -resource "aws_route_table_association" "foo" { - route_table_id = aws_route_table.bar.id - subnet_id = aws_subnet.foo.id +`, rName) } -` -const testAccRouteTableAssociationSubnetConfig_ChangeSubnet = testAccRouteTableAssociatonCommonVpcConfig + ` -resource "aws_route_table" "foo" { - vpc_id = aws_vpc.foo.id +func testAccRouteTableAssociationConfigSubnet(rName string) string { + return composeConfig(testAccRouteTableAssociationConfigBaseVPC(rName), fmt.Sprintf(` +resource "aws_route_table" "test" { + vpc_id = aws_vpc.test.id route { cidr_block = "10.0.0.0/8" - gateway_id = aws_internet_gateway.foo.id + gateway_id = aws_internet_gateway.test.id } tags = { - Name = "tf-acc-route-table-assoc" + Name = %[1]q } } -resource "aws_subnet" "bar" { - vpc_id = aws_vpc.foo.id - cidr_block = "10.1.2.0/24" - - tags = { - Name = "tf-acc-route-table-assoc" - } +resource "aws_route_table_association" "test" { + route_table_id = aws_route_table.test.id + subnet_id = aws_subnet.test.id } - -resource "aws_route_table_association" "foo" { - route_table_id = aws_route_table.foo.id - subnet_id = aws_subnet.bar.id +`, rName)) } -` -const testAccRouteTableAssociationGatewayConfig = testAccRouteTableAssociatonCommonVpcConfig + ` -resource "aws_route_table" "foo" { - vpc_id = aws_vpc.foo.id +func testAccRouteTableAssociationConfigSubnetChangeRouteTable(rName string) string { + return composeConfig(testAccRouteTableAssociationConfigBaseVPC(rName), fmt.Sprintf(` +resource "aws_route_table" "test2" { + vpc_id = aws_vpc.test.id route { - cidr_block = aws_subnet.foo.cidr_block - network_interface_id = aws_network_interface.appliance.id - } - - tags = { - Name = "tf-acc-route-table-assoc" + cidr_block = "10.0.0.0/8" + gateway_id = aws_internet_gateway.test.id } -} - -resource "aws_subnet" "appliance" { - vpc_id = aws_vpc.foo.id - cidr_block = "10.1.2.0/24" tags = { - Name = "tf-acc-route-table-assoc" + Name = %[1]q } } -resource "aws_network_interface" "appliance" { - subnet_id = aws_subnet.appliance.id +resource "aws_route_table_association" "test" { + route_table_id = aws_route_table.test2.id + subnet_id = aws_subnet.test.id } - -resource "aws_route_table_association" "foo" { - route_table_id = aws_route_table.foo.id - gateway_id = aws_internet_gateway.foo.id +`, rName)) } -` -const testAccRouteTableAssociationGatewayConfig_ChangeRouteTable = testAccRouteTableAssociatonCommonVpcConfig + ` -resource "aws_route_table" "bar" { - vpc_id = aws_vpc.foo.id +func testAccRouteTableAssociationConfigGateway(rName string) string { + return composeConfig(testAccRouteTableAssociationConfigBaseVPC(rName), fmt.Sprintf(` +resource "aws_route_table" "test" { + vpc_id = aws_vpc.test.id route { - cidr_block = aws_subnet.foo.cidr_block - network_interface_id = aws_network_interface.appliance.id + cidr_block = aws_subnet.test.cidr_block + network_interface_id = aws_network_interface.test.id } tags = { - Name = "tf-acc-route-table-assoc" + Name = %[1]q } } -resource "aws_subnet" "appliance" { - vpc_id = aws_vpc.foo.id - cidr_block = "10.1.2.0/24" +resource "aws_network_interface" "test" { + subnet_id = aws_subnet.test.id tags = { - Name = "tf-acc-route-table-assoc" + Name = %[1]q } } -resource "aws_network_interface" "appliance" { - subnet_id = aws_subnet.appliance.id +resource "aws_route_table_association" "test" { + route_table_id = aws_route_table.test.id + gateway_id = aws_internet_gateway.test.id } - -resource "aws_route_table_association" "foo" { - route_table_id = aws_route_table.bar.id - gateway_id = aws_internet_gateway.foo.id +`, rName)) } -` -const testAccRouteTableAssociationGatewayConfig_ChangeGateway = testAccRouteTableAssociatonCommonVpcConfig + ` -resource "aws_route_table" "foo" { - vpc_id = aws_vpc.foo.id +func testAccRouteTableAssociationConfigGatewayChangeRouteTable(rName string) string { + return composeConfig(testAccRouteTableAssociationConfigBaseVPC(rName), fmt.Sprintf(` +resource "aws_route_table" "test2" { + vpc_id = aws_vpc.test.id route { - cidr_block = aws_subnet.foo.cidr_block - network_interface_id = aws_network_interface.appliance.id - } - - tags = { - Name = "tf-acc-route-table-assoc" - } -} - -resource "aws_subnet" "appliance" { - vpc_id = aws_vpc.foo.id - cidr_block = "10.1.2.0/24" - - tags = { - Name = "tf-acc-route-table-assoc" + cidr_block = aws_subnet.test.cidr_block + network_interface_id = aws_network_interface.test.id } -} - -resource "aws_network_interface" "appliance" { - subnet_id = aws_subnet.appliance.id -} - -resource "aws_vpn_gateway" "bar" { - vpc_id = aws_vpc.foo.id tags = { - Name = "tf-acc-route-table-assoc" + Name = %[1]q } } -resource "aws_route_table_association" "foo" { - route_table_id = aws_route_table.foo.id - gateway_id = aws_vpn_gateway.bar.id -} -` - -const testAccRouteTableAssociatonCommonVpcConfig = ` -resource "aws_vpc" "foo" { - cidr_block = "10.1.0.0/16" +resource "aws_network_interface" "test" { + subnet_id = aws_subnet.test.id tags = { - Name = "tf-acc-route-table-assoc" + Name = %[1]q } } -resource "aws_subnet" "foo" { - vpc_id = aws_vpc.foo.id - cidr_block = "10.1.1.0/24" - - tags = { - Name = "tf-acc-route-table-assoc" - } +resource "aws_route_table_association" "test" { + route_table_id = aws_route_table.test2.id + gateway_id = aws_internet_gateway.test.id } - -resource "aws_internet_gateway" "foo" { - vpc_id = aws_vpc.foo.id - - tags = { - Name = "tf-acc-route-table-assoc" - } +`, rName)) } -` From 67c069f1d1b56cd63807c2c5aa05d2edf2cd4eca Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 14 Jun 2021 17:47:49 -0400 Subject: [PATCH 0452/1208] r/aws_main_route_table_association: Add waiters. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSMainRouteTableAssociation_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSMainRouteTableAssociation_ -timeout 180m === RUN TestAccAWSMainRouteTableAssociation_basic === PAUSE TestAccAWSMainRouteTableAssociation_basic === CONT TestAccAWSMainRouteTableAssociation_basic --- PASS: TestAccAWSMainRouteTableAssociation_basic (61.64s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 65.154s --- aws/internal/service/ec2/finder/finder.go | 40 +++++ ...source_aws_main_route_table_association.go | 158 ++++++++---------- ...e_aws_main_route_table_association_test.go | 143 ++++++++-------- ...source_aws_route_table_association_test.go | 12 -- 4 files changed, 177 insertions(+), 176 deletions(-) diff --git a/aws/internal/service/ec2/finder/finder.go b/aws/internal/service/ec2/finder/finder.go index 4bf913ffca19..19c803d940f6 100644 --- a/aws/internal/service/ec2/finder/finder.go +++ b/aws/internal/service/ec2/finder/finder.go @@ -235,6 +235,46 @@ func NetworkInterfaceSecurityGroup(conn *ec2.EC2, networkInterfaceID string, sec return result, err } +// MainRouteTableAssociationByID returns the main route table association corresponding to the specified identifier. +// Returns NotFoundError if no route table association is found. +func MainRouteTableAssociationByID(conn *ec2.EC2, associationID string) (*ec2.RouteTableAssociation, error) { + association, err := RouteTableAssociationByID(conn, associationID) + + if err != nil { + return nil, err + } + + if !aws.BoolValue(association.Main) { + return nil, &resource.NotFoundError{ + Message: fmt.Sprintf("%s is not the association with the main route table", associationID), + } + } + + return association, err +} + +// MainRouteTableAssociationByVpcID returns the main route table association for the specified VPC. +// Returns NotFoundError if no route table association is found. +func MainRouteTableAssociationByVpcID(conn *ec2.EC2, vpcID string) (*ec2.RouteTableAssociation, error) { + routeTable, err := MainRouteTableByVpcID(conn, vpcID) + + if err != nil { + return nil, err + } + + for _, association := range routeTable.Associations { + if aws.BoolValue(association.Main) { + if state := aws.StringValue(association.AssociationState.State); state == ec2.RouteTableAssociationStateCodeDisassociated { + continue + } + + return association, nil + } + } + + return nil, &resource.NotFoundError{} +} + // RouteTableAssociationByID returns the route table association corresponding to the specified identifier. // Returns NotFoundError if no route table association is found. func RouteTableAssociationByID(conn *ec2.EC2, associationID string) (*ec2.RouteTableAssociation, error) { diff --git a/aws/resource_aws_main_route_table_association.go b/aws/resource_aws_main_route_table_association.go index a3f08b082e78..e8a3b955fd75 100644 --- a/aws/resource_aws_main_route_table_association.go +++ b/aws/resource_aws_main_route_table_association.go @@ -7,6 +7,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsMainRouteTableAssociation() *schema.Resource { @@ -17,9 +20,13 @@ func resourceAwsMainRouteTableAssociation() *schema.Resource { Delete: resourceAwsMainRouteTableAssociationDelete, Schema: map[string]*schema.Schema{ - "vpc_id": { + // We use this field to record the main route table that is automatically + // created when the VPC is created. We need this to be able to "destroy" + // our main route table association, which we do by returning this route + // table to its original place as the Main Route Table for the VPC. + "original_route_table_id": { Type: schema.TypeString, - Required: true, + Computed: true, }, "route_table_id": { @@ -27,13 +34,9 @@ func resourceAwsMainRouteTableAssociation() *schema.Resource { Required: true, }, - // We use this field to record the main route table that is automatically - // created when the VPC is created. We need this to be able to "destroy" - // our main route table association, which we do by returning this route - // table to its original place as the Main Route Table for the VPC. - "original_route_table_id": { + "vpc_id": { Type: schema.TypeString, - Computed: true, + Required: true, }, }, } @@ -41,134 +44,105 @@ func resourceAwsMainRouteTableAssociation() *schema.Resource { func resourceAwsMainRouteTableAssociationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - vpcId := d.Get("vpc_id").(string) - routeTableId := d.Get("route_table_id").(string) - log.Printf("[INFO] Creating main route table association: %s => %s", vpcId, routeTableId) + vpcID := d.Get("vpc_id").(string) - mainAssociation, err := findMainRouteTableAssociation(conn, vpcId) + association, err := finder.MainRouteTableAssociationByVpcID(conn, vpcID) if err != nil { - return fmt.Errorf("error finding EC2 VPC (%s) main route table association for replacement: %w", vpcId, err) + return fmt.Errorf("error reading Main Route Table Association (%s): %w", vpcID, err) } - if mainAssociation == nil { - return fmt.Errorf("error finding EC2 VPC (%s) main route table association for replacement: association not found", vpcId) + routeTableID := d.Get("route_table_id").(string) + input := &ec2.ReplaceRouteTableAssociationInput{ + AssociationId: association.RouteTableAssociationId, + RouteTableId: aws.String(routeTableID), } - resp, err := conn.ReplaceRouteTableAssociation(&ec2.ReplaceRouteTableAssociationInput{ - AssociationId: mainAssociation.RouteTableAssociationId, - RouteTableId: aws.String(routeTableId), - }) + log.Printf("[DEBUG] Creating Main Route Table Association: %s", input) + output, err := conn.ReplaceRouteTableAssociation(input) + if err != nil { - return err + return fmt.Errorf("error creating Main Route Table Association (%s): %w", routeTableID, err) } - d.Set("original_route_table_id", mainAssociation.RouteTableId) - d.SetId(aws.StringValue(resp.NewAssociationId)) - log.Printf("[INFO] New main route table association ID: %s", d.Id()) + d.SetId(aws.StringValue(output.NewAssociationId)) - return nil + log.Printf("[DEBUG] Waiting for Main Route Table Association (%s) creation", d.Id()) + if _, err := waiter.RouteTableAssociationUpdated(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Main Route Table Association (%s) create: %w", d.Id(), err) + } + + d.Set("original_route_table_id", association.RouteTableId) + + return resourceAwsMainRouteTableAssociationRead(d, meta) } func resourceAwsMainRouteTableAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - mainAssociation, err := findMainRouteTableAssociation( - conn, - d.Get("vpc_id").(string)) - if err != nil { - return err - } + _, err := finder.MainRouteTableAssociationByID(conn, d.Id()) - if mainAssociation == nil || *mainAssociation.RouteTableAssociationId != d.Id() { - // It seems it doesn't exist anymore, so clear the ID + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Main Route Table Association (%s) not found, removing from state", d.Id()) d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading Main Route Table Association (%s): %w", d.Id(), err) } return nil } -// Update is almost exactly like Create, except we want to retain the -// original_route_table_id - this needs to stay recorded as the AWS-created -// table from VPC creation. func resourceAwsMainRouteTableAssociationUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - vpcId := d.Get("vpc_id").(string) - routeTableId := d.Get("route_table_id").(string) - log.Printf("[INFO] Updating main route table association: %s => %s", vpcId, routeTableId) - - resp, err := conn.ReplaceRouteTableAssociation(&ec2.ReplaceRouteTableAssociationInput{ + routeTableID := d.Get("route_table_id").(string) + input := &ec2.ReplaceRouteTableAssociationInput{ AssociationId: aws.String(d.Id()), - RouteTableId: aws.String(routeTableId), - }) + RouteTableId: aws.String(routeTableID), + } + + log.Printf("[DEBUG] Updating Main Route Table Association: %s", input) + output, err := conn.ReplaceRouteTableAssociation(input) + if err != nil { - return err + return fmt.Errorf("error updating Main Route Table Association (%s): %w", routeTableID, err) } - d.SetId(aws.StringValue(resp.NewAssociationId)) - log.Printf("[INFO] New main route table association ID: %s", d.Id()) + // This whole thing with the resource ID being changed on update seems unsustainable. + // Keeping it here for backwards compatibilty... + d.SetId(aws.StringValue(output.NewAssociationId)) - return nil + log.Printf("[DEBUG] Waiting for Main Route Table Association (%s) update", d.Id()) + if _, err := waiter.RouteTableAssociationUpdated(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for Main Route Table Association (%s) update: %w", d.Id(), err) + } + + return resourceAwsMainRouteTableAssociationRead(d, meta) } func resourceAwsMainRouteTableAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - vpcId := d.Get("vpc_id").(string) - originalRouteTableId := d.Get("original_route_table_id").(string) - - log.Printf("[INFO] Deleting main route table association by resetting Main Route Table for VPC: %s to its original Route Table: %s", - vpcId, - originalRouteTableId) - resp, err := conn.ReplaceRouteTableAssociation(&ec2.ReplaceRouteTableAssociationInput{ + input := &ec2.ReplaceRouteTableAssociationInput{ AssociationId: aws.String(d.Id()), - RouteTableId: aws.String(originalRouteTableId), - }) - if err != nil { - return err + RouteTableId: aws.String(d.Get("original_route_table_id").(string)), } - log.Printf("[INFO] Resulting Association ID: %s", *resp.NewAssociationId) + log.Printf("[DEBUG] Deleting Main Route Table Association: %s", input) + output, err := conn.ReplaceRouteTableAssociation(input) - return nil -} - -func findMainRouteTableAssociation(conn *ec2.EC2, vpcId string) (*ec2.RouteTableAssociation, error) { - mainRouteTable, err := findMainRouteTable(conn, vpcId) if err != nil { - return nil, err - } - if mainRouteTable == nil { - return nil, nil + return fmt.Errorf("error deleting Main Route Table Association (%s): %w", d.Get("route_table_id").(string), err) } - for _, a := range mainRouteTable.Associations { - if *a.Main { - return a, nil - } + log.Printf("[DEBUG] Waiting for Main Route Table Association (%s) deletion", d.Id()) + if _, err := waiter.RouteTableAssociationUpdated(conn, aws.StringValue(output.NewAssociationId)); err != nil { + return fmt.Errorf("error waiting for Main Route Table Association (%s) delete: %w", d.Id(), err) } - return nil, fmt.Errorf("Could not find main routing table association for VPC: %s", vpcId) -} -func findMainRouteTable(conn *ec2.EC2, vpcId string) (*ec2.RouteTable, error) { - mainFilter := &ec2.Filter{ - Name: aws.String("association.main"), - Values: []*string{aws.String("true")}, - } - vpcFilter := &ec2.Filter{ - Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpcId)}, - } - routeResp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{ - Filters: []*ec2.Filter{mainFilter, vpcFilter}, - }) - if err != nil { - return nil, err - } else if len(routeResp.RouteTables) != 1 { - return nil, nil - } - - return routeResp.RouteTables[0], nil + return nil } diff --git a/aws/resource_aws_main_route_table_association_test.go b/aws/resource_aws_main_route_table_association_test.go index c511349fb007..83bbb135e538 100644 --- a/aws/resource_aws_main_route_table_association_test.go +++ b/aws/resource_aws_main_route_table_association_test.go @@ -4,13 +4,19 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" + "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestAccAWSMainRouteTableAssociation_basic(t *testing.T) { + var rta ec2.RouteTableAssociation + resourceName := "aws_main_route_table_association.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), @@ -18,15 +24,15 @@ func TestAccAWSMainRouteTableAssociation_basic(t *testing.T) { CheckDestroy: testAccCheckMainRouteTableAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccMainRouteTableAssociationConfig, + Config: testAccMainRouteTableAssociationConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckMainRouteTableAssociation("aws_main_route_table_association.foo", "aws_vpc.foo"), + testAccCheckMainRouteTableAssociationExists(resourceName, &rta), ), }, { - Config: testAccMainRouteTableAssociationConfigUpdate, + Config: testAccMainRouteTableAssociationConfigUpdated(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckMainRouteTableAssociation("aws_main_route_table_association.foo", "aws_vpc.foo"), + testAccCheckMainRouteTableAssociationExists(resourceName, &rta), ), }, }, @@ -41,139 +47,132 @@ func testAccCheckMainRouteTableAssociationDestroy(s *terraform.State) error { continue } - mainAssociation, err := findMainRouteTableAssociation( - conn, - rs.Primary.Attributes["vpc_id"], - ) + _, err := finder.MainRouteTableAssociationByID(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + if err != nil { - // Verify the error is what we want - if ae, ok := err.(awserr.Error); ok && ae.Code() == "ApplicationDoesNotExistException" { - continue - } return err } - if mainAssociation != nil { - return fmt.Errorf("still exists") - } + return fmt.Errorf("Main route table association %s still exists", rs.Primary.ID) } return nil } -func testAccCheckMainRouteTableAssociation(mainRouteTableAssociationResource string, vpcResource string) resource.TestCheckFunc { +func testAccCheckMainRouteTableAssociationExists(n string, v *ec2.RouteTableAssociation) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[mainRouteTableAssociationResource] + rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", mainRouteTableAssociationResource) + return fmt.Errorf("Not found: %s", n) } if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } - vpc, ok := s.RootModule().Resources[vpcResource] - if !ok { - return fmt.Errorf("Not found: %s", vpcResource) - } - conn := testAccProvider.Meta().(*AWSClient).ec2conn - mainAssociation, err := findMainRouteTableAssociation(conn, vpc.Primary.ID) + + association, err := finder.MainRouteTableAssociationByID(conn, rs.Primary.ID) + if err != nil { return err } - if *mainAssociation.RouteTableAssociationId != rs.Primary.ID { - return fmt.Errorf("Found wrong main association: %s", - *mainAssociation.RouteTableAssociationId) - } + *v = *association return nil } } -const testAccMainRouteTableAssociationConfig = ` -resource "aws_vpc" "foo" { +func testAccMainRouteTableAssociationConfigBaseVPC(rName string) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { cidr_block = "10.1.0.0/16" tags = { - Name = "terraform-testacc-main-route-table-association" + Name = %[1]q } } -resource "aws_subnet" "foo" { - vpc_id = aws_vpc.foo.id +resource "aws_subnet" "test" { + vpc_id = aws_vpc.test.id cidr_block = "10.1.1.0/24" tags = { - Name = "tf-acc-main-route-table-association" + Name = %[1]q } } -resource "aws_internet_gateway" "foo" { - vpc_id = aws_vpc.foo.id -} - -resource "aws_route_table" "foo" { - vpc_id = aws_vpc.foo.id +resource "aws_internet_gateway" "test" { + vpc_id = aws_vpc.test.id - route { - cidr_block = "10.0.0.0/8" - gateway_id = aws_internet_gateway.foo.id + tags = { + Name = %[1]q } } - -resource "aws_main_route_table_association" "foo" { - vpc_id = aws_vpc.foo.id - route_table_id = aws_route_table.foo.id +`, rName) } -` -const testAccMainRouteTableAssociationConfigUpdate = ` -resource "aws_vpc" "foo" { - cidr_block = "10.1.0.0/16" +func testAccMainRouteTableAssociationConfig(rName string) string { + return composeConfig(testAccMainRouteTableAssociationConfigBaseVPC(rName), fmt.Sprintf(` +resource "aws_route_table" "test" { + vpc_id = aws_vpc.test.id - tags = { - Name = "terraform-testacc-main-route-table-association-update" + route { + cidr_block = "10.0.0.0/8" + gateway_id = aws_internet_gateway.test.id } -} - -resource "aws_subnet" "foo" { - vpc_id = aws_vpc.foo.id - cidr_block = "10.1.1.0/24" tags = { - Name = "tf-acc-main-route-table-association-update" + Name = %[1]q } } -resource "aws_internet_gateway" "foo" { - vpc_id = aws_vpc.foo.id +resource "aws_main_route_table_association" "test" { + vpc_id = aws_vpc.test.id + route_table_id = aws_route_table.test.id +} +`, rName)) } +func testAccMainRouteTableAssociationConfigUpdated(rName string) string { + return composeConfig(testAccMainRouteTableAssociationConfigBaseVPC(rName), fmt.Sprintf(` # Need to keep the old route table around when we update the # main_route_table_association, otherwise Terraform will try to destroy the # route table too early, and will fail because it's still the main one -resource "aws_route_table" "foo" { - vpc_id = aws_vpc.foo.id +resource "aws_route_table" "test" { + vpc_id = aws_vpc.test.id route { cidr_block = "10.0.0.0/8" - gateway_id = aws_internet_gateway.foo.id + gateway_id = aws_internet_gateway.test.id + } + + tags = { + Name = %[1]q } } -resource "aws_route_table" "bar" { - vpc_id = aws_vpc.foo.id +resource "aws_route_table" "test2" { + vpc_id = aws_vpc.test.id route { cidr_block = "10.0.0.0/8" - gateway_id = aws_internet_gateway.foo.id + gateway_id = aws_internet_gateway.test.id + } + + tags = { + Name = %[1]q } } -resource "aws_main_route_table_association" "foo" { - vpc_id = aws_vpc.foo.id - route_table_id = aws_route_table.bar.id +resource "aws_main_route_table_association" "test" { + vpc_id = aws_vpc.test.id + route_table_id = aws_route_table.test2.id +} +`, rName)) } -` diff --git a/aws/resource_aws_route_table_association_test.go b/aws/resource_aws_route_table_association_test.go index e0017635d4ee..44693350e379 100644 --- a/aws/resource_aws_route_table_association_test.go +++ b/aws/resource_aws_route_table_association_test.go @@ -214,18 +214,6 @@ func testAccCheckRouteTableAssociationExists(n string, v *ec2.RouteTableAssociat } } -func testAccCheckRouteTableAssociationDisappears(rta *ec2.RouteTableAssociation) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).ec2conn - - _, err := conn.DisassociateRouteTable(&ec2.DisassociateRouteTableInput{ - AssociationId: rta.RouteTableAssociationId, - }) - - return err - } -} - func testAccAWSRouteTabAssocImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { return func(s *terraform.State) (string, error) { rs, ok := s.RootModule().Resources[resourceName] From af7c0267f41c013e9b52482023912b147afea18a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 10:15:49 -0400 Subject: [PATCH 0453/1208] Add 'tfresource.RetryUntilFound'. Test 'tfresource.RetryUntilFound'. --- aws/internal/tfresource/retry.go | 33 ++++++++++++++++ aws/internal/tfresource/retry_test.go | 56 +++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/aws/internal/tfresource/retry.go b/aws/internal/tfresource/retry.go index 517a6b219334..544b2d688799 100644 --- a/aws/internal/tfresource/retry.go +++ b/aws/internal/tfresource/retry.go @@ -7,6 +7,39 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) +// RetryUntilFound retries the specified function until the underlying resource is found. +// The function returns a resource.NotFoundError to indicate that the underlying resource does not exist. +// If the retries time out, the function is called one last time. +func RetryUntilFound(timeout time.Duration, f func() (interface{}, error)) (interface{}, error) { + var output interface{} + + err := resource.Retry(timeout, func() *resource.RetryError { + var err error + + output, err = f() + + if NotFound(err) { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if TimedOut(err) { + output, err = f() + } + + if err != nil { + return nil, err + } + + return output, err +} + // RetryWhenAwsErrCodeEquals retries the specified function when it returns one of the specified AWS error code. func RetryWhenAwsErrCodeEquals(timeout time.Duration, f func() (interface{}, error), codes ...string) (interface{}, error) { var output interface{} diff --git a/aws/internal/tfresource/retry_test.go b/aws/internal/tfresource/retry_test.go index 8a396b9e3de5..ecb8b14907f1 100644 --- a/aws/internal/tfresource/retry_test.go +++ b/aws/internal/tfresource/retry_test.go @@ -7,9 +7,65 @@ import ( "time" "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) +func TestRetryUntilFound(t *testing.T) { + var retryCount int32 + + testCases := []struct { + Name string + F func() (interface{}, error) + ExpectError bool + }{ + { + Name: "no error", + F: func() (interface{}, error) { + return nil, nil + }, + }, + { + Name: "non-retryable other error", + F: func() (interface{}, error) { + return nil, errors.New("TestCode") + }, + ExpectError: true, + }, + { + Name: "retryable not-found error timeout", + F: func() (interface{}, error) { + return nil, &resource.NotFoundError{} + }, + ExpectError: true, + }, + { + Name: "retryable AWS error success", + F: func() (interface{}, error) { + if atomic.CompareAndSwapInt32(&retryCount, 0, 1) { + return nil, &resource.NotFoundError{} + } + + return nil, nil + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + retryCount = 0 + + _, err := tfresource.RetryUntilFound(5*time.Second, testCase.F) + + if testCase.ExpectError && err == nil { + t.Fatal("expected error") + } else if !testCase.ExpectError && err != nil { + t.Fatalf("unexpected error: %s", err) + } + }) + } +} + func TestRetryWhenAwsErrCodeEquals(t *testing.T) { var retryCount int32 From 081aebdba912a7d9cb623fd0c8ad5cee3e1b1a46 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 10:24:23 -0400 Subject: [PATCH 0454/1208] Revert "Add 'tfresource.RetryUntilFound'." This reverts commit af7c0267f41c013e9b52482023912b147afea18a. --- aws/internal/tfresource/retry.go | 33 ---------------- aws/internal/tfresource/retry_test.go | 56 --------------------------- 2 files changed, 89 deletions(-) diff --git a/aws/internal/tfresource/retry.go b/aws/internal/tfresource/retry.go index 544b2d688799..517a6b219334 100644 --- a/aws/internal/tfresource/retry.go +++ b/aws/internal/tfresource/retry.go @@ -7,39 +7,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -// RetryUntilFound retries the specified function until the underlying resource is found. -// The function returns a resource.NotFoundError to indicate that the underlying resource does not exist. -// If the retries time out, the function is called one last time. -func RetryUntilFound(timeout time.Duration, f func() (interface{}, error)) (interface{}, error) { - var output interface{} - - err := resource.Retry(timeout, func() *resource.RetryError { - var err error - - output, err = f() - - if NotFound(err) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return nil - }) - - if TimedOut(err) { - output, err = f() - } - - if err != nil { - return nil, err - } - - return output, err -} - // RetryWhenAwsErrCodeEquals retries the specified function when it returns one of the specified AWS error code. func RetryWhenAwsErrCodeEquals(timeout time.Duration, f func() (interface{}, error), codes ...string) (interface{}, error) { var output interface{} diff --git a/aws/internal/tfresource/retry_test.go b/aws/internal/tfresource/retry_test.go index ecb8b14907f1..8a396b9e3de5 100644 --- a/aws/internal/tfresource/retry_test.go +++ b/aws/internal/tfresource/retry_test.go @@ -7,65 +7,9 @@ import ( "time" "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -func TestRetryUntilFound(t *testing.T) { - var retryCount int32 - - testCases := []struct { - Name string - F func() (interface{}, error) - ExpectError bool - }{ - { - Name: "no error", - F: func() (interface{}, error) { - return nil, nil - }, - }, - { - Name: "non-retryable other error", - F: func() (interface{}, error) { - return nil, errors.New("TestCode") - }, - ExpectError: true, - }, - { - Name: "retryable not-found error timeout", - F: func() (interface{}, error) { - return nil, &resource.NotFoundError{} - }, - ExpectError: true, - }, - { - Name: "retryable AWS error success", - F: func() (interface{}, error) { - if atomic.CompareAndSwapInt32(&retryCount, 0, 1) { - return nil, &resource.NotFoundError{} - } - - return nil, nil - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.Name, func(t *testing.T) { - retryCount = 0 - - _, err := tfresource.RetryUntilFound(5*time.Second, testCase.F) - - if testCase.ExpectError && err == nil { - t.Fatal("expected error") - } else if !testCase.ExpectError && err != nil { - t.Fatalf("unexpected error: %s", err) - } - }) - } -} - func TestRetryWhenAwsErrCodeEquals(t *testing.T) { var retryCount int32 From 42c30754145d2a5a1bfb2a3eb5e765a5e9caa782 Mon Sep 17 00:00:00 2001 From: Nayo Akinyele Date: Tue, 15 Jun 2021 14:47:11 +0100 Subject: [PATCH 0455/1208] Change order of test execution in AWSCloudWatchEventBusPolicy --- ...ce_aws_cloudwatch_event_bus_policy_test.go | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index 1bb8c1f01285..32851bb9774c 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -1,17 +1,14 @@ package aws import ( - // "encoding/json" "fmt" "testing" - // "time" "github.com/aws/aws-sdk-go/aws" events "github.com/aws/aws-sdk-go/service/cloudwatchevents" "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" - // tfevents "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents" ) func TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { @@ -38,6 +35,28 @@ func TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { }) } +func TestAccAWSCloudWatchEventBusPolicy_disappears(t *testing.T) { + resourceName := "aws_cloudwatch_event_bus_policy.test" + rstring := acctest.RandString(5) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventBusDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudwatchEventBusPolicyConfig(rstring), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchEventBusPolicy(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAWSCloudwatchEventBusPolicyExists(pr string) resource.TestCheckFunc { return func(state *terraform.State) error { eventBusResource, ok := state.RootModule().Resources[pr] @@ -99,25 +118,3 @@ resource "aws_cloudwatch_event_bus_policy" "test" { } `, name) } - -func TestAccAWSCloudWatchEventBusPolicy_Disappears(t *testing.T) { - resourceName := "aws_cloudwatch_event_bus_policy.test" - busName := acctest.RandomWithPrefix("tf-acc-test-bus") - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, events.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSCloudWatchEventBusDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSCloudwatchEventBusPolicyConfig(busName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), - testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudWatchEventBusPolicy(), resourceName), - ), - ExpectNonEmptyPlan: true, - }, - }, - }) -} From 3a96fb1d3ea2b5cbcc8644d9394c156337fcf85e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 11:19:50 -0400 Subject: [PATCH 0456/1208] VPC Endpoint changes from #13737. --- aws/internal/service/ec2/enum.go | 12 + aws/internal/service/ec2/errors.go | 5 +- aws/internal/service/ec2/finder/finder.go | 87 ++++-- aws/internal/service/ec2/id.go | 8 + aws/internal/service/ec2/waiter/status.go | 16 ++ aws/internal/service/ec2/waiter/waiter.go | 62 +++++ aws/resource_aws_vpc_endpoint.go | 116 ++------ ...ws_vpc_endpoint_route_table_association.go | 115 +++----- ...c_endpoint_route_table_association_test.go | 86 +++--- ...rce_aws_vpc_endpoint_subnet_association.go | 105 ++++---- ...ws_vpc_endpoint_subnet_association_test.go | 202 ++++++-------- aws/resource_aws_vpc_endpoint_test.go | 255 ++++-------------- 12 files changed, 454 insertions(+), 615 deletions(-) create mode 100644 aws/internal/service/ec2/enum.go diff --git a/aws/internal/service/ec2/enum.go b/aws/internal/service/ec2/enum.go new file mode 100644 index 000000000000..e7bfd1269526 --- /dev/null +++ b/aws/internal/service/ec2/enum.go @@ -0,0 +1,12 @@ +package ec2 + +const ( + // https://docs.aws.amazon.com/vpc/latest/privatelink/vpce-interface.html#vpce-interface-lifecycle + VpcEndpointStateAvailable = "available" + VpcEndpointStateDeleted = "deleted" + VpcEndpointStateDeleting = "deleting" + VpcEndpointStateFailed = "failed" + VpcEndpointStatePending = "pending" + VpcEndpointStatePendingAcceptance = "pendingAcceptance" + VpcEndpointStateRejected = "rejected" +) diff --git a/aws/internal/service/ec2/errors.go b/aws/internal/service/ec2/errors.go index f4f93f28cd10..cbcac12e0975 100644 --- a/aws/internal/service/ec2/errors.go +++ b/aws/internal/service/ec2/errors.go @@ -5,12 +5,13 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/go-multierror" + multierror "github.com/hashicorp/go-multierror" ) const ( ErrCodeGatewayNotAttached = "Gateway.NotAttached" ErrCodeInvalidAssociationIDNotFound = "InvalidAssociationID.NotFound" + ErrCodeInvalidParameter = "InvalidParameter" ErrCodeInvalidParameterException = "InvalidParameterException" ErrCodeInvalidParameterValue = "InvalidParameterValue" ) @@ -29,6 +30,7 @@ const ( const ( ErrCodeInvalidRouteNotFound = "InvalidRoute.NotFound" + ErrCodeInvalidRouteTableIdNotFound = "InvalidRouteTableId.NotFound" ErrCodeInvalidRouteTableIDNotFound = "InvalidRouteTableID.NotFound" ) @@ -57,6 +59,7 @@ const ( ) const ( + ErrCodeInvalidSubnetIdNotFound = "InvalidSubnetId.NotFound" ErrCodeInvalidSubnetIDNotFound = "InvalidSubnetID.NotFound" ) diff --git a/aws/internal/service/ec2/finder/finder.go b/aws/internal/service/ec2/finder/finder.go index 19c803d940f6..81d99aff35b0 100644 --- a/aws/internal/service/ec2/finder/finder.go +++ b/aws/internal/service/ec2/finder/finder.go @@ -619,59 +619,96 @@ func VpcByID(conn *ec2.EC2, id string) (*ec2.Vpc, error) { return nil, nil } -// VpcEndpointByID looks up a VpcEndpoint by ID. When not found, returns nil and potentially an API error. -func VpcEndpointByID(conn *ec2.EC2, id string) (*ec2.VpcEndpoint, error) { +// VpcEndpointByID returns the VPC endpoint corresponding to the specified identifier. +// Returns NotFoundError if no VPC endpoint is found. +func VpcEndpointByID(conn *ec2.EC2, vpcEndpointID string) (*ec2.VpcEndpoint, error) { input := &ec2.DescribeVpcEndpointsInput{ - VpcEndpointIds: aws.StringSlice([]string{id}), + VpcEndpointIds: aws.StringSlice([]string{vpcEndpointID}), } - output, err := conn.DescribeVpcEndpoints(input) + vpcEndpoint, err := VpcEndpoint(conn, input) if err != nil { return nil, err } - if output == nil { - return nil, nil - } - - for _, vpcEndpoint := range output.VpcEndpoints { - if vpcEndpoint == nil { - continue + if state := aws.StringValue(vpcEndpoint.State); state == tfec2.VpcEndpointStateDeleted { + return nil, &resource.NotFoundError{ + Message: state, + LastRequest: input, } + } - if aws.StringValue(vpcEndpoint.VpcEndpointId) != id { - continue + // Eventual consistency check. + if aws.StringValue(vpcEndpoint.VpcEndpointId) != vpcEndpointID { + return nil, &resource.NotFoundError{ + LastRequest: input, } - - return vpcEndpoint, nil } - return nil, nil + return vpcEndpoint, nil } -// VpcEndpointRouteTableAssociation returns the associated Route Table ID if found -func VpcEndpointRouteTableAssociation(conn *ec2.EC2, vpcEndpointID string, routeTableID string) (*string, error) { - var result *string +func VpcEndpoint(conn *ec2.EC2, input *ec2.DescribeVpcEndpointsInput) (*ec2.VpcEndpoint, error) { + output, err := conn.DescribeVpcEndpoints(input) - vpcEndpoint, err := VpcEndpointByID(conn, vpcEndpointID) + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidVpcEndpointIdNotFound) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } if err != nil { return nil, err } - if vpcEndpoint == nil { - return nil, nil + if output == nil || len(output.VpcEndpoints) == 0 || output.VpcEndpoints[0] == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.VpcEndpoints[0], nil +} + +// VpcEndpointRouteTableAssociationExists returns NotFoundError if no association for the specified VPC endpoint and route table IDs is found. +func VpcEndpointRouteTableAssociationExists(conn *ec2.EC2, vpcEndpointID string, routeTableID string) error { + vpcEndpoint, err := VpcEndpointByID(conn, vpcEndpointID) + + if err != nil { + return err } for _, vpcEndpointRouteTableID := range vpcEndpoint.RouteTableIds { if aws.StringValue(vpcEndpointRouteTableID) == routeTableID { - result = vpcEndpointRouteTableID - break + return nil } } - return result, err + return &resource.NotFoundError{ + LastError: fmt.Errorf("VPC Endpoint Route Table Association (%s/%s) not found", vpcEndpointID, routeTableID), + } +} + +// VpcEndpointSubnetAssociationExists returns NotFoundError if no association for the specified VPC endpoint and subnet IDs is found. +func VpcEndpointSubnetAssociationExists(conn *ec2.EC2, vpcEndpointID string, subnetID string) error { + vpcEndpoint, err := VpcEndpointByID(conn, vpcEndpointID) + + if err != nil { + return err + } + + for _, vpcEndpointSubnetID := range vpcEndpoint.SubnetIds { + if aws.StringValue(vpcEndpointSubnetID) == subnetID { + return nil + } + } + + return &resource.NotFoundError{ + LastError: fmt.Errorf("VPC Endpoint Subnet Association (%s/%s) not found", vpcEndpointID, subnetID), + } } // VpcPeeringConnectionByID returns the VPC peering connection corresponding to the specified identifier. diff --git a/aws/internal/service/ec2/id.go b/aws/internal/service/ec2/id.go index c7fa5040e0f7..cf5cb8a0cb38 100644 --- a/aws/internal/service/ec2/id.go +++ b/aws/internal/service/ec2/id.go @@ -95,6 +95,14 @@ func TransitGatewayPrefixListReferenceParseID(id string) (string, string, error) return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected transit-gateway-route-table-id%[2]sprefix-list-id", id, transitGatewayPrefixListReferenceSeparator) } +func VpcEndpointRouteTableAssociationCreateID(vpcEndpointID, routeTableID string) string { + return fmt.Sprintf("a-%s%d", vpcEndpointID, hashcode.String(routeTableID)) +} + +func VpcEndpointSubnetAssociationCreateID(vpcEndpointID, subnetID string) string { + return fmt.Sprintf("a-%s%d", vpcEndpointID, hashcode.String(subnetID)) +} + func VpnGatewayVpcAttachmentCreateID(vpnGatewayID, vpcID string) string { return fmt.Sprintf("vpn-attachment-%x", hashcode.String(fmt.Sprintf("%s-%s", vpcID, vpnGatewayID))) } diff --git a/aws/internal/service/ec2/waiter/status.go b/aws/internal/service/ec2/waiter/status.go index 8b8ffde410c6..3fa0a512c85c 100644 --- a/aws/internal/service/ec2/waiter/status.go +++ b/aws/internal/service/ec2/waiter/status.go @@ -504,3 +504,19 @@ func ManagedPrefixListState(conn *ec2.EC2, prefixListId string) resource.StateRe return managedPrefixList, aws.StringValue(managedPrefixList.State), nil } } + +func VpcEndpointState(conn *ec2.EC2, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + vpcEndpoint, err := finder.VpcEndpointByID(conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return vpcEndpoint, aws.StringValue(vpcEndpoint.State), nil + } +} diff --git a/aws/internal/service/ec2/waiter/waiter.go b/aws/internal/service/ec2/waiter/waiter.go index b119c2fdb779..6a55619627a4 100644 --- a/aws/internal/service/ec2/waiter/waiter.go +++ b/aws/internal/service/ec2/waiter/waiter.go @@ -2,6 +2,7 @@ package waiter import ( "errors" + "fmt" "strconv" "time" @@ -689,3 +690,64 @@ func ManagedPrefixListDeleted(conn *ec2.EC2, prefixListId string) error { return nil } + +func VpcEndpointAccepted(conn *ec2.EC2, vpcEndpointID string, timeout time.Duration) (*ec2.VpcEndpoint, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{tfec2.VpcEndpointStatePendingAcceptance}, + Target: []string{tfec2.VpcEndpointStateAvailable}, + Timeout: timeout, + Refresh: VpcEndpointState(conn, vpcEndpointID), + Delay: 5 * time.Second, + MinTimeout: 5 * time.Second, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*ec2.VpcEndpoint); ok { + if output != nil && aws.StringValue(output.State) == tfec2.VpcEndpointStateFailed && output.LastError != nil { + tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.StringValue(output.LastError.Code), aws.StringValue(output.LastError.Message))) + } + + return output, err + } + + return nil, err +} + +func VpcEndpointAvailable(conn *ec2.EC2, vpcEndpointID string, timeout time.Duration) (*ec2.VpcEndpoint, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{tfec2.VpcEndpointStatePending}, + Target: []string{tfec2.VpcEndpointStateAvailable, tfec2.VpcEndpointStatePendingAcceptance}, + Timeout: timeout, + Refresh: VpcEndpointState(conn, vpcEndpointID), + Delay: 5 * time.Second, + MinTimeout: 5 * time.Second, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*ec2.VpcEndpoint); ok { + return output, err + } + + return nil, err +} + +func VpcEndpointDeleted(conn *ec2.EC2, vpcEndpointID string, timeout time.Duration) (*ec2.VpcEndpoint, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{tfec2.VpcEndpointStateDeleting}, + Target: []string{}, + Timeout: timeout, + Refresh: VpcEndpointState(conn, vpcEndpointID), + Delay: 5 * time.Second, + MinTimeout: 5 * time.Second, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*ec2.VpcEndpoint); ok { + return output, err + } + + return nil, err +} diff --git a/aws/resource_aws_vpc_endpoint.go b/aws/resource_aws_vpc_endpoint.go index 8c4a0a08f408..2a2c17deb0f8 100644 --- a/aws/resource_aws_vpc_endpoint.go +++ b/aws/resource_aws_vpc_endpoint.go @@ -10,12 +10,14 @@ import ( "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -198,8 +200,10 @@ func resourceAwsVpcEndpointCreate(d *schema.ResourceData, meta interface{}) erro } } - if err := vpcEndpointWaitUntilAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { - return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %s", d.Id(), err) + _, err = waiter.VpcEndpointAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)) + + if err != nil { + return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %w", d.Id(), err) } return resourceAwsVpcEndpointRead(d, meta) @@ -210,25 +214,17 @@ func resourceAwsVpcEndpointRead(d *schema.ResourceData, meta interface{}) error defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - vpceRaw, state, err := vpcEndpointStateRefresh(conn, d.Id())() - if err != nil && state != "failed" { - return fmt.Errorf("error reading VPC Endpoint (%s): %s", d.Id(), err) - } + vpce, err := finder.VpcEndpointByID(conn, d.Id()) - terminalStates := map[string]bool{ - "deleted": true, - "deleting": true, - "failed": true, - "expired": true, - "rejected": true, - } - if _, ok := terminalStates[state]; ok { - log.Printf("[WARN] VPC Endpoint (%s) in state (%s), removing from state", d.Id(), state) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] VPC Endpoint (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - vpce := vpceRaw.(*ec2.VpcEndpoint) + if err != nil { + return fmt.Errorf("error reading VPC Endpoint (%s): %w", d.Id(), err) + } arn := arn.ARN{ Partition: meta.(*AWSClient).partition, @@ -355,8 +351,10 @@ func resourceAwsVpcEndpointUpdate(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("Error updating VPC Endpoint: %s", err) } - if err := vpcEndpointWaitUntilAvailable(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { - return err + _, err := waiter.VpcEndpointAvailable(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %w", d.Id(), err) } } @@ -395,7 +393,9 @@ func resourceAwsVpcEndpointDelete(d *schema.ResourceData, meta interface{}) erro } } - if err := vpcEndpointWaitUntilDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + _, err = waiter.VpcEndpointDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) + + if err != nil { return fmt.Errorf("error waiting for EC2 VPC Endpoint (%s) to delete: %w", d.Id(), err) } @@ -429,87 +429,15 @@ func vpcEndpointAccept(conn *ec2.EC2, vpceId, svcName string, timeout time.Durat return fmt.Errorf("error accepting VPC Endpoint (%s) connection: %s", vpceId, err) } - stateConf := &resource.StateChangeConf{ - Pending: []string{"pendingAcceptance", "pending"}, - Target: []string{"available"}, - Refresh: vpcEndpointStateRefresh(conn, vpceId), - Timeout: timeout, - Delay: 5 * time.Second, - MinTimeout: 5 * time.Second, - } + _, err = waiter.VpcEndpointAccepted(conn, vpceId, timeout) - _, err = stateConf.WaitForState() if err != nil { - return fmt.Errorf("error waiting for VPC Endpoint (%s) to be accepted: %s", vpceId, err) + return fmt.Errorf("error waiting for VPC Endpoint (%s) to be accepted: %w", vpceId, err) } return nil } -func vpcEndpointStateRefresh(conn *ec2.EC2, vpceId string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - log.Printf("[DEBUG] Reading VPC Endpoint: %s", vpceId) - resp, err := conn.DescribeVpcEndpoints(&ec2.DescribeVpcEndpointsInput{ - VpcEndpointIds: aws.StringSlice([]string{vpceId}), - }) - if err != nil { - if isAWSErr(err, "InvalidVpcEndpointId.NotFound", "") { - return "", "deleted", nil - } - - return nil, "", err - } - - n := len(resp.VpcEndpoints) - switch n { - case 0: - return "", "deleted", nil - - case 1: - vpce := resp.VpcEndpoints[0] - state := aws.StringValue(vpce.State) - // No use in retrying if the endpoint is in a failed state. - if state == "failed" { - return nil, state, errors.New("VPC Endpoint is in a failed state") - } - return vpce, state, nil - - default: - return nil, "", fmt.Errorf("Found %d VPC Endpoints for %s, expected 1", n, vpceId) - } - } -} - -func vpcEndpointWaitUntilAvailable(conn *ec2.EC2, vpceId string, timeout time.Duration) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{"pending"}, - Target: []string{"available", "pendingAcceptance"}, - Refresh: vpcEndpointStateRefresh(conn, vpceId), - Timeout: timeout, - Delay: 5 * time.Second, - MinTimeout: 5 * time.Second, - } - - _, err := stateConf.WaitForState() - - return err -} - -func vpcEndpointWaitUntilDeleted(conn *ec2.EC2, vpceID string, timeout time.Duration) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{"available", "pending", "deleting"}, - Target: []string{"deleted"}, - Refresh: vpcEndpointStateRefresh(conn, vpceID), - Timeout: timeout, - Delay: 5 * time.Second, - MinTimeout: 5 * time.Second, - } - - _, err := stateConf.WaitForState() - - return err -} - func setVpcEndpointCreateList(d *schema.ResourceData, key string, c *[]*string) { if v, ok := d.GetOk(key); ok { list := v.(*schema.Set) diff --git a/aws/resource_aws_vpc_endpoint_route_table_association.go b/aws/resource_aws_vpc_endpoint_route_table_association.go index 5c88d02be7b8..0e56c8669b2a 100644 --- a/aws/resource_aws_vpc_endpoint_route_table_association.go +++ b/aws/resource_aws_vpc_endpoint_route_table_association.go @@ -6,12 +6,9 @@ import ( "strings" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode" tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" @@ -47,21 +44,23 @@ func resourceAwsVpcEndpointRouteTableAssociationCreate(d *schema.ResourceData, m endpointId := d.Get("vpc_endpoint_id").(string) rtId := d.Get("route_table_id").(string) + // Human friendly ID for error messages since d.Id() is non-descriptive + id := fmt.Sprintf("%s/%s", endpointId, rtId) - _, err := findResourceVpcEndpoint(conn, endpointId) - if err != nil { - return err - } - - _, err = conn.ModifyVpcEndpoint(&ec2.ModifyVpcEndpointInput{ + input := &ec2.ModifyVpcEndpointInput{ VpcEndpointId: aws.String(endpointId), AddRouteTableIds: aws.StringSlice([]string{rtId}), - }) + } + + log.Printf("[DEBUG] Creating VPC Endpoint Route Table Association: %s", input) + + _, err := conn.ModifyVpcEndpoint(input) + if err != nil { - return fmt.Errorf("Error creating VPC Endpoint/Route Table association: %s", err.Error()) + return fmt.Errorf("error creating VPC Endpoint Route Table Association (%s): %w", id, err) } - d.SetId(vpcEndpointIdRouteTableIdHash(endpointId, rtId)) + d.SetId(tfec2.VpcEndpointRouteTableAssociationCreateID(endpointId, rtId)) return resourceAwsVpcEndpointRouteTableAssociationRead(d, meta) } @@ -74,35 +73,17 @@ func resourceAwsVpcEndpointRouteTableAssociationRead(d *schema.ResourceData, met // Human friendly ID for error messages since d.Id() is non-descriptive id := fmt.Sprintf("%s/%s", endpointId, rtId) - var routeTableID *string - - err := resource.Retry(waiter.PropagationTimeout, func() *resource.RetryError { - var err error - - routeTableID, err = finder.VpcEndpointRouteTableAssociation(conn, endpointId, rtId) - - if d.IsNewResource() && tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidVpcEndpointIdNotFound) { - return resource.RetryableError(err) - } + _, err := tfresource.RetryUntilFound(waiter.PropagationTimeout, d.IsNewResource(), func() (interface{}, error) { + err := finder.VpcEndpointRouteTableAssociationExists(conn, endpointId, rtId) if err != nil { - return resource.NonRetryableError(err) - } - - if d.IsNewResource() && routeTableID == nil { - return resource.RetryableError(&resource.NotFoundError{ - LastError: fmt.Errorf("VPC Endpoint Route Table Association (%s) not found", id), - }) + return nil, err } - return nil + return struct{}{}, nil }) - if tfresource.TimedOut(err) { - routeTableID, err = finder.VpcEndpointRouteTableAssociation(conn, endpointId, rtId) - } - - if d.IsNewResource() && tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidVpcEndpointIdNotFound) { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] VPC Endpoint Route Table Association (%s) not found, removing from state", id) d.SetId("") return nil @@ -112,16 +93,6 @@ func resourceAwsVpcEndpointRouteTableAssociationRead(d *schema.ResourceData, met return fmt.Errorf("error reading VPC Endpoint Route Table Association (%s): %w", id, err) } - if routeTableID == nil { - if d.IsNewResource() { - return fmt.Errorf("error reading VPC Endpoint Route Table Association (%s): not found after creation", id) - } - - log.Printf("[WARN] VPC Endpoint Route Table Association (%s) not found, removing from state", id) - d.SetId("") - return nil - } - return nil } @@ -130,27 +101,24 @@ func resourceAwsVpcEndpointRouteTableAssociationDelete(d *schema.ResourceData, m endpointId := d.Get("vpc_endpoint_id").(string) rtId := d.Get("route_table_id").(string) + // Human friendly ID for error messages since d.Id() is non-descriptive + id := fmt.Sprintf("%s/%s", endpointId, rtId) - _, err := conn.ModifyVpcEndpoint(&ec2.ModifyVpcEndpointInput{ + input := &ec2.ModifyVpcEndpointInput{ VpcEndpointId: aws.String(endpointId), RemoveRouteTableIds: aws.StringSlice([]string{rtId}), - }) - if err != nil { - ec2err, ok := err.(awserr.Error) - if !ok { - return fmt.Errorf("Error deleting VPC Endpoint/Route Table association: %s", err.Error()) - } + } - switch ec2err.Code() { - case "InvalidVpcEndpointId.NotFound": - fallthrough - case "InvalidRouteTableId.NotFound": - fallthrough - case "InvalidParameter": - log.Printf("[DEBUG] VPC Endpoint/Route Table association is already gone") - default: - return fmt.Errorf("Error deleting VPC Endpoint/Route Table association: %s", err.Error()) - } + log.Printf("[DEBUG] Deleting VPC Endpoint Route Table Association: %s", input) + + _, err := conn.ModifyVpcEndpoint(input) + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidVpcEndpointIdNotFound) || tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidRouteTableIdNotFound) || tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidParameter) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting VPC Endpoint Route Table Association (%s): %w", id, err) } return nil @@ -164,30 +132,11 @@ func resourceAwsVpcEndpointRouteTableAssociationImport(d *schema.ResourceData, m vpceId := parts[0] rtId := parts[1] - log.Printf("[DEBUG] Importing VPC Endpoint (%s) Route Table (%s) association", vpceId, rtId) + log.Printf("[DEBUG] Importing VPC Endpoint (%s) Route Table (%s) Association", vpceId, rtId) - d.SetId(vpcEndpointIdRouteTableIdHash(vpceId, rtId)) + d.SetId(tfec2.VpcEndpointRouteTableAssociationCreateID(vpceId, rtId)) d.Set("vpc_endpoint_id", vpceId) d.Set("route_table_id", rtId) return []*schema.ResourceData{d}, nil } - -func findResourceVpcEndpoint(conn *ec2.EC2, id string) (*ec2.VpcEndpoint, error) { - resp, err := conn.DescribeVpcEndpoints(&ec2.DescribeVpcEndpointsInput{ - VpcEndpointIds: aws.StringSlice([]string{id}), - }) - if err != nil { - return nil, err - } - - if resp.VpcEndpoints == nil || len(resp.VpcEndpoints) == 0 { - return nil, fmt.Errorf("No VPC Endpoints were found for %s", id) - } - - return resp.VpcEndpoints[0], nil -} - -func vpcEndpointIdRouteTableIdHash(endpointId, rtId string) string { - return fmt.Sprintf("a-%s%d", endpointId, hashcode.String(rtId)) -} diff --git a/aws/resource_aws_vpc_endpoint_route_table_association_test.go b/aws/resource_aws_vpc_endpoint_route_table_association_test.go index 4b5df4883659..fcbe71b0a7d1 100644 --- a/aws/resource_aws_vpc_endpoint_route_table_association_test.go +++ b/aws/resource_aws_vpc_endpoint_route_table_association_test.go @@ -4,18 +4,17 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestAccAWSVpcEndpointRouteTableAssociation_basic(t *testing.T) { - var vpce ec2.VpcEndpoint resourceName := "aws_vpc_endpoint_route_table_association.test" - rName := fmt.Sprintf("tf-testacc-vpce-%s", acctest.RandString(16)) + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -26,7 +25,7 @@ func TestAccAWSVpcEndpointRouteTableAssociation_basic(t *testing.T) { { Config: testAccVpcEndpointRouteTableAssociationConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckVpcEndpointRouteTableAssociationExists(resourceName, &vpce), + testAccCheckVpcEndpointRouteTableAssociationExists(resourceName), ), }, { @@ -39,6 +38,28 @@ func TestAccAWSVpcEndpointRouteTableAssociation_basic(t *testing.T) { }) } +func TestAccAWSVpcEndpointRouteTableAssociation_disappears(t *testing.T) { + resourceName := "aws_vpc_endpoint_route_table_association.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckVpcEndpointRouteTableAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVpcEndpointRouteTableAssociationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcEndpointRouteTableAssociationExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsVpcEndpointRouteTableAssociation(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckVpcEndpointRouteTableAssociationDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn @@ -47,33 +68,23 @@ func testAccCheckVpcEndpointRouteTableAssociationDestroy(s *terraform.State) err continue } - // Try to find the resource - resp, err := conn.DescribeVpcEndpoints(&ec2.DescribeVpcEndpointsInput{ - VpcEndpointIds: aws.StringSlice([]string{rs.Primary.Attributes["vpc_endpoint_id"]}), - }) - if err != nil { - // Verify the error is what we want - ec2err, ok := err.(awserr.Error) - if !ok { - return err - } - if ec2err.Code() != "InvalidVpcEndpointId.NotFound" { - return err - } - return nil + err := finder.VpcEndpointRouteTableAssociationExists(conn, rs.Primary.Attributes["vpc_endpoint_id"], rs.Primary.Attributes["route_table_id"]) + + if tfresource.NotFound(err) { + continue } - vpce := resp.VpcEndpoints[0] - if len(vpce.RouteTableIds) > 0 { - return fmt.Errorf( - "VPC endpoint %s has route tables", *vpce.VpcEndpointId) + if err != nil { + return err } + + return fmt.Errorf("VPC Endpoint Route Table Association %s still exists", rs.Primary.ID) } return nil } -func testAccCheckVpcEndpointRouteTableAssociationExists(n string, vpce *ec2.VpcEndpoint) resource.TestCheckFunc { +func testAccCheckVpcEndpointRouteTableAssociationExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -85,29 +96,8 @@ func testAccCheckVpcEndpointRouteTableAssociationExists(n string, vpce *ec2.VpcE } conn := testAccProvider.Meta().(*AWSClient).ec2conn - resp, err := conn.DescribeVpcEndpoints(&ec2.DescribeVpcEndpointsInput{ - VpcEndpointIds: aws.StringSlice([]string{rs.Primary.Attributes["vpc_endpoint_id"]}), - }) - if err != nil { - return err - } - if len(resp.VpcEndpoints) == 0 { - return fmt.Errorf("VPC Endpoint not found") - } - *vpce = *resp.VpcEndpoints[0] - - if len(vpce.RouteTableIds) == 0 { - return fmt.Errorf("No VPC Endpoint Route Table Associations") - } - - for _, rtId := range vpce.RouteTableIds { - if aws.StringValue(rtId) == rs.Primary.Attributes["route_table_id"] { - return nil - } - } - - return fmt.Errorf("VPC Endpoint Route Table Association not found") + return finder.VpcEndpointRouteTableAssociationExists(conn, rs.Primary.Attributes["vpc_endpoint_id"], rs.Primary.Attributes["route_table_id"]) } } @@ -138,6 +128,10 @@ data "aws_region" "current" {} resource "aws_vpc_endpoint" "test" { vpc_id = aws_vpc.test.id service_name = "com.amazonaws.${data.aws_region.current.name}.s3" + + tags = { + Name = %[1]q + } } resource "aws_route_table" "test" { diff --git a/aws/resource_aws_vpc_endpoint_subnet_association.go b/aws/resource_aws_vpc_endpoint_subnet_association.go index 477fe03ebc92..11b92a26c927 100644 --- a/aws/resource_aws_vpc_endpoint_subnet_association.go +++ b/aws/resource_aws_vpc_endpoint_subnet_association.go @@ -6,11 +6,14 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode" + tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsVpcEndpointSubnetAssociation() *schema.Resource { @@ -47,12 +50,16 @@ func resourceAwsVpcEndpointSubnetAssociationCreate(d *schema.ResourceData, meta endpointId := d.Get("vpc_endpoint_id").(string) snId := d.Get("subnet_id").(string) + // Human friendly ID for error messages since d.Id() is non-descriptive + id := fmt.Sprintf("%s/%s", endpointId, snId) - _, err := findResourceVpcEndpoint(conn, endpointId) - if err != nil { - return err + input := &ec2.ModifyVpcEndpointInput{ + VpcEndpointId: aws.String(endpointId), + AddSubnetIds: aws.StringSlice([]string{snId}), } + log.Printf("[DEBUG] Creating VPC Endpoint Subnet Association: %s", input) + // See https://github.com/hashicorp/terraform-provider-aws/issues/3382. // Prevent concurrent subnet association requests and delay between requests. mk := "vpc_endpoint_subnet_association_" + endpointId @@ -64,22 +71,23 @@ func resourceAwsVpcEndpointSubnetAssociationCreate(d *schema.ResourceData, meta Timeout: 3 * time.Minute, Target: []string{"ok"}, Refresh: func() (interface{}, string, error) { - res, err := conn.ModifyVpcEndpoint(&ec2.ModifyVpcEndpointInput{ - VpcEndpointId: aws.String(endpointId), - AddSubnetIds: aws.StringSlice([]string{snId}), - }) - return res, "ok", err + output, err := conn.ModifyVpcEndpoint(input) + + return output, "ok", err }, } - _, err = c.WaitForState() + _, err := c.WaitForState() + if err != nil { - return fmt.Errorf("Error creating Vpc Endpoint/Subnet association: %s", err) + return fmt.Errorf("error creating VPC Endpoint Subnet Association (%s): %w", id, err) } - d.SetId(vpcEndpointSubnetAssociationId(endpointId, snId)) + d.SetId(tfec2.VpcEndpointSubnetAssociationCreateID(endpointId, snId)) + + _, err = waiter.VpcEndpointAvailable(conn, endpointId, d.Timeout(schema.TimeoutCreate)) - if err := vpcEndpointWaitUntilAvailable(conn, endpointId, d.Timeout(schema.TimeoutCreate)); err != nil { - return err + if err != nil { + return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %w", endpointId, err) } return resourceAwsVpcEndpointSubnetAssociationRead(d, meta) @@ -90,31 +98,21 @@ func resourceAwsVpcEndpointSubnetAssociationRead(d *schema.ResourceData, meta in endpointId := d.Get("vpc_endpoint_id").(string) snId := d.Get("subnet_id").(string) + // Human friendly ID for error messages since d.Id() is non-descriptive + id := fmt.Sprintf("%s/%s", endpointId, snId) - vpce, err := findResourceVpcEndpoint(conn, endpointId) - if err != nil { - if isAWSErr(err, "InvalidVpcEndpointId.NotFound", "") { - log.Printf("[WARN] Vpc Endpoint (%s) not found, removing Vpc Endpoint/Subnet association (%s) from state", endpointId, d.Id()) - d.SetId("") - return nil - } - - return err - } + err := finder.VpcEndpointSubnetAssociationExists(conn, endpointId, snId) - found := false - for _, id := range vpce.SubnetIds { - if aws.StringValue(id) == snId { - found = true - break - } - } - if !found { - log.Printf("[WARN] Vpc Endpoint/Subnet association (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] VPC Endpoint Subnet Association (%s) not found, removing from state", id) d.SetId("") return nil } + if err != nil { + return fmt.Errorf("error reading VPC Endpoint Subnet Association (%s): %w", id, err) + } + return nil } @@ -123,34 +121,31 @@ func resourceAwsVpcEndpointSubnetAssociationDelete(d *schema.ResourceData, meta endpointId := d.Get("vpc_endpoint_id").(string) snId := d.Get("subnet_id").(string) + // Human friendly ID for error messages since d.Id() is non-descriptive + id := fmt.Sprintf("%s/%s", endpointId, snId) - _, err := conn.ModifyVpcEndpoint(&ec2.ModifyVpcEndpointInput{ + input := &ec2.ModifyVpcEndpointInput{ VpcEndpointId: aws.String(endpointId), RemoveSubnetIds: aws.StringSlice([]string{snId}), - }) + } + + log.Printf("[DEBUG] Deleting VPC Endpoint Subnet Association: %s", input) + + _, err := conn.ModifyVpcEndpoint(input) + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidVpcEndpointIdNotFound) || tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidSubnetIdNotFound) || tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidParameter) { + return nil + } + if err != nil { - ec2err, ok := err.(awserr.Error) - if !ok { - return fmt.Errorf("Error deleting Vpc Endpoint/Subnet association: %s", err) - } - - switch ec2err.Code() { - case "InvalidVpcEndpointId.NotFound": - fallthrough - case "InvalidParameter": - log.Printf("[DEBUG] Vpc Endpoint/Subnet association is already gone") - default: - return fmt.Errorf("Error deleting Vpc Endpoint/Subnet association: %s", err) - } + return fmt.Errorf("error deleting VPC Endpoint Subnet Association (%s): %w", id, err) } - if err := vpcEndpointWaitUntilAvailable(conn, endpointId, d.Timeout(schema.TimeoutDelete)); err != nil { - return err + _, err = waiter.VpcEndpointAvailable(conn, endpointId, d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %w", endpointId, err) } return nil } - -func vpcEndpointSubnetAssociationId(endpointId, snId string) string { - return fmt.Sprintf("a-%s%d", endpointId, hashcode.String(snId)) -} diff --git a/aws/resource_aws_vpc_endpoint_subnet_association_test.go b/aws/resource_aws_vpc_endpoint_subnet_association_test.go index 8e6f80d16742..758426bc2a3b 100644 --- a/aws/resource_aws_vpc_endpoint_subnet_association_test.go +++ b/aws/resource_aws_vpc_endpoint_subnet_association_test.go @@ -4,15 +4,18 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" + "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestAccAWSVpcEndpointSubnetAssociation_basic(t *testing.T) { var vpce ec2.VpcEndpoint + resourceName := "aws_vpc_endpoint_subnet_association.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -21,18 +24,44 @@ func TestAccAWSVpcEndpointSubnetAssociation_basic(t *testing.T) { CheckDestroy: testAccCheckVpcEndpointSubnetAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccVpcEndpointSubnetAssociationConfig_basic, + Config: testAccVpcEndpointSubnetAssociationConfigBasic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckVpcEndpointSubnetAssociationExists( - "aws_vpc_endpoint_subnet_association.a", &vpce), + testAccCheckVpcEndpointSubnetAssociationExists(resourceName, &vpce), ), }, }, }) } +func TestAccAWSVpcEndpointSubnetAssociation_disappears(t *testing.T) { + var vpce ec2.VpcEndpoint + resourceName := "aws_vpc_endpoint_subnet_association.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckVpcEndpointSubnetAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVpcEndpointSubnetAssociationConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcEndpointSubnetAssociationExists(resourceName, &vpce), + testAccCheckResourceDisappears(testAccProvider, resourceAwsVpcEndpointSubnetAssociation(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func TestAccAWSVpcEndpointSubnetAssociation_multiple(t *testing.T) { var vpce ec2.VpcEndpoint + resourceName0 := "aws_vpc_endpoint_subnet_association.test.0" + resourceName1 := "aws_vpc_endpoint_subnet_association.test.1" + resourceName2 := "aws_vpc_endpoint_subnet_association.test.2" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -41,14 +70,11 @@ func TestAccAWSVpcEndpointSubnetAssociation_multiple(t *testing.T) { CheckDestroy: testAccCheckVpcEndpointSubnetAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccVpcEndpointSubnetAssociationConfig_multiple, + Config: testAccVpcEndpointSubnetAssociationConfigMultiple(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckVpcEndpointSubnetAssociationExists( - "aws_vpc_endpoint_subnet_association.a.0", &vpce), - testAccCheckVpcEndpointSubnetAssociationExists( - "aws_vpc_endpoint_subnet_association.a.1", &vpce), - testAccCheckVpcEndpointSubnetAssociationExists( - "aws_vpc_endpoint_subnet_association.a.2", &vpce), + testAccCheckVpcEndpointSubnetAssociationExists(resourceName0, &vpce), + testAccCheckVpcEndpointSubnetAssociationExists(resourceName1, &vpce), + testAccCheckVpcEndpointSubnetAssociationExists(resourceName2, &vpce), ), }, }, @@ -63,27 +89,17 @@ func testAccCheckVpcEndpointSubnetAssociationDestroy(s *terraform.State) error { continue } - // Try to find the resource - resp, err := conn.DescribeVpcEndpoints(&ec2.DescribeVpcEndpointsInput{ - VpcEndpointIds: aws.StringSlice([]string{rs.Primary.Attributes["vpc_endpoint_id"]}), - }) - if err != nil { - // Verify the error is what we want - ec2err, ok := err.(awserr.Error) - if !ok { - return err - } - if ec2err.Code() != "InvalidVpcEndpointId.NotFound" { - return err - } - return nil + err := finder.VpcEndpointSubnetAssociationExists(conn, rs.Primary.Attributes["vpc_endpoint_id"], rs.Primary.Attributes["subnet_id"]) + + if tfresource.NotFound(err) { + continue } - vpce := resp.VpcEndpoints[0] - if len(vpce.SubnetIds) > 0 { - return fmt.Errorf( - "Vpc endpoint %s has subnets", *vpce.VpcEndpointId) + if err != nil { + return err } + + return fmt.Errorf("VPC Endpoint Subnet Association %s still exists", rs.Primary.ID) } return nil @@ -101,130 +117,90 @@ func testAccCheckVpcEndpointSubnetAssociationExists(n string, vpce *ec2.VpcEndpo } conn := testAccProvider.Meta().(*AWSClient).ec2conn - resp, err := conn.DescribeVpcEndpoints(&ec2.DescribeVpcEndpointsInput{ - VpcEndpointIds: aws.StringSlice([]string{rs.Primary.Attributes["vpc_endpoint_id"]}), - }) + + out, err := finder.VpcEndpointByID(conn, rs.Primary.Attributes["vpc_endpoint_id"]) + if err != nil { return err } - if len(resp.VpcEndpoints) == 0 { - return fmt.Errorf("Vpc endpoint not found") - } - *vpce = *resp.VpcEndpoints[0] + err = finder.VpcEndpointSubnetAssociationExists(conn, rs.Primary.Attributes["vpc_endpoint_id"], rs.Primary.Attributes["subnet_id"]) - if len(vpce.SubnetIds) == 0 { - return fmt.Errorf("no subnet associations") + if err != nil { + return err } - for _, id := range vpce.SubnetIds { - if aws.StringValue(id) == rs.Primary.Attributes["subnet_id"] { - return nil - } - } + *vpce = *out - return fmt.Errorf("subnet association not found") + return nil } } -const testAccVpcEndpointSubnetAssociationConfig_basic = ` -resource "aws_vpc" "foo" { +func testAccVpcEndpointSubnetAssociationConfigBase(rName string) string { + return composeConfig( + testAccAvailableAZsNoOptInConfig(), + fmt.Sprintf(` +resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" tags = { - Name = "terraform-testacc-vpc-endpoint-subnet-association" + Name = %[1]q } } -data "aws_security_group" "default" { - vpc_id = aws_vpc.foo.id +data "aws_security_group" "test" { + vpc_id = aws_vpc.test.id name = "default" } data "aws_region" "current" {} -data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } -} - -resource "aws_vpc_endpoint" "ec2" { - vpc_id = aws_vpc.foo.id +resource "aws_vpc_endpoint" "test" { + vpc_id = aws_vpc.test.id vpc_endpoint_type = "Interface" service_name = "com.amazonaws.${data.aws_region.current.name}.ec2" - security_group_ids = [data.aws_security_group.default.id] + security_group_ids = [data.aws_security_group.test.id] private_dns_enabled = false -} - -resource "aws_subnet" "sn" { - vpc_id = aws_vpc.foo.id - availability_zone = data.aws_availability_zones.available.names[0] - cidr_block = "10.0.0.0/17" tags = { - Name = "tf-acc-vpc-endpoint-subnet-association" + Name = %[1]q } } -resource "aws_vpc_endpoint_subnet_association" "a" { - vpc_endpoint_id = aws_vpc_endpoint.ec2.id - subnet_id = aws_subnet.sn.id -} -` +resource "aws_subnet" "test" { + count = 3 -const testAccVpcEndpointSubnetAssociationConfig_multiple = ` -resource "aws_vpc" "foo" { - cidr_block = "10.0.0.0/16" + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 2, count.index) tags = { - Name = "terraform-testacc-vpc-endpoint-subnet-association" + Name = %[1]q } } - -data "aws_security_group" "default" { - vpc_id = aws_vpc.foo.id - name = "default" +`, rName)) } -data "aws_region" "current" {} - -data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } +func testAccVpcEndpointSubnetAssociationConfigBasic(rName string) string { + return composeConfig( + testAccVpcEndpointSubnetAssociationConfigBase(rName), + ` +resource "aws_vpc_endpoint_subnet_association" "test" { + vpc_endpoint_id = aws_vpc_endpoint.test.id + subnet_id = aws_subnet.test[0].id } - -resource "aws_vpc_endpoint" "ec2" { - vpc_id = aws_vpc.foo.id - vpc_endpoint_type = "Interface" - service_name = "com.amazonaws.${data.aws_region.current.name}.ec2" - security_group_ids = [data.aws_security_group.default.id] - private_dns_enabled = false +`) } -resource "aws_subnet" "sn" { +func testAccVpcEndpointSubnetAssociationConfigMultiple(rName string) string { + return composeConfig( + testAccVpcEndpointSubnetAssociationConfigBase(rName), + ` +resource "aws_vpc_endpoint_subnet_association" "test" { count = 3 - vpc_id = aws_vpc.foo.id - availability_zone = data.aws_availability_zones.available.names[count.index] - cidr_block = cidrsubnet(aws_vpc.foo.cidr_block, 2, count.index) - - tags = { - Name = format("tf-acc-vpc-endpoint-subnet-association-%d", count.index + 1) - } + vpc_endpoint_id = aws_vpc_endpoint.test.id + subnet_id = aws_subnet.test[count.index].id } - -resource "aws_vpc_endpoint_subnet_association" "a" { - count = 3 - - vpc_endpoint_id = aws_vpc_endpoint.ec2.id - subnet_id = aws_subnet.sn.*.id[count.index] +`) } -` diff --git a/aws/resource_aws_vpc_endpoint_test.go b/aws/resource_aws_vpc_endpoint_test.go index f90a78c087ca..55883b2fc4ec 100644 --- a/aws/resource_aws_vpc_endpoint_test.go +++ b/aws/resource_aws_vpc_endpoint_test.go @@ -9,12 +9,13 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/go-multierror" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -554,23 +555,15 @@ func testAccCheckVpcEndpointDestroy(s *terraform.State) error { continue } - // Try to find the VPC - input := &ec2.DescribeVpcEndpointsInput{ - VpcEndpointIds: []*string{aws.String(rs.Primary.ID)}, + _, err := finder.VpcEndpointByID(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue } - resp, err := conn.DescribeVpcEndpoints(input) + if err != nil { - // Verify the error is what we want - if ae, ok := err.(awserr.Error); ok && ae.Code() == "InvalidVpcEndpointId.NotFound" { - continue - } return err } - if len(resp.VpcEndpoints) > 0 && aws.StringValue(resp.VpcEndpoints[0].State) != "deleted" { - return fmt.Errorf("VPC Endpoints still exist.") - } - - return err } return nil @@ -588,18 +581,14 @@ func testAccCheckVpcEndpointExists(n string, endpoint *ec2.VpcEndpoint) resource } conn := testAccProvider.Meta().(*AWSClient).ec2conn - input := &ec2.DescribeVpcEndpointsInput{ - VpcEndpointIds: []*string{aws.String(rs.Primary.ID)}, - } - resp, err := conn.DescribeVpcEndpoints(input) + + out, err := finder.VpcEndpointByID(conn, rs.Primary.ID) + if err != nil { return err } - if len(resp.VpcEndpoints) == 0 { - return fmt.Errorf("VPC Endpoint not found") - } - *endpoint = *resp.VpcEndpoints[0] + *endpoint = *out return nil } @@ -793,21 +782,12 @@ resource "aws_vpc" "test" { } } -data "aws_security_group" "test" { - vpc_id = aws_vpc.test.id - name = "default" -} - data "aws_region" "current" {} resource "aws_vpc_endpoint" "test" { vpc_id = aws_vpc.test.id service_name = "com.amazonaws.${data.aws_region.current.name}.ec2" vpc_endpoint_type = "Interface" - - security_group_ids = [ - data.aws_security_group.test.id, - ] } `, rName) } @@ -840,8 +820,8 @@ POLICY `, rName, policy) } -func testAccVpcEndpointConfig_interfaceWithSubnet(rName string) string { - return fmt.Sprintf(` +func testAccVpcEndpointConfig_vpcBase(rName string) string { + return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(` resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" enable_dns_support = true @@ -854,61 +834,34 @@ resource "aws_vpc" "test" { data "aws_region" "current" {} -data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } -} - -resource "aws_subnet" "test1" { - vpc_id = aws_vpc.test.id - cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 2, 0) - availability_zone = data.aws_availability_zones.available.names[0] - - tags = { - Name = %[1]q - } -} +resource "aws_subnet" "test" { + count = 3 -resource "aws_subnet" "test2" { vpc_id = aws_vpc.test.id - cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 2, 1) - availability_zone = data.aws_availability_zones.available.names[1] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 2, count.index) + availability_zone = data.aws_availability_zones.available.names[count.index] tags = { Name = %[1]q } } -resource "aws_subnet" "test3" { - vpc_id = aws_vpc.test.id - cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 2, 2) - availability_zone = data.aws_availability_zones.available.names[2] - - tags = { - Name = %[1]q - } -} +resource "aws_security_group" "test" { + count = 2 -resource "aws_security_group" "test1" { vpc_id = aws_vpc.test.id tags = { Name = %[1]q } } - -resource "aws_security_group" "test2" { - vpc_id = aws_vpc.test.id - - tags = { - Name = %[1]q - } +`, rName)) } +func testAccVpcEndpointConfig_interfaceWithSubnet(rName string) string { + return composeConfig( + testAccVpcEndpointConfig_vpcBase(rName), + fmt.Sprintf(` resource "aws_vpc_endpoint" "test" { vpc_id = aws_vpc.test.id service_name = "com.amazonaws.${data.aws_region.current.name}.ec2" @@ -916,90 +869,25 @@ resource "aws_vpc_endpoint" "test" { private_dns_enabled = false subnet_ids = [ - aws_subnet.test1.id, + aws_subnet.test[0].id, ] security_group_ids = [ - aws_security_group.test1.id, - aws_security_group.test2.id, + aws_security_group.test[0].id, + aws_security_group.test[1].id, ] tags = { Name = %[1]q } } -`, rName) +`, rName)) } func testAccVpcEndpointConfig_interfaceWithSubnetModified(rName string) string { - return fmt.Sprintf(` -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" - enable_dns_support = true - enable_dns_hostnames = true - - tags = { - Name = %[1]q - } -} - -data "aws_region" "current" {} - -data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } -} - -resource "aws_subnet" "test1" { - vpc_id = aws_vpc.test.id - cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 2, 0) - availability_zone = data.aws_availability_zones.available.names[0] - - tags = { - Name = %[1]q - } -} - -resource "aws_subnet" "test2" { - vpc_id = aws_vpc.test.id - cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 2, 1) - availability_zone = data.aws_availability_zones.available.names[1] - - tags = { - Name = %[1]q - } -} - -resource "aws_subnet" "test3" { - vpc_id = aws_vpc.test.id - cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 2, 2) - availability_zone = data.aws_availability_zones.available.names[2] - - tags = { - Name = %[1]q - } -} - -resource "aws_security_group" "test1" { - vpc_id = aws_vpc.test.id - - tags = { - Name = %[1]q - } -} - -resource "aws_security_group" "test2" { - vpc_id = aws_vpc.test.id - - tags = { - Name = %[1]q - } -} - + return composeConfig( + testAccVpcEndpointConfig_vpcBase(rName), + fmt.Sprintf(` resource "aws_vpc_endpoint" "test" { vpc_id = aws_vpc.test.id service_name = "com.amazonaws.${data.aws_region.current.name}.ec2" @@ -1007,38 +895,32 @@ resource "aws_vpc_endpoint" "test" { private_dns_enabled = true subnet_ids = [ - aws_subnet.test1.id, - aws_subnet.test2.id, - aws_subnet.test3.id, + aws_subnet.test[2].id, + aws_subnet.test[1].id, + aws_subnet.test[0].id, ] security_group_ids = [ - aws_security_group.test1.id, + aws_security_group.test[1].id, ] tags = { Name = %[1]q } } -`, rName) +`, rName)) } func testAccVpcEndpointConfig_interfaceNonAWSService(rName string, autoAccept bool) string { - return fmt.Sprintf(` -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" - - tags = { - Name = %[1]q - } -} - + return composeConfig( + testAccVpcEndpointConfig_vpcBase(rName), + fmt.Sprintf(` resource "aws_lb" "test" { name = %[1]q subnets = [ - aws_subnet.test1.id, - aws_subnet.test2.id, + aws_subnet.test[0].id, + aws_subnet.test[1].id, ] load_balancer_type = "network" @@ -1051,47 +933,12 @@ resource "aws_lb" "test" { } } -data "aws_region" "current" {} - -data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } -} - -resource "aws_subnet" "test1" { - vpc_id = aws_vpc.test.id - cidr_block = "10.0.1.0/24" - availability_zone = data.aws_availability_zones.available.names[0] - - tags = { - Name = %[1]q - } -} - -resource "aws_subnet" "test2" { - vpc_id = aws_vpc.test.id - cidr_block = "10.0.2.0/24" - availability_zone = data.aws_availability_zones.available.names[1] - - tags = { - Name = %[1]q - } -} - resource "aws_vpc_endpoint_service" "test" { acceptance_required = true network_load_balancer_arns = [ aws_lb.test.id, ] -} - -resource "aws_security_group" "test" { - vpc_id = aws_vpc.test.id tags = { Name = %[1]q @@ -1106,14 +953,14 @@ resource "aws_vpc_endpoint" "test" { auto_accept = %[2]t security_group_ids = [ - aws_security_group.test.id, + aws_security_group.test[0].id, ] tags = { Name = %[1]q } } -`, rName, autoAccept) +`, rName, autoAccept)) } func testAccVpcEndpointConfigTags1(rName, tagKey1, tagValue1 string) string { @@ -1173,7 +1020,7 @@ resource "aws_vpc" "test" { cidr_block = "10.10.10.0/25" tags = { - Name = "tf-acc-test-load-balancer" + Name = %[1]q } } @@ -1183,7 +1030,7 @@ resource "aws_subnet" "test" { vpc_id = aws_vpc.test.id tags = { - Name = "tf-acc-test-load-balancer" + Name = %[1]q } } @@ -1194,12 +1041,20 @@ resource "aws_lb" "test" { subnet_mapping { subnet_id = aws_subnet.test.id } + + tags = { + Name = %[1]q + } } resource "aws_vpc_endpoint_service" "test" { acceptance_required = false allowed_principals = [data.aws_caller_identity.current.arn] gateway_load_balancer_arns = [aws_lb.test.arn] + + tags = { + Name = %[1]q + } } resource "aws_vpc_endpoint" "test" { @@ -1207,6 +1062,10 @@ resource "aws_vpc_endpoint" "test" { subnet_ids = [aws_subnet.test.id] vpc_endpoint_type = aws_vpc_endpoint_service.test.service_type vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } } `, rName)) } From 085da7e0a507610aa52c67caacf8e57996ae1a97 Mon Sep 17 00:00:00 2001 From: Maciej Rostanski Date: Tue, 15 Jun 2021 17:20:35 +0200 Subject: [PATCH 0457/1208] EKS node group scaling_config.min_size can be 0 --- aws/resource_aws_eks_node_group.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_eks_node_group.go b/aws/resource_aws_eks_node_group.go index 17001047f7a3..b772e406082c 100644 --- a/aws/resource_aws_eks_node_group.go +++ b/aws/resource_aws_eks_node_group.go @@ -192,7 +192,7 @@ func resourceAwsEksNodeGroup() *schema.Resource { "desired_size": { Type: schema.TypeInt, Required: true, - ValidateFunc: validation.IntAtLeast(1), + ValidateFunc: validation.IntAtLeast(0), }, "max_size": { Type: schema.TypeInt, @@ -202,7 +202,7 @@ func resourceAwsEksNodeGroup() *schema.Resource { "min_size": { Type: schema.TypeInt, Required: true, - ValidateFunc: validation.IntAtLeast(1), + ValidateFunc: validation.IntAtLeast(0), }, }, }, From df29eba274596f085067023f129e99acfd47c3bd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 12:13:36 -0400 Subject: [PATCH 0458/1208] r/aws_vpc_endpoint_route_table_association: Use waiters. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSVpcEndpointRouteTableAssociation_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSVpcEndpointRouteTableAssociation_ -timeout 180m === RUN TestAccAWSVpcEndpointRouteTableAssociation_basic === PAUSE TestAccAWSVpcEndpointRouteTableAssociation_basic === RUN TestAccAWSVpcEndpointRouteTableAssociation_disappears === PAUSE TestAccAWSVpcEndpointRouteTableAssociation_disappears === CONT TestAccAWSVpcEndpointRouteTableAssociation_basic === CONT TestAccAWSVpcEndpointRouteTableAssociation_disappears --- PASS: TestAccAWSVpcEndpointRouteTableAssociation_disappears (39.13s) --- PASS: TestAccAWSVpcEndpointRouteTableAssociation_basic (41.03s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 44.118s --- aws/internal/service/ec2/waiter/status.go | 20 ++++++ aws/internal/service/ec2/waiter/waiter.go | 28 ++++++++ ...ws_vpc_endpoint_route_table_association.go | 70 ++++++++++--------- ...rce_aws_vpc_endpoint_subnet_association.go | 47 ++++++------- 4 files changed, 107 insertions(+), 58 deletions(-) diff --git a/aws/internal/service/ec2/waiter/status.go b/aws/internal/service/ec2/waiter/status.go index 3fa0a512c85c..68265ef0f402 100644 --- a/aws/internal/service/ec2/waiter/status.go +++ b/aws/internal/service/ec2/waiter/status.go @@ -520,3 +520,23 @@ func VpcEndpointState(conn *ec2.EC2, id string) resource.StateRefreshFunc { return vpcEndpoint, aws.StringValue(vpcEndpoint.State), nil } } + +const ( + VpcEndpointRouteTableAssociationStatusReady = "ready" +) + +func VpcEndpointRouteTableAssociationStatus(conn *ec2.EC2, vpcEndpointID, routeTableID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + err := finder.VpcEndpointRouteTableAssociationExists(conn, vpcEndpointID, routeTableID) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return "", VpcEndpointRouteTableAssociationStatusReady, nil + } +} diff --git a/aws/internal/service/ec2/waiter/waiter.go b/aws/internal/service/ec2/waiter/waiter.go index 6a55619627a4..73ff47bfbd78 100644 --- a/aws/internal/service/ec2/waiter/waiter.go +++ b/aws/internal/service/ec2/waiter/waiter.go @@ -751,3 +751,31 @@ func VpcEndpointDeleted(conn *ec2.EC2, vpcEndpointID string, timeout time.Durati return nil, err } + +func VpcEndpointRouteTableAssociationDeleted(conn *ec2.EC2, vpcEndpointID, routeTableID string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{VpcEndpointRouteTableAssociationStatusReady}, + Target: []string{}, + Refresh: VpcEndpointRouteTableAssociationStatus(conn, vpcEndpointID, routeTableID), + Timeout: PropagationTimeout, + ContinuousTargetOccurence: 2, + } + + _, err := stateConf.WaitForState() + + return err +} + +func VpcEndpointRouteTableAssociationReady(conn *ec2.EC2, vpcEndpointID, routeTableID string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{}, + Target: []string{VpcEndpointRouteTableAssociationStatusReady}, + Refresh: VpcEndpointRouteTableAssociationStatus(conn, vpcEndpointID, routeTableID), + Timeout: PropagationTimeout, + ContinuousTargetOccurence: 2, + } + + _, err := stateConf.WaitForState() + + return err +} diff --git a/aws/resource_aws_vpc_endpoint_route_table_association.go b/aws/resource_aws_vpc_endpoint_route_table_association.go index 0e56c8669b2a..0ef447a13e36 100644 --- a/aws/resource_aws_vpc_endpoint_route_table_association.go +++ b/aws/resource_aws_vpc_endpoint_route_table_association.go @@ -25,12 +25,12 @@ func resourceAwsVpcEndpointRouteTableAssociation() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "vpc_endpoint_id": { + "route_table_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "route_table_id": { + "vpc_endpoint_id": { Type: schema.TypeString, Required: true, ForceNew: true, @@ -42,25 +42,30 @@ func resourceAwsVpcEndpointRouteTableAssociation() *schema.Resource { func resourceAwsVpcEndpointRouteTableAssociationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - endpointId := d.Get("vpc_endpoint_id").(string) - rtId := d.Get("route_table_id").(string) + endpointID := d.Get("vpc_endpoint_id").(string) + routeTableID := d.Get("route_table_id").(string) // Human friendly ID for error messages since d.Id() is non-descriptive - id := fmt.Sprintf("%s/%s", endpointId, rtId) + id := fmt.Sprintf("%s/%s", endpointID, routeTableID) input := &ec2.ModifyVpcEndpointInput{ - VpcEndpointId: aws.String(endpointId), - AddRouteTableIds: aws.StringSlice([]string{rtId}), + VpcEndpointId: aws.String(endpointID), + AddRouteTableIds: aws.StringSlice([]string{routeTableID}), } log.Printf("[DEBUG] Creating VPC Endpoint Route Table Association: %s", input) - _, err := conn.ModifyVpcEndpoint(input) if err != nil { return fmt.Errorf("error creating VPC Endpoint Route Table Association (%s): %w", id, err) } - d.SetId(tfec2.VpcEndpointRouteTableAssociationCreateID(endpointId, rtId)) + d.SetId(tfec2.VpcEndpointRouteTableAssociationCreateID(endpointID, routeTableID)) + + err = waiter.VpcEndpointRouteTableAssociationReady(conn, endpointID, routeTableID) + + if err != nil { + return fmt.Errorf("error waiting for VPC Endpoint Route Table Association (%s) to become available: %w", id, err) + } return resourceAwsVpcEndpointRouteTableAssociationRead(d, meta) } @@ -68,20 +73,12 @@ func resourceAwsVpcEndpointRouteTableAssociationCreate(d *schema.ResourceData, m func resourceAwsVpcEndpointRouteTableAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - endpointId := d.Get("vpc_endpoint_id").(string) - rtId := d.Get("route_table_id").(string) + endpointID := d.Get("vpc_endpoint_id").(string) + routeTableID := d.Get("route_table_id").(string) // Human friendly ID for error messages since d.Id() is non-descriptive - id := fmt.Sprintf("%s/%s", endpointId, rtId) - - _, err := tfresource.RetryUntilFound(waiter.PropagationTimeout, d.IsNewResource(), func() (interface{}, error) { - err := finder.VpcEndpointRouteTableAssociationExists(conn, endpointId, rtId) + id := fmt.Sprintf("%s/%s", endpointID, routeTableID) - if err != nil { - return nil, err - } - - return struct{}{}, nil - }) + err := finder.VpcEndpointRouteTableAssociationExists(conn, endpointID, routeTableID) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] VPC Endpoint Route Table Association (%s) not found, removing from state", id) @@ -99,18 +96,17 @@ func resourceAwsVpcEndpointRouteTableAssociationRead(d *schema.ResourceData, met func resourceAwsVpcEndpointRouteTableAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - endpointId := d.Get("vpc_endpoint_id").(string) - rtId := d.Get("route_table_id").(string) + endpointID := d.Get("vpc_endpoint_id").(string) + routeTableID := d.Get("route_table_id").(string) // Human friendly ID for error messages since d.Id() is non-descriptive - id := fmt.Sprintf("%s/%s", endpointId, rtId) + id := fmt.Sprintf("%s/%s", endpointID, routeTableID) input := &ec2.ModifyVpcEndpointInput{ - VpcEndpointId: aws.String(endpointId), - RemoveRouteTableIds: aws.StringSlice([]string{rtId}), + VpcEndpointId: aws.String(endpointID), + RemoveRouteTableIds: aws.StringSlice([]string{routeTableID}), } - log.Printf("[DEBUG] Deleting VPC Endpoint Route Table Association: %s", input) - + log.Printf("[DEBUG] Deleting VPC Endpoint Route Table Association: %s", id) _, err := conn.ModifyVpcEndpoint(input) if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidVpcEndpointIdNotFound) || tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidRouteTableIdNotFound) || tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidParameter) { @@ -121,6 +117,12 @@ func resourceAwsVpcEndpointRouteTableAssociationDelete(d *schema.ResourceData, m return fmt.Errorf("error deleting VPC Endpoint Route Table Association (%s): %w", id, err) } + err = waiter.VpcEndpointRouteTableAssociationDeleted(conn, endpointID, routeTableID) + + if err != nil { + return fmt.Errorf("error waiting for VPC Endpoint Route Table Association (%s) to delete: %w", id, err) + } + return nil } @@ -130,13 +132,13 @@ func resourceAwsVpcEndpointRouteTableAssociationImport(d *schema.ResourceData, m return nil, fmt.Errorf("Wrong format of resource: %s. Please follow 'vpc-endpoint-id/route-table-id'", d.Id()) } - vpceId := parts[0] - rtId := parts[1] - log.Printf("[DEBUG] Importing VPC Endpoint (%s) Route Table (%s) Association", vpceId, rtId) + endpointID := parts[0] + routeTableID := parts[1] + log.Printf("[DEBUG] Importing VPC Endpoint (%s) Route Table (%s) Association", endpointID, routeTableID) - d.SetId(tfec2.VpcEndpointRouteTableAssociationCreateID(vpceId, rtId)) - d.Set("vpc_endpoint_id", vpceId) - d.Set("route_table_id", rtId) + d.SetId(tfec2.VpcEndpointRouteTableAssociationCreateID(endpointID, routeTableID)) + d.Set("vpc_endpoint_id", endpointID) + d.Set("route_table_id", routeTableID) return []*schema.ResourceData{d}, nil } diff --git a/aws/resource_aws_vpc_endpoint_subnet_association.go b/aws/resource_aws_vpc_endpoint_subnet_association.go index 11b92a26c927..9a2ada6ae598 100644 --- a/aws/resource_aws_vpc_endpoint_subnet_association.go +++ b/aws/resource_aws_vpc_endpoint_subnet_association.go @@ -26,12 +26,12 @@ func resourceAwsVpcEndpointSubnetAssociation() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "vpc_endpoint_id": { + "subnet_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "subnet_id": { + "vpc_endpoint_id": { Type: schema.TypeString, Required: true, ForceNew: true, @@ -48,21 +48,21 @@ func resourceAwsVpcEndpointSubnetAssociation() *schema.Resource { func resourceAwsVpcEndpointSubnetAssociationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - endpointId := d.Get("vpc_endpoint_id").(string) - snId := d.Get("subnet_id").(string) + endpointID := d.Get("vpc_endpoint_id").(string) + subnetID := d.Get("subnet_id").(string) // Human friendly ID for error messages since d.Id() is non-descriptive - id := fmt.Sprintf("%s/%s", endpointId, snId) + id := fmt.Sprintf("%s/%s", endpointID, subnetID) input := &ec2.ModifyVpcEndpointInput{ - VpcEndpointId: aws.String(endpointId), - AddSubnetIds: aws.StringSlice([]string{snId}), + VpcEndpointId: aws.String(endpointID), + AddSubnetIds: aws.StringSlice([]string{subnetID}), } log.Printf("[DEBUG] Creating VPC Endpoint Subnet Association: %s", input) // See https://github.com/hashicorp/terraform-provider-aws/issues/3382. // Prevent concurrent subnet association requests and delay between requests. - mk := "vpc_endpoint_subnet_association_" + endpointId + mk := "vpc_endpoint_subnet_association_" + endpointID awsMutexKV.Lock(mk) defer awsMutexKV.Unlock(mk) @@ -82,12 +82,12 @@ func resourceAwsVpcEndpointSubnetAssociationCreate(d *schema.ResourceData, meta return fmt.Errorf("error creating VPC Endpoint Subnet Association (%s): %w", id, err) } - d.SetId(tfec2.VpcEndpointSubnetAssociationCreateID(endpointId, snId)) + d.SetId(tfec2.VpcEndpointSubnetAssociationCreateID(endpointID, subnetID)) - _, err = waiter.VpcEndpointAvailable(conn, endpointId, d.Timeout(schema.TimeoutCreate)) + _, err = waiter.VpcEndpointAvailable(conn, endpointID, d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %w", endpointId, err) + return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %w", endpointID, err) } return resourceAwsVpcEndpointSubnetAssociationRead(d, meta) @@ -96,12 +96,12 @@ func resourceAwsVpcEndpointSubnetAssociationCreate(d *schema.ResourceData, meta func resourceAwsVpcEndpointSubnetAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - endpointId := d.Get("vpc_endpoint_id").(string) - snId := d.Get("subnet_id").(string) + endpointID := d.Get("vpc_endpoint_id").(string) + subnetID := d.Get("subnet_id").(string) // Human friendly ID for error messages since d.Id() is non-descriptive - id := fmt.Sprintf("%s/%s", endpointId, snId) + id := fmt.Sprintf("%s/%s", endpointID, subnetID) - err := finder.VpcEndpointSubnetAssociationExists(conn, endpointId, snId) + err := finder.VpcEndpointSubnetAssociationExists(conn, endpointID, subnetID) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] VPC Endpoint Subnet Association (%s) not found, removing from state", id) @@ -119,18 +119,17 @@ func resourceAwsVpcEndpointSubnetAssociationRead(d *schema.ResourceData, meta in func resourceAwsVpcEndpointSubnetAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - endpointId := d.Get("vpc_endpoint_id").(string) - snId := d.Get("subnet_id").(string) + endpointID := d.Get("vpc_endpoint_id").(string) + subnetID := d.Get("subnet_id").(string) // Human friendly ID for error messages since d.Id() is non-descriptive - id := fmt.Sprintf("%s/%s", endpointId, snId) + id := fmt.Sprintf("%s/%s", endpointID, subnetID) input := &ec2.ModifyVpcEndpointInput{ - VpcEndpointId: aws.String(endpointId), - RemoveSubnetIds: aws.StringSlice([]string{snId}), + VpcEndpointId: aws.String(endpointID), + RemoveSubnetIds: aws.StringSlice([]string{subnetID}), } - log.Printf("[DEBUG] Deleting VPC Endpoint Subnet Association: %s", input) - + log.Printf("[DEBUG] Deleting VPC Endpoint Subnet Association: %s", id) _, err := conn.ModifyVpcEndpoint(input) if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidVpcEndpointIdNotFound) || tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidSubnetIdNotFound) || tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidParameter) { @@ -141,10 +140,10 @@ func resourceAwsVpcEndpointSubnetAssociationDelete(d *schema.ResourceData, meta return fmt.Errorf("error deleting VPC Endpoint Subnet Association (%s): %w", id, err) } - _, err = waiter.VpcEndpointAvailable(conn, endpointId, d.Timeout(schema.TimeoutDelete)) + _, err = waiter.VpcEndpointAvailable(conn, endpointID, d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %w", endpointId, err) + return fmt.Errorf("error waiting for VPC Endpoint (%s) to become available: %w", endpointID, err) } return nil From b6e6fb94e53038aeeafe7dc99a67e1c0d36c5ba2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 12:36:12 -0400 Subject: [PATCH 0459/1208] r/aws_vpc_endpoint: Fix 'TestAccAWSVpcEndpoint_interfaceBasic'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSVpcEndpoint_interfaceBasic' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSVpcEndpoint_interfaceBasic -timeout 180m === RUN TestAccAWSVpcEndpoint_interfaceBasic === PAUSE TestAccAWSVpcEndpoint_interfaceBasic === CONT TestAccAWSVpcEndpoint_interfaceBasic --- PASS: TestAccAWSVpcEndpoint_interfaceBasic (141.62s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 145.881s --- aws/resource_aws_vpc_endpoint_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/aws/resource_aws_vpc_endpoint_test.go b/aws/resource_aws_vpc_endpoint_test.go index 55883b2fc4ec..40c22ec21d8e 100644 --- a/aws/resource_aws_vpc_endpoint_test.go +++ b/aws/resource_aws_vpc_endpoint_test.go @@ -782,12 +782,21 @@ resource "aws_vpc" "test" { } } +data "aws_security_group" "test" { + vpc_id = aws_vpc.test.id + name = "default" +} + data "aws_region" "current" {} resource "aws_vpc_endpoint" "test" { vpc_id = aws_vpc.test.id service_name = "com.amazonaws.${data.aws_region.current.name}.ec2" vpc_endpoint_type = "Interface" + + security_group_ids = [ + data.aws_security_group.test.id, + ] } `, rName) } From f2af9b4defb216f413b1b65e88e2d4ad180b4b07 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 15:39:35 -0400 Subject: [PATCH 0460/1208] Don't semgrep for 'tfresource.*' inside the 'tfresource' package. --- .semgrep.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.semgrep.yml b/.semgrep.yml index 7bc84a369add..c9a41d64c4a4 100644 --- a/.semgrep.yml +++ b/.semgrep.yml @@ -356,6 +356,7 @@ rules: paths: exclude: - "*_test.go" + - aws/internal/tfresource/*.go include: - aws/ patterns: From c41c7840ea717df084bafcf7de89857e9f1ead9d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 15:40:10 -0400 Subject: [PATCH 0461/1208] Fix awsproviderlint misspell errors. --- aws/resource_aws_main_route_table_association.go | 2 +- aws/resource_aws_route_table_association.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_main_route_table_association.go b/aws/resource_aws_main_route_table_association.go index e8a3b955fd75..b97508d2eef5 100644 --- a/aws/resource_aws_main_route_table_association.go +++ b/aws/resource_aws_main_route_table_association.go @@ -113,7 +113,7 @@ func resourceAwsMainRouteTableAssociationUpdate(d *schema.ResourceData, meta int } // This whole thing with the resource ID being changed on update seems unsustainable. - // Keeping it here for backwards compatibilty... + // Keeping it here for backwards compatibility... d.SetId(aws.StringValue(output.NewAssociationId)) log.Printf("[DEBUG] Waiting for Main Route Table Association (%s) update", d.Id()) diff --git a/aws/resource_aws_route_table_association.go b/aws/resource_aws_route_table_association.go index 552dad00db1c..8cc2a39bb919 100644 --- a/aws/resource_aws_route_table_association.go +++ b/aws/resource_aws_route_table_association.go @@ -121,7 +121,7 @@ func resourceAwsRouteTableAssociationUpdate(d *schema.ResourceData, meta interfa output, err := conn.ReplaceRouteTableAssociation(input) // This whole thing with the resource ID being changed on update seems unsustainable. - // Keeping it here for backwards compatibilty... + // Keeping it here for backwards compatibility... if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidAssociationIDNotFound) { // Not found, so just create a new one From f6a0203a4d7b4a97411494cbc0fadb177052cd85 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 16:24:49 -0400 Subject: [PATCH 0462/1208] Ignore golanci-lint 'unparam' error. --- aws/resource_aws_route_table.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route_table.go b/aws/resource_aws_route_table.go index 7844a32a4033..4095f291c3a0 100644 --- a/aws/resource_aws_route_table.go +++ b/aws/resource_aws_route_table.go @@ -888,7 +888,7 @@ func routeTableRouteDestinationAttribute(m map[string]interface{}) (string, stri } // routeTableRouteTargetAttribute returns the attribute key and value of the route table route's target. -func routeTableRouteTargetAttribute(m map[string]interface{}) (string, string) { +func routeTableRouteTargetAttribute(m map[string]interface{}) (string, string) { //nolint:unparam for _, key := range routeTableValidTargets { if v, ok := m[key].(string); ok && v != "" { return key, v From 8f8a267e9a7a1dfe2bb3187045111ac8f66b6988 Mon Sep 17 00:00:00 2001 From: Adam Lewandowski Date: Tue, 18 May 2021 13:55:27 -0400 Subject: [PATCH 0463/1208] Add changelog entry --- .changelog/19426.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19426.txt diff --git a/.changelog/19426.txt b/.changelog/19426.txt new file mode 100644 index 000000000000..75097c3548e9 --- /dev/null +++ b/.changelog/19426.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_route_table: Add retries when reading route table +``` From cc31e7d7aab251e13819e34fec75da1612c6a5a7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 16:48:49 -0400 Subject: [PATCH 0464/1208] Add CHANGELOG entries. --- .changelog/19426.txt | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.changelog/19426.txt b/.changelog/19426.txt index 75097c3548e9..912bdafd6b0f 100644 --- a/.changelog/19426.txt +++ b/.changelog/19426.txt @@ -1,3 +1,23 @@ ```release-note:enhancement -resource/aws_route_table: Add retries when reading route table +resource/aws_route_table: Add retries when creating, deleting and replacing routes ``` + +```release-note:enhancement +resource/aws_route: Add retries when creating, deleting and replacing routes +``` + +```release-note:enhancement +resource/aws_default_route_table: Add retries when creating, deleting and replacing routes +``` + +```release-note:enhancement +resource/aws_default_route_table: Add retries when creating, deleting and replacing routes +``` + +```release-note:enhancement +resource/aws_main_route_table_association: Wait for association to reach the required state +``` + +```release-note:enhancement +resource/aws_route_table_association: Wait for association to reach the required state +``` \ No newline at end of file From 4579cff2d603a322b07dad898a8490487a684c33 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 16:50:35 -0400 Subject: [PATCH 0465/1208] Fix terrafmt errors. --- aws/resource_aws_route_table_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_route_table_test.go b/aws/resource_aws_route_table_test.go index 663fee82be60..f377447270a8 100644 --- a/aws/resource_aws_route_table_test.go +++ b/aws/resource_aws_route_table_test.go @@ -2116,12 +2116,12 @@ resource "aws_network_interface" "test1" { } resource "aws_network_interface" "test2" { - subnet_id = aws_subnet.test.id - - tags = { - Name = %[1]q - } + subnet_id = aws_subnet.test.id + + tags = { + Name = %[1]q } +} resource "aws_route_table" "test" { vpc_id = aws_vpc.test.id From c2953e4bacf1c46d8f3ef27433865909d4054535 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 16:57:22 -0400 Subject: [PATCH 0466/1208] Rename tests to help tctest. Acceptance test output: % go test -v ./aws/internal/net === RUN TestCIDRBlocksEqual --- PASS: TestCIDRBlocksEqual (0.00s) === RUN TestCanonicalCIDRBlock --- PASS: TestCanonicalCIDRBlock (0.00s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws/internal/net 0.687s --- aws/internal/net/cidr_test.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/aws/internal/net/cidr_test.go b/aws/internal/net/cidr_test.go index ce1ccefa3244..308f76a50799 100644 --- a/aws/internal/net/cidr_test.go +++ b/aws/internal/net/cidr_test.go @@ -1,10 +1,12 @@ -package net +package net_test import ( "testing" + + tfnet "github.com/terraform-providers/terraform-provider-aws/aws/internal/net" ) -func Test_CIDRBlocksEqual(t *testing.T) { +func TestCIDRBlocksEqual(t *testing.T) { for _, ts := range []struct { cidr1 string cidr2 string @@ -18,14 +20,14 @@ func Test_CIDRBlocksEqual(t *testing.T) { {"::/0", "::0/0", true}, {"", "", false}, } { - equal := CIDRBlocksEqual(ts.cidr1, ts.cidr2) + equal := tfnet.CIDRBlocksEqual(ts.cidr1, ts.cidr2) if ts.equal != equal { t.Fatalf("CIDRBlocksEqual(%q, %q) should be: %t", ts.cidr1, ts.cidr2, ts.equal) } } } -func Test_CanonicalCIDRBlock(t *testing.T) { +func TestCanonicalCIDRBlock(t *testing.T) { for _, ts := range []struct { cidr string expected string @@ -35,7 +37,7 @@ func Test_CanonicalCIDRBlock(t *testing.T) { {"::0/0", "::/0"}, {"", ""}, } { - got := CanonicalCIDRBlock(ts.cidr) + got := tfnet.CanonicalCIDRBlock(ts.cidr) if ts.expected != got { t.Fatalf("CanonicalCIDRBlock(%q) should be: %q, got: %q", ts.cidr, ts.expected, got) } From c26d46d7de4fe3c3401ec17f6ed7bd6f95e64638 Mon Sep 17 00:00:00 2001 From: Gareth Oakley Date: Tue, 6 Apr 2021 18:13:09 +0100 Subject: [PATCH 0467/1208] resource/aws_route53_resolver_firewall_config: Add new resource --- .../service/route53resolver/finder/finder.go | 29 +++ aws/provider.go | 1 + ...ce_aws_route53_resolver_firewall_config.go | 129 +++++++++++++ ...s_route53_resolver_firewall_config_test.go | 174 ++++++++++++++++++ .../route53_resolver_firewall_config.markdown | 48 +++++ 5 files changed, 381 insertions(+) create mode 100644 aws/resource_aws_route53_resolver_firewall_config.go create mode 100644 aws/resource_aws_route53_resolver_firewall_config_test.go create mode 100644 website/docs/r/route53_resolver_firewall_config.markdown diff --git a/aws/internal/service/route53resolver/finder/finder.go b/aws/internal/service/route53resolver/finder/finder.go index 59286ec207dd..50165183796f 100644 --- a/aws/internal/service/route53resolver/finder/finder.go +++ b/aws/internal/service/route53resolver/finder/finder.go @@ -116,6 +116,35 @@ func FirewallDomainListByID(conn *route53resolver.Route53Resolver, firewallDomai return output.FirewallDomainList, nil } +// FirewallConfigByID returns the dnssec configuration corresponding to the specified ID. +// Returns nil if no configuration is found. +func FirewallConfigByID(conn *route53resolver.Route53Resolver, firewallConfigID string) (*route53resolver.FirewallConfig, error) { + input := &route53resolver.ListFirewallConfigsInput{} + + var config *route53resolver.FirewallConfig + // GetFirewallConfigs does not support query with id + err := conn.ListFirewallConfigsPages(input, func(page *route53resolver.ListFirewallConfigsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, c := range page.FirewallConfigs { + if aws.StringValue(c.Id) == firewallConfigID { + config = c + return false + } + } + + return !lastPage + }) + + if err != nil { + return nil, err + } + + return config, nil +} + // FirewallRuleByID returns the DNS Firewall rule corresponding to the specified rule group and domain list IDs. // Returns nil if no DNS Firewall rule is found. func FirewallRuleByID(conn *route53resolver.Route53Resolver, firewallRuleId string) (*route53resolver.FirewallRule, error) { diff --git a/aws/provider.go b/aws/provider.go index 55715b6f977a..09bb2c0de5d4 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -963,6 +963,7 @@ func Provider() *schema.Provider { "aws_route53_health_check": resourceAwsRoute53HealthCheck(), "aws_route53_resolver_dnssec_config": resourceAwsRoute53ResolverDnssecConfig(), "aws_route53_resolver_endpoint": resourceAwsRoute53ResolverEndpoint(), + "aws_route53_resolver_firewall_config": resourceAwsRoute53ResolverFirewallConfig(), "aws_route53_resolver_firewall_domain_list": resourceAwsRoute53ResolverFirewallDomainList(), "aws_route53_resolver_firewall_rule": resourceAwsRoute53ResolverFirewallRule(), "aws_route53_resolver_firewall_rule_group": resourceAwsRoute53ResolverFirewallRuleGroup(), diff --git a/aws/resource_aws_route53_resolver_firewall_config.go b/aws/resource_aws_route53_resolver_firewall_config.go new file mode 100644 index 000000000000..d05d3b3ff78d --- /dev/null +++ b/aws/resource_aws_route53_resolver_firewall_config.go @@ -0,0 +1,129 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/route53resolver" + "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/service/route53resolver/finder" +) + +func resourceAwsRoute53ResolverFirewallConfig() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsRoute53ResolverFirewallConfigCreate, + Read: resourceAwsRoute53ResolverFirewallConfigRead, + Delete: resourceAwsRoute53ResolverFirewallConfigDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + + "owner_id": { + Type: schema.TypeString, + Computed: true, + }, + + "resource_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "firewall_fail_open": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(route53resolver.FirewallFailOpenStatus_Values(), false), + }, + }, + } +} + +func resourceAwsRoute53ResolverFirewallConfigCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + + input := &route53resolver.UpdateFirewallConfigInput{ + ResourceId: aws.String(d.Get("resource_id").(string)), + } + + if v, ok := d.GetOk("firewall_fail_open"); ok { + input.FirewallFailOpen = aws.String(v.(string)) + } + + log.Printf("[DEBUG] Creating Route 53 Resolver DNS Firewall config: %#v", input) + output, err := conn.UpdateFirewallConfig(input) + if err != nil { + return fmt.Errorf("error creating Route 53 Resolver DNS Firewall config: %w", err) + } + + d.SetId(aws.StringValue(output.FirewallConfig.Id)) + + return resourceAwsRoute53ResolverFirewallConfigRead(d, meta) +} + +func resourceAwsRoute53ResolverFirewallConfigRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + + config, err := finder.FirewallConfigByID(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error getting Route 53 Resolver DNS Firewall config (%s): %w", d.Id(), err) + } + + if config == nil { + log.Printf("[WARN] Route 53 Resolver DNS Firewall config (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + d.Set("id", config.Id) + d.Set("owner_id", config.OwnerId) + d.Set("resource_id", config.ResourceId) + d.Set("firewall_fail_open", config.FirewallFailOpen) + + return nil +} + +func resourceAwsRoute53ResolverFirewallConfigUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + + input := &route53resolver.UpdateFirewallConfigInput{ + ResourceId: aws.String(d.Get("resource_id").(string)), + } + + if v, ok := d.GetOk("firewall_fail_open"); ok { + input.FirewallFailOpen = aws.String(v.(string)) + } + + log.Printf("[DEBUG] Updating Route 53 Resolver DNS Firewall config: %#v", input) + _, err := conn.UpdateFirewallConfig(input) + if err != nil { + return fmt.Errorf("error creating Route 53 Resolver DNS Firewall config: %w", err) + } + + return resourceAwsRoute53ResolverFirewallConfigRead(d, meta) +} + +func resourceAwsRoute53ResolverFirewallConfigDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).route53resolverconn + + log.Printf("[DEBUG] Deleting Route 53 Resolver DNS Firewall config") + _, err := conn.UpdateFirewallConfig(&route53resolver.UpdateFirewallConfigInput{ + ResourceId: aws.String(d.Get("resource_id").(string)), + FirewallFailOpen: aws.String(route53resolver.FirewallFailOpenStatusDisabled), + }) + + if err != nil { + return fmt.Errorf("error deleting Route 53 Resolver DNS Firewall config (%s): %w", d.Id(), err) + } + + return nil +} diff --git a/aws/resource_aws_route53_resolver_firewall_config_test.go b/aws/resource_aws_route53_resolver_firewall_config_test.go new file mode 100644 index 000000000000..68bb9e6a79ca --- /dev/null +++ b/aws/resource_aws_route53_resolver_firewall_config_test.go @@ -0,0 +1,174 @@ +package aws + +import ( + "fmt" + "log" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/finder" +) + +func init() { + resource.AddTestSweepers("aws_route53_resolver_firewall_config", &resource.Sweeper{ + Name: "aws_route53_resolver_firewall_config", + F: testSweepRoute53ResolverFirewallConfigs, + Dependencies: []string{ + "aws_route53_resolver_firewall_config_association", + }, + }) +} + +func testSweepRoute53ResolverFirewallConfigs(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).route53resolverconn + var sweeperErrs *multierror.Error + + err = conn.ListFirewallConfigsPages(&route53resolver.ListFirewallConfigsInput{}, func(page *route53resolver.ListFirewallConfigsOutput, isLast bool) bool { + if page == nil { + return !isLast + } + + for _, firewallRuleGroup := range page.FirewallConfigs { + id := aws.StringValue(firewallRuleGroup.Id) + + log.Printf("[INFO] Deleting Route53 Resolver DNS Firewall config: %s", id) + r := resourceAwsRoute53ResolverFirewallConfig() + d := r.Data(nil) + d.SetId(id) + err := r.Delete(d, client) + + if err != nil { + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) + continue + } + } + + return !isLast + }) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Route53 Resolver DNS Firewall configs sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + } + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving Route53 Resolver DNS Firewall configs: %w", err)) + } + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSRoute53ResolverFirewallConfig_basic(t *testing.T) { + var v route53resolver.FirewallConfig + resourceName := "aws_route53_resolver_firewall_config.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, + ErrorCheck: testAccErrorCheck(t, route53resolver.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53ResolverFirewallConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53ResolverFirewallConfigConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverFirewallConfigExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "firewall_fail_open", "ENABLED"), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSRoute53ResolverFirewallConfig_disappears(t *testing.T) { + var v route53resolver.FirewallConfig + resourceName := "aws_route53_resolver_firewall_config.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, + ErrorCheck: testAccErrorCheck(t, route53resolver.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53ResolverFirewallConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53ResolverFirewallConfigConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverFirewallConfigExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53ResolverFirewallConfig(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckRoute53ResolverFirewallConfigDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).route53resolverconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_route53_resolver_firewall_config" { + continue + } + + // Try to find the resource + _, err := finder.FirewallConfigByID(conn, rs.Primary.ID) + // Verify the error is what we want + if isAWSErr(err, route53resolver.ErrCodeResourceNotFoundException, "") { + continue + } + if err != nil { + return err + } + return fmt.Errorf("Route 53 Resolver DNS Firewall config still exists: %s", rs.Primary.ID) + } + + return nil +} + +func testAccCheckRoute53ResolverFirewallConfigExists(n string, v *route53resolver.FirewallConfig) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Route 53 Resolver DNS Firewall config ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).route53resolverconn + out, err := finder.FirewallConfigByID(conn, rs.Primary.ID) + if err != nil { + return err + } + + *v = *out + + return nil + } +} + +func testAccRoute53ResolverFirewallConfigConfig() string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_route53_resolver_firewall_config" "test" { + resource_id = aws_vpc.test.id + firewall_fail_open = "ENABLED" +} +`) +} diff --git a/website/docs/r/route53_resolver_firewall_config.markdown b/website/docs/r/route53_resolver_firewall_config.markdown new file mode 100644 index 000000000000..fb152728daa1 --- /dev/null +++ b/website/docs/r/route53_resolver_firewall_config.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "Route53 Resolver" +layout: "aws" +page_title: "AWS: aws_route53_resolver_firewall_config" +description: |- + Provides a Route 53 Resolver DNS Firewall config resource. +--- + +# Resource: aws_route53_resolver_firewall_config + +Provides a Route 53 Resolver DNS Firewall config resource. + +## Example Usage + +```terraform +resource "aws_vpc" "example" { + cidr_block = "10.0.0.0/16" + enable_dns_support = true + enable_dns_hostnames = true +} + +resource "aws_route53_resolver_firewall_config" "example" { + resource_id = aws_vpc.example.id + firewall_fail_open = "ENABLED" +} +``` + +## Argument Reference + +The following argument is supported: + +* `resource_id` - (Required) The ID of the VPC that the configuration is for. +* `firewall_fail_open` - (Required) Determines how Route 53 Resolver handles queries during failures, for example when all traffic that is sent to DNS Firewall fails to receive a reply. By default, fail open is disabled, which means the failure mode is closed. This approach favors security over availability. DNS Firewall blocks queries that it is unable to evaluate properly. If you enable this option, the failure mode is open. This approach favors availability over security. DNS Firewall allows queries to proceed if it is unable to properly evaluate them. Valid values: `ENABLED`, `DISABLED`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the firewall configuration. +* `owner_id` - The AWS account ID of the owner of the VPC that this firewall configuration applies to. + +## Import + +Route 53 Resolver DNS Firewall configs can be imported using the Route 53 Resolver DNS Firewall config ID, e.g. + +``` +$ terraform import aws_route53_resolver_firewall_config.example rdsc-be1866ecc1683e95 +``` From 05a8bcb99da087660cdca9c00564533dc160c04d Mon Sep 17 00:00:00 2001 From: Gareth Oakley Date: Wed, 21 Apr 2021 20:37:59 +0100 Subject: [PATCH 0468/1208] resource/aws_route53_resolver_firewall_config: Address review comments --- .changelog/18733.txt | 3 +++ aws/resource_aws_route53_resolver_firewall_config.go | 6 ------ aws/resource_aws_route53_resolver_firewall_config_test.go | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) create mode 100644 .changelog/18733.txt diff --git a/.changelog/18733.txt b/.changelog/18733.txt new file mode 100644 index 000000000000..d75f326a0c9a --- /dev/null +++ b/.changelog/18733.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_route53_resolver_firewall_config +``` \ No newline at end of file diff --git a/aws/resource_aws_route53_resolver_firewall_config.go b/aws/resource_aws_route53_resolver_firewall_config.go index d05d3b3ff78d..8e2183af4f05 100644 --- a/aws/resource_aws_route53_resolver_firewall_config.go +++ b/aws/resource_aws_route53_resolver_firewall_config.go @@ -21,11 +21,6 @@ func resourceAwsRoute53ResolverFirewallConfig() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - }, - "owner_id": { Type: schema.TypeString, Computed: true, @@ -84,7 +79,6 @@ func resourceAwsRoute53ResolverFirewallConfigRead(d *schema.ResourceData, meta i return nil } - d.Set("id", config.Id) d.Set("owner_id", config.OwnerId) d.Set("resource_id", config.ResourceId) d.Set("firewall_fail_open", config.FirewallFailOpen) diff --git a/aws/resource_aws_route53_resolver_firewall_config_test.go b/aws/resource_aws_route53_resolver_firewall_config_test.go index 68bb9e6a79ca..f82e90c7f1d5 100644 --- a/aws/resource_aws_route53_resolver_firewall_config_test.go +++ b/aws/resource_aws_route53_resolver_firewall_config_test.go @@ -31,9 +31,9 @@ func testSweepRoute53ResolverFirewallConfigs(region string) error { conn := client.(*AWSClient).route53resolverconn var sweeperErrs *multierror.Error - err = conn.ListFirewallConfigsPages(&route53resolver.ListFirewallConfigsInput{}, func(page *route53resolver.ListFirewallConfigsOutput, isLast bool) bool { + err = conn.ListFirewallConfigsPages(&route53resolver.ListFirewallConfigsInput{}, func(page *route53resolver.ListFirewallConfigsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, firewallRuleGroup := range page.FirewallConfigs { From 60a450d9237a4863d538029271fe82112d9bd6e2 Mon Sep 17 00:00:00 2001 From: Gareth Oakley Date: Tue, 27 Apr 2021 19:56:29 +0100 Subject: [PATCH 0469/1208] resource/aws_route53_resolver_firewall_config: Address review comments II --- aws/resource_aws_route53_resolver_firewall_config_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_resolver_firewall_config_test.go b/aws/resource_aws_route53_resolver_firewall_config_test.go index f82e90c7f1d5..bb849eb6b0dc 100644 --- a/aws/resource_aws_route53_resolver_firewall_config_test.go +++ b/aws/resource_aws_route53_resolver_firewall_config_test.go @@ -52,7 +52,7 @@ func testSweepRoute53ResolverFirewallConfigs(region string) error { } } - return !isLast + return !lastPage }) if testSweepSkipSweepError(err) { log.Printf("[WARN] Skipping Route53 Resolver DNS Firewall configs sweep for %s: %s", region, err) From 7c56752b204a763b8109ebb25fd45fc94400ef20 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 15 Jun 2021 17:03:49 -0400 Subject: [PATCH 0470/1208] r/aws_route53_resolver_firewall_config: Reference 'resourceAwsRoute53ResolverFirewallConfigUpdate'. --- aws/resource_aws_route53_resolver_firewall_config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_route53_resolver_firewall_config.go b/aws/resource_aws_route53_resolver_firewall_config.go index 8e2183af4f05..88c3a133aee5 100644 --- a/aws/resource_aws_route53_resolver_firewall_config.go +++ b/aws/resource_aws_route53_resolver_firewall_config.go @@ -15,6 +15,7 @@ func resourceAwsRoute53ResolverFirewallConfig() *schema.Resource { return &schema.Resource{ Create: resourceAwsRoute53ResolverFirewallConfigCreate, Read: resourceAwsRoute53ResolverFirewallConfigRead, + Update: resourceAwsRoute53ResolverFirewallConfigUpdate, Delete: resourceAwsRoute53ResolverFirewallConfigDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, From dad15ed34d0d656d178ba16bb5b13a3b947b3639 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Wed, 16 Jun 2021 01:31:31 +0300 Subject: [PATCH 0471/1208] fix idp update + more tests --- aws/resource_aws_cognito_identity_provider.go | 27 ++--- ...urce_aws_cognito_identity_provider_test.go | 111 ++++++++++++++++++ 2 files changed, 121 insertions(+), 17 deletions(-) diff --git a/aws/resource_aws_cognito_identity_provider.go b/aws/resource_aws_cognito_identity_provider.go index ebde3d525f96..0fdc73c0f774 100644 --- a/aws/resource_aws_cognito_identity_provider.go +++ b/aws/resource_aws_cognito_identity_provider.go @@ -63,17 +63,10 @@ func resourceAwsCognitoIdentityProvider() *schema.Resource { }, "provider_type": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - cognitoidentityprovider.IdentityProviderTypeTypeSaml, - cognitoidentityprovider.IdentityProviderTypeTypeFacebook, - cognitoidentityprovider.IdentityProviderTypeTypeGoogle, - cognitoidentityprovider.IdentityProviderTypeTypeLoginWithAmazon, - cognitoidentityprovider.IdentityProviderTypeTypeOidc, - cognitoidentityprovider.IdentityProviderTypeTypeSignInWithApple, - }, false), + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(cognitoidentityprovider.IdentityProviderTypeType_Values(), false), }, "user_pool_id": { @@ -111,7 +104,7 @@ func resourceAwsCognitoIdentityProviderCreate(d *schema.ResourceData, meta inter _, err := conn.CreateIdentityProvider(params) if err != nil { - return fmt.Errorf("Error creating Cognito Identity Provider: %s", err) + return fmt.Errorf("Error creating Cognito Identity Provider: %w", err) } d.SetId(fmt.Sprintf("%s:%s", userPoolID, providerName)) @@ -154,15 +147,15 @@ func resourceAwsCognitoIdentityProviderRead(d *schema.ResourceData, meta interfa d.Set("user_pool_id", ip.UserPoolId) if err := d.Set("attribute_mapping", aws.StringValueMap(ip.AttributeMapping)); err != nil { - return fmt.Errorf("error setting attribute_mapping error: %s", err) + return fmt.Errorf("error setting attribute_mapping error: %w", err) } if err := d.Set("provider_details", aws.StringValueMap(ip.ProviderDetails)); err != nil { - return fmt.Errorf("error setting provider_details error: %s", err) + return fmt.Errorf("error setting provider_details error: %w", err) } if err := d.Set("idp_identifiers", flattenStringList(ip.IdpIdentifiers)); err != nil { - return fmt.Errorf("error setting idp_identifiers error: %s", err) + return fmt.Errorf("error setting idp_identifiers error: %w", err) } return nil @@ -191,12 +184,12 @@ func resourceAwsCognitoIdentityProviderUpdate(d *schema.ResourceData, meta inter } if d.HasChange("idp_identifiers") { - params.IdpIdentifiers = expandStringList(d.Get("supported_login_providers").([]interface{})) + params.IdpIdentifiers = expandStringList(d.Get("idp_identifiers").([]interface{})) } _, err = conn.UpdateIdentityProvider(params) if err != nil { - return fmt.Errorf("Error updating Cognito Identity Provider: %s", err) + return fmt.Errorf("Error updating Cognito Identity Provider: %w", err) } return resourceAwsCognitoIdentityProviderRead(d, meta) diff --git a/aws/resource_aws_cognito_identity_provider_test.go b/aws/resource_aws_cognito_identity_provider_test.go index 599f58824bfb..bd2a94206e2a 100644 --- a/aws/resource_aws_cognito_identity_provider_test.go +++ b/aws/resource_aws_cognito_identity_provider_test.go @@ -72,6 +72,88 @@ func TestAccAWSCognitoIdentityProvider_basic(t *testing.T) { }) } +func TestAccAWSCognitoIdentityProvider_idpIdentifiers(t *testing.T) { + var identityProvider cognitoidentityprovider.IdentityProviderType + resourceName := "aws_cognito_identity_provider.test" + userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + ErrorCheck: testAccErrorCheck(t, cognitoidentityprovider.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoIdentityProviderDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoIdentityProviderIDPIdentifierConfig(userPoolName, "test"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoIdentityProviderExists(resourceName, &identityProvider), + resource.TestCheckResourceAttr(resourceName, "idp_identifiers.#", "1"), + resource.TestCheckResourceAttr(resourceName, "idp_identifiers.0", "test"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCognitoIdentityProviderIDPIdentifierConfig(userPoolName, "test2"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoIdentityProviderExists(resourceName, &identityProvider), + resource.TestCheckResourceAttr(resourceName, "idp_identifiers.#", "1"), + resource.TestCheckResourceAttr(resourceName, "idp_identifiers.0", "test2"), + ), + }, + }, + }) +} + +func TestAccAWSCognitoIdentityProvider_disappears(t *testing.T) { + var identityProvider cognitoidentityprovider.IdentityProviderType + resourceName := "aws_cognito_identity_provider.test" + userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + ErrorCheck: testAccErrorCheck(t, cognitoidentityprovider.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoIdentityProviderDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoIdentityProviderConfig_basic(userPoolName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoIdentityProviderExists(resourceName, &identityProvider), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCognitoIdentityProvider(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSCognitoIdentityProvider_disappears_userPool(t *testing.T) { + var identityProvider cognitoidentityprovider.IdentityProviderType + resourceName := "aws_cognito_identity_provider.test" + userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + ErrorCheck: testAccErrorCheck(t, cognitoidentityprovider.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoIdentityProviderDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoIdentityProviderConfig_basic(userPoolName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoIdentityProviderExists(resourceName, &identityProvider), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCognitoUserPool(), "aws_cognito_user_pool.test"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAWSCognitoIdentityProviderDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).cognitoidpconn @@ -194,3 +276,32 @@ resource "aws_cognito_identity_provider" "test" { } `, userPoolName) } + +func testAccAWSCognitoIdentityProviderIDPIdentifierConfig(userPoolName, attribute string) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "test" { + name = %[1]q + auto_verified_attributes = ["email"] +} + +resource "aws_cognito_identity_provider" "test" { + user_pool_id = aws_cognito_user_pool.test.id + provider_name = "Google" + provider_type = "Google" + + idp_identifiers = [%[2]q] + + provider_details = { + attributes_url = "https://people.googleapis.com/v1/people/me?personFields=" + attributes_url_add_attributes = "true" + authorize_scopes = "email" + authorize_url = "https://accounts.google.com/o/oauth2/v2/auth" + client_id = "test-url.apps.googleusercontent.com" + client_secret = "client_secret" + oidc_issuer = "https://accounts.google.com" + token_request_method = "POST" + token_url = "https://www.googleapis.com/oauth2/v4/token" + } +} +`, userPoolName, attribute) +} From ea1120e3348f37e6ddd9a4810327f3a80d19b08f Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Wed, 16 Jun 2021 01:33:33 +0300 Subject: [PATCH 0472/1208] changelog --- .changelog/19819.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19819.txt diff --git a/.changelog/19819.txt b/.changelog/19819.txt new file mode 100644 index 000000000000..00170c5f1653 --- /dev/null +++ b/.changelog/19819.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_cognito_identity_provider: Fix updating `idp_identifiers` crash. +``` \ No newline at end of file From 33bcd099c556622000ec5f2c6de907c8ceb5045c Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Wed, 16 Jun 2021 01:35:18 +0300 Subject: [PATCH 0473/1208] fix changelog :) --- .changelog/19819.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/19819.txt b/.changelog/19819.txt index 00170c5f1653..dd629b76c046 100644 --- a/.changelog/19819.txt +++ b/.changelog/19819.txt @@ -1,3 +1,3 @@ -```release-note:enhancement +```release-note:bug resource/aws_cognito_identity_provider: Fix updating `idp_identifiers` crash. ``` \ No newline at end of file From acf4b550ac2b33fbc853f2718627bedc2410c466 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Tue, 15 Jun 2021 16:24:10 -0700 Subject: [PATCH 0474/1208] Check for nil values --- aws/data_source_aws_directory_service_directory.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/data_source_aws_directory_service_directory.go b/aws/data_source_aws_directory_service_directory.go index d4087075d817..8cd92cb946e7 100644 --- a/aws/data_source_aws_directory_service_directory.go +++ b/aws/data_source_aws_directory_service_directory.go @@ -182,9 +182,9 @@ func dataSourceAwsDirectoryServiceDirectoryRead(d *schema.ResourceData, meta int d.Set("enable_sso", dir.SsoEnabled) var securityGroupId *string - if aws.StringValue(dir.Type) == directoryservice.DirectoryTypeAdconnector { + if aws.StringValue(dir.Type) == directoryservice.DirectoryTypeAdconnector && dir.ConnectSettings != nil { securityGroupId = dir.ConnectSettings.SecurityGroupId - } else { + } else if dir.VpcSettings != nil { securityGroupId = dir.VpcSettings.SecurityGroupId } d.Set("security_group_id", securityGroupId) From cb6088e0733f6a08933155b343a446cd022b3033 Mon Sep 17 00:00:00 2001 From: slavo Date: Wed, 16 Jun 2021 11:22:39 +0200 Subject: [PATCH 0475/1208] Adjust default timeouts to be aligned with documentation of the resource. --- aws/internal/service/glue/waiter/waiter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/internal/service/glue/waiter/waiter.go b/aws/internal/service/glue/waiter/waiter.go index 3187f9bfca7e..3161620e0cad 100644 --- a/aws/internal/service/glue/waiter/waiter.go +++ b/aws/internal/service/glue/waiter/waiter.go @@ -14,8 +14,8 @@ const ( SchemaAvailableTimeout = 2 * time.Minute SchemaDeleteTimeout = 2 * time.Minute SchemaVersionAvailableTimeout = 2 * time.Minute - TriggerCreateTimeout = 2 * time.Minute - TriggerDeleteTimeout = 2 * time.Minute + TriggerCreateTimeout = 5 * time.Minute + TriggerDeleteTimeout = 5 * time.Minute ) // MLTransformDeleted waits for an MLTransform to return Deleted From fc0d421884f8e6c99bbb195f31bea8492f1e2e04 Mon Sep 17 00:00:00 2001 From: slavo Date: Wed, 16 Jun 2021 11:22:39 +0200 Subject: [PATCH 0476/1208] Adjust default Glue timeouts to be aligned with documentation of the resource. --- aws/internal/service/glue/waiter/waiter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/internal/service/glue/waiter/waiter.go b/aws/internal/service/glue/waiter/waiter.go index 3187f9bfca7e..3161620e0cad 100644 --- a/aws/internal/service/glue/waiter/waiter.go +++ b/aws/internal/service/glue/waiter/waiter.go @@ -14,8 +14,8 @@ const ( SchemaAvailableTimeout = 2 * time.Minute SchemaDeleteTimeout = 2 * time.Minute SchemaVersionAvailableTimeout = 2 * time.Minute - TriggerCreateTimeout = 2 * time.Minute - TriggerDeleteTimeout = 2 * time.Minute + TriggerCreateTimeout = 5 * time.Minute + TriggerDeleteTimeout = 5 * time.Minute ) // MLTransformDeleted waits for an MLTransform to return Deleted From db2bb61a3d9d12f4870235b939f56240639fd999 Mon Sep 17 00:00:00 2001 From: slavo Date: Wed, 16 Jun 2021 11:56:32 +0200 Subject: [PATCH 0477/1208] add release note entry --- .changelog/19827.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19827.txt diff --git a/.changelog/19827.txt b/.changelog/19827.txt new file mode 100644 index 000000000000..ba9eb20c6f8b --- /dev/null +++ b/.changelog/19827.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_glue_trigger: Fix default timeouts for Create and Delete operations +``` \ No newline at end of file From a45c360a5da92c24e5a42b217778db7c003ef7c2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 16 Jun 2021 09:38:28 -0400 Subject: [PATCH 0478/1208] r/aws_route53_resolver_firewall_config: Tweak 'testAccCheckRoute53ResolverFirewallConfigDestroy'. --- .../service/route53resolver/finder/finder.go | 7 ++++- ...ce_aws_route53_resolver_firewall_config.go | 11 ++++--- ...s_route53_resolver_firewall_config_test.go | 31 ++++++++++++++----- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/aws/internal/service/route53resolver/finder/finder.go b/aws/internal/service/route53resolver/finder/finder.go index 50165183796f..63e030eaecad 100644 --- a/aws/internal/service/route53resolver/finder/finder.go +++ b/aws/internal/service/route53resolver/finder/finder.go @@ -3,6 +3,7 @@ package finder import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" tfroute53resolver "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver" ) @@ -117,7 +118,7 @@ func FirewallDomainListByID(conn *route53resolver.Route53Resolver, firewallDomai } // FirewallConfigByID returns the dnssec configuration corresponding to the specified ID. -// Returns nil if no configuration is found. +// Returns NotFoundError if no configuration is found. func FirewallConfigByID(conn *route53resolver.Route53Resolver, firewallConfigID string) (*route53resolver.FirewallConfig, error) { input := &route53resolver.ListFirewallConfigsInput{} @@ -142,6 +143,10 @@ func FirewallConfigByID(conn *route53resolver.Route53Resolver, firewallConfigID return nil, err } + if config == nil { + return nil, &resource.NotFoundError{} + } + return config, nil } diff --git a/aws/resource_aws_route53_resolver_firewall_config.go b/aws/resource_aws_route53_resolver_firewall_config.go index 88c3a133aee5..0b51b59d49b4 100644 --- a/aws/resource_aws_route53_resolver_firewall_config.go +++ b/aws/resource_aws_route53_resolver_firewall_config.go @@ -9,6 +9,7 @@ import ( "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/service/route53resolver/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsRoute53ResolverFirewallConfig() *schema.Resource { @@ -70,16 +71,16 @@ func resourceAwsRoute53ResolverFirewallConfigRead(d *schema.ResourceData, meta i config, err := finder.FirewallConfigByID(conn, d.Id()) - if err != nil { - return fmt.Errorf("error getting Route 53 Resolver DNS Firewall config (%s): %w", d.Id(), err) - } - - if config == nil { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] Route 53 Resolver DNS Firewall config (%s) not found, removing from state", d.Id()) d.SetId("") return nil } + if err != nil { + return fmt.Errorf("error getting Route 53 Resolver DNS Firewall config (%s): %w", d.Id(), err) + } + d.Set("owner_id", config.OwnerId) d.Set("resource_id", config.ResourceId) d.Set("firewall_fail_open", config.FirewallFailOpen) diff --git a/aws/resource_aws_route53_resolver_firewall_config_test.go b/aws/resource_aws_route53_resolver_firewall_config_test.go index bb849eb6b0dc..3e84162227ba 100644 --- a/aws/resource_aws_route53_resolver_firewall_config_test.go +++ b/aws/resource_aws_route53_resolver_firewall_config_test.go @@ -8,9 +8,11 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/route53resolver" "github.com/hashicorp/go-multierror" + "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" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -68,6 +70,7 @@ func testSweepRoute53ResolverFirewallConfigs(region string) error { func TestAccAWSRoute53ResolverFirewallConfig_basic(t *testing.T) { var v route53resolver.FirewallConfig resourceName := "aws_route53_resolver_firewall_config.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, @@ -76,7 +79,7 @@ func TestAccAWSRoute53ResolverFirewallConfig_basic(t *testing.T) { CheckDestroy: testAccCheckRoute53ResolverFirewallConfigDestroy, Steps: []resource.TestStep{ { - Config: testAccRoute53ResolverFirewallConfigConfig(), + Config: testAccRoute53ResolverFirewallConfigConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverFirewallConfigExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "firewall_fail_open", "ENABLED"), @@ -95,6 +98,7 @@ func TestAccAWSRoute53ResolverFirewallConfig_basic(t *testing.T) { func TestAccAWSRoute53ResolverFirewallConfig_disappears(t *testing.T) { var v route53resolver.FirewallConfig resourceName := "aws_route53_resolver_firewall_config.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, @@ -103,7 +107,7 @@ func TestAccAWSRoute53ResolverFirewallConfig_disappears(t *testing.T) { CheckDestroy: testAccCheckRoute53ResolverFirewallConfigDestroy, Steps: []resource.TestStep{ { - Config: testAccRoute53ResolverFirewallConfigConfig(), + Config: testAccRoute53ResolverFirewallConfigConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverFirewallConfigExists(resourceName, &v), testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53ResolverFirewallConfig(), resourceName), @@ -122,15 +126,20 @@ func testAccCheckRoute53ResolverFirewallConfigDestroy(s *terraform.State) error continue } - // Try to find the resource - _, err := finder.FirewallConfigByID(conn, rs.Primary.ID) - // Verify the error is what we want - if isAWSErr(err, route53resolver.ErrCodeResourceNotFoundException, "") { + config, err := finder.FirewallConfigByID(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { continue } + if err != nil { return err } + + if aws.StringValue(config.FirewallFailOpen) == route53resolver.FirewallFailOpenStatusDisabled { + return nil + } + return fmt.Errorf("Route 53 Resolver DNS Firewall config still exists: %s", rs.Primary.ID) } @@ -149,7 +158,9 @@ func testAccCheckRoute53ResolverFirewallConfigExists(n string, v *route53resolve } conn := testAccProvider.Meta().(*AWSClient).route53resolverconn + out, err := finder.FirewallConfigByID(conn, rs.Primary.ID) + if err != nil { return err } @@ -160,15 +171,19 @@ func testAccCheckRoute53ResolverFirewallConfigExists(n string, v *route53resolve } } -func testAccRoute53ResolverFirewallConfigConfig() string { +func testAccRoute53ResolverFirewallConfigConfig(rName string) string { return fmt.Sprintf(` resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } } resource "aws_route53_resolver_firewall_config" "test" { resource_id = aws_vpc.test.id firewall_fail_open = "ENABLED" } -`) +`, rName) } From 33b32a908e8d5bf3e9d25f4a900f396d7ca6994d Mon Sep 17 00:00:00 2001 From: Nayo Akinyele Date: Wed, 16 Jun 2021 14:38:15 +0100 Subject: [PATCH 0479/1208] Improve cloudwatch_event_bus_policy docs with practical examples --- .../cloudwatch_event_bus_policy.html.markdown | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/website/docs/r/cloudwatch_event_bus_policy.html.markdown b/website/docs/r/cloudwatch_event_bus_policy.html.markdown index ed9cd103c737..150290784bd6 100644 --- a/website/docs/r/cloudwatch_event_bus_policy.html.markdown +++ b/website/docs/r/cloudwatch_event_bus_policy.html.markdown @@ -6,7 +6,7 @@ description: |- Provides a resource to create an EventBridge policy to support cross-account events. --- -# Resource: aws_cloudwatch_event_permission +# Resource: aws_cloudwatch_event_bus_policy Provides a resource to create an EventBridge resource policy to support cross-account events. @@ -19,6 +19,61 @@ Provides a resource to create an EventBridge resource policy to support cross-ac ### Account Access ```hcl +data "aws_iam_policy_document" "test" { + statement { + sid = "DevAccountAccess" + effect = "Allow" + actions = [ + "events:PutEvents", + ] + resources = [ + "arn:aws:events:eu-west-1:111111111111:event-bus/default" + ] + + principals { + type = "AWS" + identifiers = ["123456789012"] + } + } +} + +resource "aws_cloudwatch_event_bus_policy" "test" { + policy = data.aws_iam_policy_document.access.json + event_bus_name = aws_cloudwatch_event_bus.test.name +} +``` + +### Organization Access + +```hcl +data "aws_iam_policy_document" "test" { + statement { + sid = "OrganizationAccess" + effect = "Allow" + actions = [ + "events:DescribeRule", + "events:ListRules", + "events:ListTargetsByRule", + "events:ListTagsForResource", + ] + resources = [ + "arn:aws:events:eu-west-1:11111111111111:rule/*", + "arn:aws:events:eu-west-1:111111111111:event-bus/default" + ] + + principals { + type = "AWS" + identifiers = ["*"] + } + + condition { + test = "StringEquals" + variable = "aws:PrincipalOrgID" + values = aws_organizations_organization.example.id + } + } +} + resource "aws_cloudwatch_event_bus_policy" "test" { policy = data.aws_iam_policy_document.access.json event_bus_name = aws_cloudwatch_event_bus.test.name From b23292af4fa9fe581fe2fac60c4b621bb0ab8edf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 16 Jun 2021 10:55:59 -0400 Subject: [PATCH 0480/1208] r/aws_lambda_event_source_mapping: Additional IAM eventual consistency error message. --- aws/resource_aws_lambda_event_source_mapping.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/resource_aws_lambda_event_source_mapping.go b/aws/resource_aws_lambda_event_source_mapping.go index dc96af1f1be0..b48c61b646a1 100644 --- a/aws/resource_aws_lambda_event_source_mapping.go +++ b/aws/resource_aws_lambda_event_source_mapping.go @@ -384,6 +384,10 @@ func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta inte return resource.RetryableError(err) } + if tfawserr.ErrMessageContains(err, lambda.ErrCodeInvalidParameterValueException, "execution role does not have permissions") { + return resource.RetryableError(err) + } + if err != nil { return resource.NonRetryableError(err) } From 9d7a1f571aacfdf2d48675fd220c4b77f6bd5950 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 16 Jun 2021 10:59:28 -0400 Subject: [PATCH 0481/1208] Add CHANGELOG entry. --- .changelog/19831.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19831.txt diff --git a/.changelog/19831.txt b/.changelog/19831.txt new file mode 100644 index 000000000000..9b745f3e76a6 --- /dev/null +++ b/.changelog/19831.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_lambda_event_source_mapping: Enhance handling of IAM eventual consistency errors during create +``` \ No newline at end of file From f768a0fa80efecbb0e4e937e5628a1737f9fae94 Mon Sep 17 00:00:00 2001 From: FrancescoFucile-CAZ Date: Wed, 16 Jun 2021 16:56:19 +0100 Subject: [PATCH 0482/1208] chek policy consistency on "basic" test. --- ...ce_aws_cloudwatch_event_bus_policy_test.go | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index 32851bb9774c..1c49b190e81e 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -1,7 +1,9 @@ package aws import ( + "encoding/json" "fmt" + "reflect" "testing" "github.com/aws/aws-sdk-go/aws" @@ -23,7 +25,8 @@ func TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { { Config: testAccAWSCloudwatchEventBusPolicyConfig(rstring), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), + testAccAWSCloudWatchEventBusPolicyDocument(resourceName), + // testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), ), }, { @@ -88,6 +91,51 @@ func testAccCheckAWSCloudwatchEventBusPolicyExists(pr string) resource.TestCheck } } +func testAccAWSCloudWatchEventBusPolicyDocument(pr string) resource.TestCheckFunc { + return func(state *terraform.State) error { + eventBusPolicyResource, ok := state.RootModule().Resources[pr] + if !ok { + return fmt.Errorf("Not found: %s", pr) + } + + if eventBusPolicyResource.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + eventBusName := eventBusPolicyResource.Primary.ID + fmt.Printf("policy from state (struct): %+v\n", eventBusPolicyResource.Primary.Attributes["policy"]) + + var policyFromState map[string]interface{} + err := json.Unmarshal([]byte(eventBusPolicyResource.Primary.Attributes["policy"]), &policyFromState) + fmt.Printf("policy from state (map): %+v\n", policyFromState) + + input := &events.DescribeEventBusInput{ + Name: aws.String(eventBusName), + } + + cloudWatchEventsConnection := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn + describedEventBus, err := cloudWatchEventsConnection.DescribeEventBus(input) + + var policyFromSdk map[string]interface{} + err = json.Unmarshal([]byte(*describedEventBus.Policy), &policyFromSdk) + + fmt.Printf("output from SDK: %+v\n", policyFromSdk) + + if err != nil { + return fmt.Errorf("Reading CloudWatch Events bus policy for '%s' failed: %w", pr, err) + } + if describedEventBus.Policy == nil || len(*describedEventBus.Policy) == 0 { + return fmt.Errorf("Not found: %s", pr) + } + + if !reflect.DeepEqual(policyFromSdk, policyFromState) { + return fmt.Errorf("Policy on state doesn't match generated policy") + } + + return nil + } +} + func testAccAWSCloudwatchEventBusPolicyConfig(name string) string { return fmt.Sprintf(` resource "aws_cloudwatch_event_bus" "test" { From 9b35502f8c5b3c53c4ea652c67024ec45185ba01 Mon Sep 17 00:00:00 2001 From: FrancescoFucile-CAZ Date: Wed, 16 Jun 2021 17:08:26 +0100 Subject: [PATCH 0483/1208] polish "basic" test. --- ...rce_aws_cloudwatch_event_bus_policy_test.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index 1c49b190e81e..def6b086d397 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -26,7 +26,7 @@ func TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { Config: testAccAWSCloudwatchEventBusPolicyConfig(rstring), Check: resource.ComposeTestCheckFunc( testAccAWSCloudWatchEventBusPolicyDocument(resourceName), - // testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), + testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), ), }, { @@ -102,12 +102,10 @@ func testAccAWSCloudWatchEventBusPolicyDocument(pr string) resource.TestCheckFun return fmt.Errorf("No ID is set") } - eventBusName := eventBusPolicyResource.Primary.ID - fmt.Printf("policy from state (struct): %+v\n", eventBusPolicyResource.Primary.Attributes["policy"]) - var policyFromState map[string]interface{} err := json.Unmarshal([]byte(eventBusPolicyResource.Primary.Attributes["policy"]), &policyFromState) - fmt.Printf("policy from state (map): %+v\n", policyFromState) + + eventBusName := eventBusPolicyResource.Primary.ID input := &events.DescribeEventBusInput{ Name: aws.String(eventBusName), @@ -116,10 +114,8 @@ func testAccAWSCloudWatchEventBusPolicyDocument(pr string) resource.TestCheckFun cloudWatchEventsConnection := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn describedEventBus, err := cloudWatchEventsConnection.DescribeEventBus(input) - var policyFromSdk map[string]interface{} - err = json.Unmarshal([]byte(*describedEventBus.Policy), &policyFromSdk) - - fmt.Printf("output from SDK: %+v\n", policyFromSdk) + var describedEventBusPolicy map[string]interface{} + err = json.Unmarshal([]byte(*describedEventBus.Policy), &describedEventBusPolicy) if err != nil { return fmt.Errorf("Reading CloudWatch Events bus policy for '%s' failed: %w", pr, err) @@ -128,8 +124,8 @@ func testAccAWSCloudWatchEventBusPolicyDocument(pr string) resource.TestCheckFun return fmt.Errorf("Not found: %s", pr) } - if !reflect.DeepEqual(policyFromSdk, policyFromState) { - return fmt.Errorf("Policy on state doesn't match generated policy") + if !reflect.DeepEqual(describedEventBusPolicy, policyFromState) { + return fmt.Errorf("CloudWatch Events bus policy mismatch for '%s'", pr) } return nil From b5be7571130d06cb10d6198a2e5ba1ef3698b50e Mon Sep 17 00:00:00 2001 From: Arthur Diniz Date: Wed, 16 Jun 2021 13:28:11 -0300 Subject: [PATCH 0484/1208] Fix data source title and partial information (#19830) Signed-off-by: Arthur Diniz --- .../d/cloudfront_cache_policy.html.markdown | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/website/docs/d/cloudfront_cache_policy.html.markdown b/website/docs/d/cloudfront_cache_policy.html.markdown index cbbc79f3f868..848feb56ecc7 100644 --- a/website/docs/d/cloudfront_cache_policy.html.markdown +++ b/website/docs/d/cloudfront_cache_policy.html.markdown @@ -6,11 +6,11 @@ description: |- Use this data source to retrieve information about a CloudFront cache policy. --- -# Resource: aws_cloudfront_cache_policy +# Data source: aws_cloudfront_cache_policy -## Example Usage +Use this data source to retrieve information about a CloudFront cache policy. -The following example below creates a CloudFront cache policy. +## Example Usage ```terraform data "aws_cloudfront_cache_policy" "example" { @@ -27,6 +27,8 @@ The following arguments are supported: ## Attributes Reference +In addition to all arguments above, the following attributes are exported: + * `etag` - The current version of the cache policy. * `min_ttl` - The minimum amount of time, in seconds, that you want objects to stay in the CloudFront cache before CloudFront sends another request to the origin to see if the object has been updated. * `max_ttl` - The maximum amount of time, in seconds, that objects stay in the CloudFront cache before CloudFront sends another request to the origin to see if the object has been updated. @@ -44,22 +46,19 @@ The following arguments are supported: ### Cookies Config -`cookie_behavior` - Determines whether any cookies in viewer requests are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `allExcept`, `all`. -`cookies` - Object that contains a list of cookie names. See [Items](#items) for more information. +* `cookie_behavior` - Determines whether any cookies in viewer requests are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `allExcept`, `all`. +* `cookies` - Object that contains a list of cookie names. See [Items](#items) for more information. ### Headers Config -`header_behavior` - Determines whether any HTTP headers are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`. -`headers` - Object that contains a list of header names. See [Items](#items) for more information. +* `header_behavior` - Determines whether any HTTP headers are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`. +* `headers` - Object that contains a list of header names. See [Items](#items) for more information. ### Query String Config -`query_string_behavior` - Determines whether any URL query strings in viewer requests are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `allExcept`, `all`. -`query_strings` - Object that contains a list of query string names. See [Items](#items) for more information. +* `query_string_behavior` - Determines whether any URL query strings in viewer requests are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `allExcept`, `all`. +* `query_strings` - Object that contains a list of query string names. See [Items](#items) for more information. ### Items -`items` - A list of item names (cookies, headers, or query strings). - - - +* `items` - A list of item names (`cookies`, `headers`, or `query_strings`). \ No newline at end of file From b92a352441803324dcf0a7bc2a8fb09025867e84 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 16 Jun 2021 14:14:56 -0400 Subject: [PATCH 0485/1208] r/aws_sqs_queue: Backwards compatibility fix for default 'kms_data_key_reuse_period_seconds'. --- aws/internal/service/sqs/consts.go | 1 + aws/internal/service/sqs/waiter/waiter.go | 13 ++++++-- aws/resource_aws_sqs_queue.go | 5 +++ aws/resource_aws_sqs_queue_test.go | 37 +++++++++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/aws/internal/service/sqs/consts.go b/aws/internal/service/sqs/consts.go index 06263aa7c5da..d0c8a08e9c99 100644 --- a/aws/internal/service/sqs/consts.go +++ b/aws/internal/service/sqs/consts.go @@ -10,6 +10,7 @@ const ( const ( DefaultQueueDelaySeconds = 0 + DefaultQueueKmsDataKeyReusePeriodSeconds = 300 DefaultQueueMaximumMessageSize = 262_144 // 256 KiB. DefaultQueueMessageRetentionPeriod = 345_600 // 4 days. DefaultQueueReceiveMessageWaitTimeSeconds = 0 diff --git a/aws/internal/service/sqs/waiter/waiter.go b/aws/internal/service/sqs/waiter/waiter.go index a4a93e35a6de..4bafc85e12a8 100644 --- a/aws/internal/service/sqs/waiter/waiter.go +++ b/aws/internal/service/sqs/waiter/waiter.go @@ -2,12 +2,14 @@ package waiter import ( "fmt" + "strconv" "time" "github.com/aws/aws-sdk-go/service/sqs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" awspolicy "github.com/jen20/awspolicyequivalence" tfjson "github.com/terraform-providers/terraform-provider-aws/aws/internal/json" + tfsqs "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sqs/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -35,6 +37,11 @@ func QueueAttributesPropagated(conn *sqs.SQS, url string, expected map[string]st g, ok := got[k] if !ok { + // Backwards compatibility: https://github.com/hashicorp/terraform-provider-aws/issues/19786. + if k == sqs.QueueAttributeNameKmsDataKeyReusePeriodSeconds && e == strconv.Itoa(tfsqs.DefaultQueueKmsDataKeyReusePeriodSeconds) { + continue + } + return fmt.Errorf("SQS Queue attribute (%s) not available", k) } @@ -90,10 +97,10 @@ func QueueAttributesPropagated(conn *sqs.SQS, url string, expected map[string]st } err = attributesMatch(got) + } - if err != nil { - return err - } + if err != nil { + return err } return nil diff --git a/aws/resource_aws_sqs_queue.go b/aws/resource_aws_sqs_queue.go index ad2a664b2718..4ea09c112aa0 100644 --- a/aws/resource_aws_sqs_queue.go +++ b/aws/resource_aws_sqs_queue.go @@ -290,6 +290,11 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error { return err } + // Backwards compatibility: https://github.com/hashicorp/terraform-provider-aws/issues/19786. + if d.Get("kms_data_key_reuse_period_seconds").(int) == 0 { + d.Set("kms_data_key_reuse_period_seconds", tfsqs.DefaultQueueKmsDataKeyReusePeriodSeconds) + } + d.Set("name", name) if d.Get("fifo_queue").(bool) { d.Set("name_prefix", naming.NamePrefixFromNameWithSuffix(name, tfsqs.FifoQueueNameSuffix)) diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index 9b5fa8f4b483..0be532c8afd2 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -650,6 +650,34 @@ func TestAccAWSSQSQueue_ZeroVisibilityTimeoutSeconds(t *testing.T) { }) } +// https://github.com/hashicorp/terraform-provider-aws/issues/19786. +func TestAccAWSSQSQueue_DefaultKmsDataKeyReusePeriodSeconds(t *testing.T) { + var queueAttributes map[string]string + resourceName := "aws_sqs_queue.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sqs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSQSQueueDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSQSConfigDefaultKmsDataKeyReusePeriodSeconds(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSQSQueueExists(resourceName, &queueAttributes), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", strconv.Itoa(tfsqs.DefaultQueueKmsDataKeyReusePeriodSeconds)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAWSSQSQueuePolicyAttribute(queueAttributes *map[string]string, rName string) resource.TestCheckFunc { return func(s *terraform.State) error { expectedPolicyText := fmt.Sprintf( @@ -952,3 +980,12 @@ resource "aws_sqs_queue" "test" { } `, rName) } + +func testAccAWSSQSConfigDefaultKmsDataKeyReusePeriodSeconds(rName string) string { + return fmt.Sprintf(` +resource "aws_sqs_queue" "test" { + name = %[1]q + kms_data_key_reuse_period_seconds = 300 +} +`, rName) +} From ec5a5995ca7b8f3d02390690aaa0dcf54d252d03 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 16 Jun 2021 14:21:57 -0400 Subject: [PATCH 0486/1208] Add CHANGELOG entry. --- .changelog/19834.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19834.txt diff --git a/.changelog/19834.txt b/.changelog/19834.txt new file mode 100644 index 000000000000..1ed731803c54 --- /dev/null +++ b/.changelog/19834.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_sqs_queue: Correctly handle the default `kms_data_key_reuse_period_seconds` value of `300` for unencrypted queues +``` \ No newline at end of file From 865ba8d7552a5e022b4b0f1a51541ab057d5b04e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 16 Jun 2021 14:58:13 -0400 Subject: [PATCH 0487/1208] r/aws_sqs_queue: Acceptance tests passing. --- aws/resource_aws_sqs_queue_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_sqs_queue_test.go b/aws/resource_aws_sqs_queue_test.go index 0be532c8afd2..3457792b0a86 100644 --- a/aws/resource_aws_sqs_queue_test.go +++ b/aws/resource_aws_sqs_queue_test.go @@ -99,7 +99,7 @@ func TestAccAWSSQSQueue_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), - resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", "0"), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", strconv.Itoa(tfsqs.DefaultQueueKmsDataKeyReusePeriodSeconds)), resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", ""), resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), @@ -323,7 +323,7 @@ func TestAccAWSSQSQueue_Update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "delay_seconds", strconv.Itoa(tfsqs.DefaultQueueDelaySeconds)), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), - resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", "0"), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", strconv.Itoa(tfsqs.DefaultQueueKmsDataKeyReusePeriodSeconds)), resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", ""), resource.TestCheckResourceAttr(resourceName, "max_message_size", strconv.Itoa(tfsqs.DefaultQueueMaximumMessageSize)), resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", strconv.Itoa(tfsqs.DefaultQueueMessageRetentionPeriod)), @@ -346,7 +346,7 @@ func TestAccAWSSQSQueue_Update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "delay_seconds", "90"), resource.TestCheckResourceAttr(resourceName, "fifo_queue", "false"), resource.TestCheckResourceAttr(resourceName, "fifo_throughput_limit", ""), - resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", "0"), + resource.TestCheckResourceAttr(resourceName, "kms_data_key_reuse_period_seconds", strconv.Itoa(tfsqs.DefaultQueueKmsDataKeyReusePeriodSeconds)), resource.TestCheckResourceAttr(resourceName, "kms_master_key_id", ""), resource.TestCheckResourceAttr(resourceName, "max_message_size", "2048"), resource.TestCheckResourceAttr(resourceName, "message_retention_seconds", "86400"), From 48fc2ba999ca4add392ff676386b4916b0f97105 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 16 Jun 2021 14:58:45 -0400 Subject: [PATCH 0488/1208] r/aws_sqs_queue_policy: Missing attribute equivalent to empty expected value. --- aws/internal/service/sqs/waiter/waiter.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aws/internal/service/sqs/waiter/waiter.go b/aws/internal/service/sqs/waiter/waiter.go index 4bafc85e12a8..0df8bf619ae2 100644 --- a/aws/internal/service/sqs/waiter/waiter.go +++ b/aws/internal/service/sqs/waiter/waiter.go @@ -37,6 +37,11 @@ func QueueAttributesPropagated(conn *sqs.SQS, url string, expected map[string]st g, ok := got[k] if !ok { + // Missing attribute equivalent to empty expected value. + if e == "" { + continue + } + // Backwards compatibility: https://github.com/hashicorp/terraform-provider-aws/issues/19786. if k == sqs.QueueAttributeNameKmsDataKeyReusePeriodSeconds && e == strconv.Itoa(tfsqs.DefaultQueueKmsDataKeyReusePeriodSeconds) { continue From d3f5abca1be772421c4694e28b3bb1f78e75675c Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 1 May 2020 22:20:13 +0300 Subject: [PATCH 0489/1208] add on demand parmas --- aws/resource_aws_spot_fleet_request.go | 48 ++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index 19294744fdfc..504e29cd07f3 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -545,6 +545,22 @@ func resourceAwsSpotFleetRequest() *schema.Resource { }, Set: schema.HashString, }, + "on_demand_allocation_strategy": { + Type: schema.TypeString, + Optional: true, + }, + "on_demand_fulfilled_capacity": { + Type: schema.TypeFloat, + Optional: true, + }, + "on_demand_max_total_price": { + Type: schema.TypeString, + Optional: true, + }, + "on_demand_target_capacity": { + Type: schema.TypeInt, + Optional: true, + }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), }, @@ -988,6 +1004,22 @@ func resourceAwsSpotFleetRequestCreate(d *schema.ResourceData, meta interface{}) spotFleetConfig.SpotPrice = aws.String(v.(string)) } + if v, ok := d.GetOk("on_demand_target_capacity"); ok { + spotFleetConfig.OnDemandTargetCapacity = aws.Int64(int64(v.(int))) + } + + if v, ok := d.GetOk("on_demand_allocation_strategy"); ok { + spotFleetConfig.OnDemandAllocationStrategy = aws.String(v.(string)) + } + + if v, ok := d.GetOk("on_demand_max_total_price"); ok { + spotFleetConfig.OnDemandMaxTotalPrice = aws.String(v.(string)) + } + + if v, ok := d.GetOk("on_demand_fulfilled_capacity"); ok { + spotFleetConfig.OnDemandFulfilledCapacity = aws.Float64(v.(float64)) + } + if v, ok := d.GetOk("valid_from"); ok { validFrom, err := time.Parse(time.RFC3339, v.(string)) if err != nil { @@ -1310,6 +1342,22 @@ func resourceAwsSpotFleetRequestRead(d *schema.ResourceData, meta interface{}) e } } + if config.OnDemandTargetCapacity != nil { + d.Set("on_demand_target_capacity", aws.Int64Value(config.OnDemandTargetCapacity)) + } + + if config.OnDemandAllocationStrategy != nil { + d.Set("on_demand_allocation_strategy", aws.StringValue(config.OnDemandAllocationStrategy)) + } + + if config.OnDemandMaxTotalPrice != nil { + d.Set("on_demand_max_total_price", aws.StringValue(config.OnDemandMaxTotalPrice)) + } + + if config.OnDemandFulfilledCapacity != nil { + d.Set("on_demand_fulfilled_capacity", aws.Float64Value(config.OnDemandFulfilledCapacity)) + } + if config.LoadBalancersConfig != nil { lbConf := config.LoadBalancersConfig From 55cb6c36c211340ac1a2d5db5b0be4ae533f5182 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 1 May 2020 22:33:09 +0300 Subject: [PATCH 0490/1208] allow updating `on_demand_target_capacity` and force new to other on demand arguments --- aws/resource_aws_spot_fleet_request.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index 504e29cd07f3..252430198bc1 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -548,14 +548,17 @@ func resourceAwsSpotFleetRequest() *schema.Resource { "on_demand_allocation_strategy": { Type: schema.TypeString, Optional: true, + ForceNew: true, }, "on_demand_fulfilled_capacity": { Type: schema.TypeFloat, Optional: true, + ForceNew: true, }, "on_demand_max_total_price": { Type: schema.TypeString, Optional: true, + ForceNew: true, }, "on_demand_target_capacity": { Type: schema.TypeInt, @@ -1647,6 +1650,14 @@ func resourceAwsSpotFleetRequestUpdate(d *schema.ResourceData, meta interface{}) } } + if d.HasChange("on_demand_target_capacity") { + if val, ok := d.GetOk("on_demand_target_capacity"); ok { + req.OnDemandTargetCapacity = aws.Int64(int64(val.(int))) + } + + updateFlag = true + } + if d.HasChange("excess_capacity_termination_policy") { if val, ok := d.GetOk("excess_capacity_termination_policy"); ok { req.ExcessCapacityTerminationPolicy = aws.String(val.(string)) From f5ec0499c0344e8334b2905452ceabdd435e3452 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 1 May 2020 22:35:37 +0300 Subject: [PATCH 0491/1208] allow zero value on demand target capacity --- aws/resource_aws_spot_fleet_request.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index 252430198bc1..a5297f2204e9 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -1007,7 +1007,7 @@ func resourceAwsSpotFleetRequestCreate(d *schema.ResourceData, meta interface{}) spotFleetConfig.SpotPrice = aws.String(v.(string)) } - if v, ok := d.GetOk("on_demand_target_capacity"); ok { + if v, ok := d.GetOkExists("on_demand_target_capacity"); ok { spotFleetConfig.OnDemandTargetCapacity = aws.Int64(int64(v.(int))) } From 7e0b219cd29d4885b6a1420e1da6b80861fee968 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 1 May 2020 22:40:46 +0300 Subject: [PATCH 0492/1208] add default and validation for `on_demand_allocation_strategy` --- aws/resource_aws_spot_fleet_request.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index a5297f2204e9..377c57565aaa 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -549,6 +549,11 @@ func resourceAwsSpotFleetRequest() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Default: ec2.OnDemandAllocationStrategyLowestPrice, + ValidateFunc: validation.StringInSlice([]string{ + ec2.OnDemandAllocationStrategyPrioritized, + ec2.OnDemandAllocationStrategyLowestPrice, + }, false), }, "on_demand_fulfilled_capacity": { Type: schema.TypeFloat, From c75b1296ee81920535ba19c712967e1eb7c5dd39 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 1 May 2020 22:55:02 +0300 Subject: [PATCH 0493/1208] add docs --- website/docs/r/spot_fleet_request.html.markdown | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/docs/r/spot_fleet_request.html.markdown b/website/docs/r/spot_fleet_request.html.markdown index c2438c69fdef..70d0cba0481e 100644 --- a/website/docs/r/spot_fleet_request.html.markdown +++ b/website/docs/r/spot_fleet_request.html.markdown @@ -201,6 +201,10 @@ across different markets and instance types. Conflicts with `launch_template_con * `valid_from` - (Optional) The start date and time of the request, in UTC [RFC3339](https://tools.ietf.org/html/rfc3339#section-5.8) format(for example, YYYY-MM-DDTHH:MM:SSZ). The default is to start fulfilling the request immediately. * `load_balancers` (Optional) A list of elastic load balancer names to add to the Spot fleet. * `target_group_arns` (Optional) A list of `aws_alb_target_group` ARNs, for use with Application Load Balancing. +* `on_demand_allocation_strategy` - The order of the launch template overrides to use in fulfilling On-Demand capacity. the possible values are: `lowestPrice` and `prioritized`. the default is `lowestPrice`. +* `on_demand_fulfilled_capacity` - The number of On-Demand units fulfilled by this request compared to the set target On-Demand capacity. +* `on_demand_max_total_price` - The maximum amount per hour for On-Demand Instances that you're willing to pay. When the maximum amount you're willing to pay is reached, the fleet stops launching instances even if it hasn’t met the target capacity. +* `on_demand_target_capacity` - The number of On-Demand units to request. If the request type is `maintain`, you can specify a target capacity of 0 and add capacity later. * `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. ### Launch Template Configs From 3471810e2b43f240489c2029d3198d164b6a3578 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 2 May 2020 23:55:30 +0300 Subject: [PATCH 0494/1208] add test for `on_demand_target_capacity` --- aws/resource_aws_spot_fleet_request.go | 5 +- aws/resource_aws_spot_fleet_request_test.go | 75 +++++++++++++++++++++ 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index 377c57565aaa..c78de14c6e5b 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -1656,11 +1656,10 @@ func resourceAwsSpotFleetRequestUpdate(d *schema.ResourceData, meta interface{}) } if d.HasChange("on_demand_target_capacity") { - if val, ok := d.GetOk("on_demand_target_capacity"); ok { + if val, ok := d.GetOkExists("on_demand_target_capacity"); ok { req.OnDemandTargetCapacity = aws.Int64(int64(val.(int))) + updateFlag = true } - - updateFlag = true } if d.HasChange("excess_capacity_termination_policy") { diff --git a/aws/resource_aws_spot_fleet_request_test.go b/aws/resource_aws_spot_fleet_request_test.go index 30138bb5fc53..f46401dbadbb 100644 --- a/aws/resource_aws_spot_fleet_request_test.go +++ b/aws/resource_aws_spot_fleet_request_test.go @@ -349,6 +349,49 @@ func TestAccAWSSpotFleetRequest_launchSpecToLaunchTemplate(t *testing.T) { }) } +func TestAccAWSSpotFleetRequest_onDemandTargetCapacity(t *testing.T) { + var sfr ec2.SpotFleetRequestConfig + rName := acctest.RandString(10) + rInt := acctest.RandInt() + validUntil := time.Now().UTC().Add(24 * time.Hour).Format(time.RFC3339) + resourceName := "aws_spot_fleet_request.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSpotFleetRequestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName, rInt, validUntil, 0), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotFleetRequestExists(resourceName, &sfr), + resource.TestCheckResourceAttr(resourceName, "on_demand_target_capacity", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"wait_for_fulfillment"}, + }, + { + Config: testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName, rInt, validUntil, 1), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotFleetRequestExists(resourceName, &sfr), + resource.TestCheckResourceAttr(resourceName, "on_demand_target_capacity", "1"), + ), + }, + { + Config: testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName, rInt, validUntil, 0), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotFleetRequestExists(resourceName, &sfr), + resource.TestCheckResourceAttr(resourceName, "on_demand_target_capacity", "0"), + ), + }, + }, + }) +} + func TestAccAWSSpotFleetRequest_instanceInterruptionBehavior(t *testing.T) { var sfr ec2.SpotFleetRequestConfig rName := acctest.RandomWithPrefix("tf-acc-test") @@ -2663,3 +2706,35 @@ resource "aws_spot_fleet_request" "test" { } `, validUntil) } + +func testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName string, rInt int, validUntil string, targetCapacity int) string { + return testAccAWSSpotFleetRequestConfigBase(rName, rInt) + + fmt.Sprintf(` +resource "aws_launch_template" "test" { + name = %[2]q + image_id = "${data.aws_ami.amzn-ami-minimal-hvm-ebs.id}" + instance_type = "${data.aws_ec2_instance_type_offering.available.instance_type}" + key_name = "${aws_key_pair.test.key_name}" +} + +resource "aws_spot_fleet_request" "test" { + iam_fleet_role = "${aws_iam_role.test-role.arn}" + spot_price = "0.005" + target_capacity = 2 + valid_until = %[1]q + terminate_instances_with_expiration = true + instance_interruption_behaviour = "stop" + wait_for_fulfillment = true + on_demand_target_capacity = %[3]d + + launch_template_config { + launch_template_specification { + name = "${aws_launch_template.test.name}" + version = "${aws_launch_template.test.latest_version}" + } + } + + depends_on = ["aws_iam_policy_attachment.test-attach"] +} +`, validUntil, rName, targetCapacity) +} From e40ee1ee8047727bd6f2069d0a733d5cd3691559 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 7 Aug 2020 00:20:33 +0300 Subject: [PATCH 0495/1208] `on_demand_fulfilled_capacity` can change by other actions, adding computed add tests for on demand max price and allocation strategy --- aws/resource_aws_spot_fleet_request.go | 1 + aws/resource_aws_spot_fleet_request_test.go | 149 ++++++++++++++++++-- 2 files changed, 135 insertions(+), 15 deletions(-) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index c78de14c6e5b..15375366d6e9 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -559,6 +559,7 @@ func resourceAwsSpotFleetRequest() *schema.Resource { Type: schema.TypeFloat, Optional: true, ForceNew: true, + Computed: true, }, "on_demand_max_total_price": { Type: schema.TypeString, diff --git a/aws/resource_aws_spot_fleet_request_test.go b/aws/resource_aws_spot_fleet_request_test.go index f46401dbadbb..2de4a55b80c2 100644 --- a/aws/resource_aws_spot_fleet_request_test.go +++ b/aws/resource_aws_spot_fleet_request_test.go @@ -351,8 +351,7 @@ func TestAccAWSSpotFleetRequest_launchSpecToLaunchTemplate(t *testing.T) { func TestAccAWSSpotFleetRequest_onDemandTargetCapacity(t *testing.T) { var sfr ec2.SpotFleetRequestConfig - rName := acctest.RandString(10) - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") validUntil := time.Now().UTC().Add(24 * time.Hour).Format(time.RFC3339) resourceName := "aws_spot_fleet_request.test" @@ -362,7 +361,7 @@ func TestAccAWSSpotFleetRequest_onDemandTargetCapacity(t *testing.T) { CheckDestroy: testAccCheckAWSSpotFleetRequestDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName, rInt, validUntil, 0), + Config: testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName, validUntil, 0), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotFleetRequestExists(resourceName, &sfr), resource.TestCheckResourceAttr(resourceName, "on_demand_target_capacity", "0"), @@ -375,14 +374,14 @@ func TestAccAWSSpotFleetRequest_onDemandTargetCapacity(t *testing.T) { ImportStateVerifyIgnore: []string{"wait_for_fulfillment"}, }, { - Config: testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName, rInt, validUntil, 1), + Config: testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName, validUntil, 1), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotFleetRequestExists(resourceName, &sfr), resource.TestCheckResourceAttr(resourceName, "on_demand_target_capacity", "1"), ), }, { - Config: testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName, rInt, validUntil, 0), + Config: testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName, validUntil, 0), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotFleetRequestExists(resourceName, &sfr), resource.TestCheckResourceAttr(resourceName, "on_demand_target_capacity", "0"), @@ -392,6 +391,62 @@ func TestAccAWSSpotFleetRequest_onDemandTargetCapacity(t *testing.T) { }) } +func TestAccAWSSpotFleetRequest_onDemandMaxTotalPrice(t *testing.T) { + var sfr ec2.SpotFleetRequestConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + validUntil := time.Now().UTC().Add(24 * time.Hour).Format(time.RFC3339) + resourceName := "aws_spot_fleet_request.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSpotFleetRequestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSpotFleetRequestOnDemandMaxTotalPriceConfig(rName, validUntil, "0.05"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotFleetRequestExists(resourceName, &sfr), + resource.TestCheckResourceAttr(resourceName, "on_demand_max_total_price", "0.05"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"wait_for_fulfillment"}, + }, + }, + }) +} + +func TestAccAWSSpotFleetRequest_onDemandAllocationStrategy(t *testing.T) { + var sfr ec2.SpotFleetRequestConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + validUntil := time.Now().UTC().Add(24 * time.Hour).Format(time.RFC3339) + resourceName := "aws_spot_fleet_request.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSpotFleetRequestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSpotFleetRequestOnDemandAllocationStrategyConfig(rName, validUntil, "prioritized"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotFleetRequestExists(resourceName, &sfr), + resource.TestCheckResourceAttr(resourceName, "on_demand_allocation_strategy", "prioritized"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"wait_for_fulfillment"}, + }, + }, + }) +} + func TestAccAWSSpotFleetRequest_instanceInterruptionBehavior(t *testing.T) { var sfr ec2.SpotFleetRequestConfig rName := acctest.RandomWithPrefix("tf-acc-test") @@ -2711,17 +2766,17 @@ func testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName string, rInt i return testAccAWSSpotFleetRequestConfigBase(rName, rInt) + fmt.Sprintf(` resource "aws_launch_template" "test" { - name = %[2]q - image_id = "${data.aws_ami.amzn-ami-minimal-hvm-ebs.id}" - instance_type = "${data.aws_ec2_instance_type_offering.available.instance_type}" - key_name = "${aws_key_pair.test.key_name}" + name = %[1]q + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = data.aws_ec2_instance_type_offering.available.instance_type + key_name = aws_key_pair.test.key_name } resource "aws_spot_fleet_request" "test" { - iam_fleet_role = "${aws_iam_role.test-role.arn}" + iam_fleet_role = aws_iam_role.test.arn spot_price = "0.005" target_capacity = 2 - valid_until = %[1]q + valid_until = %[2]q terminate_instances_with_expiration = true instance_interruption_behaviour = "stop" wait_for_fulfillment = true @@ -2729,12 +2784,76 @@ resource "aws_spot_fleet_request" "test" { launch_template_config { launch_template_specification { - name = "${aws_launch_template.test.name}" - version = "${aws_launch_template.test.latest_version}" + name = aws_launch_template.test.name + version = aws_launch_template.test.latest_version + } + } + + depends_on = ["aws_iam_policy_attachment.test"] +} +`, rName, validUntil, targetCapacity) +} + +func testAccAWSSpotFleetRequestOnDemandMaxTotalPriceConfig(rName, validUntil, price string) string { + return testAccAWSSpotFleetRequestConfigBase(rName) + + fmt.Sprintf(` +resource "aws_launch_template" "test" { + name = %[1]q + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = data.aws_ec2_instance_type_offering.available.instance_type + key_name = aws_key_pair.test.key_name +} + +resource "aws_spot_fleet_request" "test" { + iam_fleet_role = aws_iam_role.test.arn + spot_price = "0.005" + target_capacity = 2 + valid_until = %[2]q + terminate_instances_with_expiration = true + instance_interruption_behaviour = "stop" + wait_for_fulfillment = true + on_demand_max_total_price = %[3]q + + launch_template_config { + launch_template_specification { + name = aws_launch_template.test.name + version = aws_launch_template.test.latest_version + } + } + + depends_on = ["aws_iam_policy_attachment.test"] +} +`, rName, validUntil, price) +} + +func testAccAWSSpotFleetRequestOnDemandAllocationStrategyConfig(rName, validUntil, strategy string) string { + return testAccAWSSpotFleetRequestConfigBase(rName) + + fmt.Sprintf(` +resource "aws_launch_template" "test" { + name = %[1]q + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = data.aws_ec2_instance_type_offering.available.instance_type + key_name = aws_key_pair.test.key_name +} + +resource "aws_spot_fleet_request" "test" { + iam_fleet_role = aws_iam_role.test.arn + spot_price = "0.005" + target_capacity = 2 + valid_until = %[2]q + terminate_instances_with_expiration = true + instance_interruption_behaviour = "stop" + wait_for_fulfillment = true + on_demand_allocation_strategy = %[3]q + + launch_template_config { + launch_template_specification { + name = aws_launch_template.test.name + version = aws_launch_template.test.latest_version } } - depends_on = ["aws_iam_policy_attachment.test-attach"] + depends_on = ["aws_iam_policy_attachment.test"] } -`, validUntil, rName, targetCapacity) +`, rName, validUntil, strategy) } From 977a5a7e366559274a768883468fd9a26ef98b09 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 7 Aug 2020 00:37:32 +0300 Subject: [PATCH 0496/1208] add test for fulfilled capacity --- aws/resource_aws_spot_fleet_request_test.go | 60 +++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/aws/resource_aws_spot_fleet_request_test.go b/aws/resource_aws_spot_fleet_request_test.go index 2de4a55b80c2..7617fee2c1ea 100644 --- a/aws/resource_aws_spot_fleet_request_test.go +++ b/aws/resource_aws_spot_fleet_request_test.go @@ -447,6 +447,34 @@ func TestAccAWSSpotFleetRequest_onDemandAllocationStrategy(t *testing.T) { }) } +func TestAccAWSSpotFleetRequest_onDemandFulfilledCapacity(t *testing.T) { + var sfr ec2.SpotFleetRequestConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + validUntil := time.Now().UTC().Add(24 * time.Hour).Format(time.RFC3339) + resourceName := "aws_spot_fleet_request.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSpotFleetRequestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSpotFleetRequestOnDemandFulfilledCapacityConfig(rName, validUntil, "2"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotFleetRequestExists(resourceName, &sfr), + resource.TestCheckResourceAttr(resourceName, "on_demand_fulfilled_capacity", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"wait_for_fulfillment"}, + }, + }, + }) +} + func TestAccAWSSpotFleetRequest_instanceInterruptionBehavior(t *testing.T) { var sfr ec2.SpotFleetRequestConfig rName := acctest.RandomWithPrefix("tf-acc-test") @@ -2857,3 +2885,35 @@ resource "aws_spot_fleet_request" "test" { } `, rName, validUntil, strategy) } + +func testAccAWSSpotFleetRequestOnDemandFulfilledCapacityConfig(rName, validUntil, capacity string) string { + return testAccAWSSpotFleetRequestConfigBase(rName) + + fmt.Sprintf(` +resource "aws_launch_template" "test" { + name = %[1]q + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = data.aws_ec2_instance_type_offering.available.instance_type + key_name = aws_key_pair.test.key_name +} + +resource "aws_spot_fleet_request" "test" { + iam_fleet_role = aws_iam_role.test.arn + spot_price = "0.005" + target_capacity = 2 + valid_until = %[2]q + terminate_instances_with_expiration = true + instance_interruption_behaviour = "stop" + wait_for_fulfillment = true + on_demand_fulfilled_capacity = %[3]q + + launch_template_config { + launch_template_specification { + name = aws_launch_template.test.name + version = aws_launch_template.test.latest_version + } + } + + depends_on = ["aws_iam_policy_attachment.test"] +} +`, rName, validUntil, capacity) +} From 114701f0259fbe381ec7c06923f202df359b1957 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 7 Aug 2020 00:48:44 +0300 Subject: [PATCH 0497/1208] remove fulfilled capacity --- aws/resource_aws_spot_fleet_request.go | 18 +------ aws/resource_aws_spot_fleet_request_test.go | 60 --------------------- 2 files changed, 2 insertions(+), 76 deletions(-) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index 15375366d6e9..b8cb369bdaa9 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -555,12 +555,6 @@ func resourceAwsSpotFleetRequest() *schema.Resource { ec2.OnDemandAllocationStrategyLowestPrice, }, false), }, - "on_demand_fulfilled_capacity": { - Type: schema.TypeFloat, - Optional: true, - ForceNew: true, - Computed: true, - }, "on_demand_max_total_price": { Type: schema.TypeString, Optional: true, @@ -1025,10 +1019,6 @@ func resourceAwsSpotFleetRequestCreate(d *schema.ResourceData, meta interface{}) spotFleetConfig.OnDemandMaxTotalPrice = aws.String(v.(string)) } - if v, ok := d.GetOk("on_demand_fulfilled_capacity"); ok { - spotFleetConfig.OnDemandFulfilledCapacity = aws.Float64(v.(float64)) - } - if v, ok := d.GetOk("valid_from"); ok { validFrom, err := time.Parse(time.RFC3339, v.(string)) if err != nil { @@ -1175,7 +1165,7 @@ func resourceAwsSpotFleetRequestStateRefreshFunc(d *schema.ResourceData, meta in spotFleetRequest := resp.SpotFleetRequestConfigs[0] - return spotFleetRequest, *spotFleetRequest.SpotFleetRequestState, nil + return spotFleetRequest, aws.StringValue(spotFleetRequest.SpotFleetRequestState), nil } } @@ -1200,7 +1190,7 @@ func resourceAwsSpotFleetRequestFulfillmentRefreshFunc(id string, conn *ec2.EC2) } cfg := resp.SpotFleetRequestConfigs[0] - status := *cfg.ActivityStatus + status := aws.StringValue(cfg.ActivityStatus) var fleetError error if status == ec2.ActivityStatusError { @@ -1363,10 +1353,6 @@ func resourceAwsSpotFleetRequestRead(d *schema.ResourceData, meta interface{}) e d.Set("on_demand_max_total_price", aws.StringValue(config.OnDemandMaxTotalPrice)) } - if config.OnDemandFulfilledCapacity != nil { - d.Set("on_demand_fulfilled_capacity", aws.Float64Value(config.OnDemandFulfilledCapacity)) - } - if config.LoadBalancersConfig != nil { lbConf := config.LoadBalancersConfig diff --git a/aws/resource_aws_spot_fleet_request_test.go b/aws/resource_aws_spot_fleet_request_test.go index 7617fee2c1ea..2de4a55b80c2 100644 --- a/aws/resource_aws_spot_fleet_request_test.go +++ b/aws/resource_aws_spot_fleet_request_test.go @@ -447,34 +447,6 @@ func TestAccAWSSpotFleetRequest_onDemandAllocationStrategy(t *testing.T) { }) } -func TestAccAWSSpotFleetRequest_onDemandFulfilledCapacity(t *testing.T) { - var sfr ec2.SpotFleetRequestConfig - rName := acctest.RandomWithPrefix("tf-acc-test") - validUntil := time.Now().UTC().Add(24 * time.Hour).Format(time.RFC3339) - resourceName := "aws_spot_fleet_request.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSSpotFleetRequestDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSSpotFleetRequestOnDemandFulfilledCapacityConfig(rName, validUntil, "2"), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSSpotFleetRequestExists(resourceName, &sfr), - resource.TestCheckResourceAttr(resourceName, "on_demand_fulfilled_capacity", "2"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"wait_for_fulfillment"}, - }, - }, - }) -} - func TestAccAWSSpotFleetRequest_instanceInterruptionBehavior(t *testing.T) { var sfr ec2.SpotFleetRequestConfig rName := acctest.RandomWithPrefix("tf-acc-test") @@ -2885,35 +2857,3 @@ resource "aws_spot_fleet_request" "test" { } `, rName, validUntil, strategy) } - -func testAccAWSSpotFleetRequestOnDemandFulfilledCapacityConfig(rName, validUntil, capacity string) string { - return testAccAWSSpotFleetRequestConfigBase(rName) + - fmt.Sprintf(` -resource "aws_launch_template" "test" { - name = %[1]q - image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id - instance_type = data.aws_ec2_instance_type_offering.available.instance_type - key_name = aws_key_pair.test.key_name -} - -resource "aws_spot_fleet_request" "test" { - iam_fleet_role = aws_iam_role.test.arn - spot_price = "0.005" - target_capacity = 2 - valid_until = %[2]q - terminate_instances_with_expiration = true - instance_interruption_behaviour = "stop" - wait_for_fulfillment = true - on_demand_fulfilled_capacity = %[3]q - - launch_template_config { - launch_template_specification { - name = aws_launch_template.test.name - version = aws_launch_template.test.latest_version - } - } - - depends_on = ["aws_iam_policy_attachment.test"] -} -`, rName, validUntil, capacity) -} From d538543464b4d367f5244b9967a2386dce8332ef Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 7 Aug 2020 01:02:04 +0300 Subject: [PATCH 0498/1208] remove fulfilled capacity --- website/docs/r/spot_fleet_request.html.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/website/docs/r/spot_fleet_request.html.markdown b/website/docs/r/spot_fleet_request.html.markdown index 70d0cba0481e..4feac1dec1f9 100644 --- a/website/docs/r/spot_fleet_request.html.markdown +++ b/website/docs/r/spot_fleet_request.html.markdown @@ -202,7 +202,6 @@ across different markets and instance types. Conflicts with `launch_template_con * `load_balancers` (Optional) A list of elastic load balancer names to add to the Spot fleet. * `target_group_arns` (Optional) A list of `aws_alb_target_group` ARNs, for use with Application Load Balancing. * `on_demand_allocation_strategy` - The order of the launch template overrides to use in fulfilling On-Demand capacity. the possible values are: `lowestPrice` and `prioritized`. the default is `lowestPrice`. -* `on_demand_fulfilled_capacity` - The number of On-Demand units fulfilled by this request compared to the set target On-Demand capacity. * `on_demand_max_total_price` - The maximum amount per hour for On-Demand Instances that you're willing to pay. When the maximum amount you're willing to pay is reached, the fleet stops launching instances even if it hasn’t met the target capacity. * `on_demand_target_capacity` - The number of On-Demand units to request. If the request type is `maintain`, you can specify a target capacity of 0 and add capacity later. * `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. From 9ccf51c10340f8919d976adac7f9a09e8a0bab79 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 15 Oct 2020 21:04:17 +0300 Subject: [PATCH 0499/1208] use enum slice --- aws/resource_aws_spot_fleet_request.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index b8cb369bdaa9..f70337df8419 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -546,14 +546,11 @@ func resourceAwsSpotFleetRequest() *schema.Resource { Set: schema.HashString, }, "on_demand_allocation_strategy": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: ec2.OnDemandAllocationStrategyLowestPrice, - ValidateFunc: validation.StringInSlice([]string{ - ec2.OnDemandAllocationStrategyPrioritized, - ec2.OnDemandAllocationStrategyLowestPrice, - }, false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: ec2.OnDemandAllocationStrategyLowestPrice, + ValidateFunc: validation.StringInSlice(ec2.OnDemandAllocationStrategy_Values(), false), }, "on_demand_max_total_price": { Type: schema.TypeString, From 9724cd791879bcb8c1f5b949928cbb225af8a360 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 5 Dec 2020 21:03:46 +0200 Subject: [PATCH 0500/1208] rebase --- aws/resource_aws_spot_fleet_request_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_spot_fleet_request_test.go b/aws/resource_aws_spot_fleet_request_test.go index 2de4a55b80c2..d1b5de2757ec 100644 --- a/aws/resource_aws_spot_fleet_request_test.go +++ b/aws/resource_aws_spot_fleet_request_test.go @@ -2763,7 +2763,7 @@ resource "aws_spot_fleet_request" "test" { } func testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName string, rInt int, validUntil string, targetCapacity int) string { - return testAccAWSSpotFleetRequestConfigBase(rName, rInt) + + return testAccAWSSpotFleetRequestConfigBase(rName) + fmt.Sprintf(` resource "aws_launch_template" "test" { name = %[1]q From 348e2525a8c0c21c82740b7390882c6760184904 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 5 Dec 2020 21:05:31 +0200 Subject: [PATCH 0501/1208] rebase --- aws/resource_aws_spot_fleet_request_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_spot_fleet_request_test.go b/aws/resource_aws_spot_fleet_request_test.go index d1b5de2757ec..85a3a70629db 100644 --- a/aws/resource_aws_spot_fleet_request_test.go +++ b/aws/resource_aws_spot_fleet_request_test.go @@ -2762,7 +2762,7 @@ resource "aws_spot_fleet_request" "test" { `, validUntil) } -func testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName string, rInt int, validUntil string, targetCapacity int) string { +func testAccAWSSpotFleetRequestOnDemandTargetCapacityConfig(rName string, validUntil string, targetCapacity int) string { return testAccAWSSpotFleetRequestConfigBase(rName) + fmt.Sprintf(` resource "aws_launch_template" "test" { From c99d2d8dad8dbb064e69820ae3138941fc4beeb9 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 5 Dec 2020 21:08:21 +0200 Subject: [PATCH 0502/1208] validations --- aws/resource_aws_spot_fleet_request.go | 54 +++++++++----------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index f70337df8419..e009907697b0 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -265,14 +265,10 @@ func resourceAwsSpotFleetRequest() *schema.Resource { ForceNew: true, }, "placement_tenancy": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - ec2.TenancyDefault, - ec2.TenancyDedicated, - ec2.TenancyHost, - }, false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.Tenancy_Values(), false), }, "spot_price": { Type: schema.TypeString, @@ -409,15 +405,11 @@ func resourceAwsSpotFleetRequest() *schema.Resource { ForceNew: false, }, "allocation_strategy": { - Type: schema.TypeString, - Optional: true, - Default: ec2.AllocationStrategyLowestPrice, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - ec2.AllocationStrategyLowestPrice, - ec2.AllocationStrategyDiversified, - ec2.AllocationStrategyCapacityOptimized, - }, false), + Type: schema.TypeString, + Optional: true, + Default: ec2.AllocationStrategyLowestPrice, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.AllocationStrategy_Values(), false), }, "instance_pools_to_use_count": { Type: schema.TypeInt, @@ -437,15 +429,11 @@ func resourceAwsSpotFleetRequest() *schema.Resource { }, false), }, "instance_interruption_behaviour": { - Type: schema.TypeString, - Optional: true, - Default: ec2.InstanceInterruptionBehaviorTerminate, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - ec2.InstanceInterruptionBehaviorTerminate, - ec2.InstanceInterruptionBehaviorStop, - ec2.InstanceInterruptionBehaviorHibernate, - }, false), + Type: schema.TypeString, + Optional: true, + Default: ec2.InstanceInterruptionBehaviorTerminate, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.InstanceInterruptionBehavior_Values(), false), }, "spot_price": { Type: schema.TypeString, @@ -470,15 +458,11 @@ func resourceAwsSpotFleetRequest() *schema.Resource { ValidateFunc: validation.IsRFC3339Time, }, "fleet_type": { - Type: schema.TypeString, - Optional: true, - Default: ec2.FleetTypeMaintain, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - ec2.FleetTypeMaintain, - ec2.FleetTypeRequest, - ec2.FleetTypeInstant, - }, false), + Type: schema.TypeString, + Optional: true, + Default: ec2.FleetTypeMaintain, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.FleetType_Values(), false), }, "spot_maintenance_strategies": { Type: schema.TypeList, From b10dea815111dd6e989580eb8f63c73f28fc5d3e Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 5 Dec 2020 21:21:42 +0200 Subject: [PATCH 0503/1208] add validations --- aws/resource_aws_spot_fleet_request.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index e009907697b0..00aa56b8199b 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -242,9 +242,10 @@ func resourceAwsSpotFleetRequest() *schema.Resource { ForceNew: true, }, "instance_type": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.InstanceType_Values(), false), }, "key_name": { Type: schema.TypeString, @@ -362,9 +363,10 @@ func resourceAwsSpotFleetRequest() *schema.Resource { ForceNew: true, }, "instance_type": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.InstanceType_Values(), false), }, "spot_price": { Type: schema.TypeString, @@ -489,12 +491,10 @@ func resourceAwsSpotFleetRequest() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "replacement_strategy": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - "launch", - }, false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.ReplacementStrategy_Values(), false), }, }, }, From 265ce5160ea18fdb6e5803a5154d9e97e311b6e9 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 11 Mar 2021 01:32:02 +0200 Subject: [PATCH 0504/1208] changelog --- .changelog/13127.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/13127.txt diff --git a/.changelog/13127.txt b/.changelog/13127.txt new file mode 100644 index 000000000000..896ccfac0de7 --- /dev/null +++ b/.changelog/13127.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_spot_fleet_request: Add plan time validation `instance_type` +``` + +```release-note:enhancement +resource/aws_spot_fleet_request: Add `on_demand_allocation_strategy`, `on_demand_max_total_price`, and `on_demand_target_capacity` arguments +``` \ No newline at end of file From 5aee072610586554bd04a797818a9973fac9bb03 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 27 Mar 2021 19:40:41 +0300 Subject: [PATCH 0505/1208] error check --- aws/resource_aws_spot_fleet_request_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aws/resource_aws_spot_fleet_request_test.go b/aws/resource_aws_spot_fleet_request_test.go index 85a3a70629db..518ac37d3149 100644 --- a/aws/resource_aws_spot_fleet_request_test.go +++ b/aws/resource_aws_spot_fleet_request_test.go @@ -357,6 +357,7 @@ func TestAccAWSSpotFleetRequest_onDemandTargetCapacity(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSpotFleetRequestDestroy, Steps: []resource.TestStep{ @@ -399,6 +400,7 @@ func TestAccAWSSpotFleetRequest_onDemandMaxTotalPrice(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSpotFleetRequestDestroy, Steps: []resource.TestStep{ @@ -427,6 +429,7 @@ func TestAccAWSSpotFleetRequest_onDemandAllocationStrategy(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSpotFleetRequestDestroy, Steps: []resource.TestStep{ From 0add81265535fb4f50b4b1fad6686214fc5b60f7 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 20:27:12 +0300 Subject: [PATCH 0506/1208] fmt --- aws/resource_aws_spot_fleet_request.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index 00aa56b8199b..5d6c76c42321 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -1081,7 +1081,7 @@ func resourceAwsSpotFleetRequestCreate(d *schema.ResourceData, meta interface{}) } if err != nil { - return fmt.Errorf("Error requesting spot fleet: %s", err) + return fmt.Errorf("Error requesting spot fleet: %w", err) } d.SetId(aws.StringValue(resp.SpotFleetRequestId)) @@ -1132,7 +1132,7 @@ func resourceAwsSpotFleetRequestStateRefreshFunc(d *schema.ResourceData, meta in resp, err := conn.DescribeSpotFleetRequests(req) if err != nil { - log.Printf("Error on retrieving Spot Fleet Request when waiting: %s", err) + log.Printf("Error on retrieving Spot Fleet Request when waiting: %w", err) return nil, "", nil } @@ -1158,7 +1158,7 @@ func resourceAwsSpotFleetRequestFulfillmentRefreshFunc(id string, conn *ec2.EC2) resp, err := conn.DescribeSpotFleetRequests(req) if err != nil { - log.Printf("Error on retrieving Spot Fleet Request when waiting: %s", err) + log.Printf("Error on retrieving Spot Fleet Request when waiting: %w", err) return nil, "", nil } @@ -1298,7 +1298,7 @@ func resourceAwsSpotFleetRequestRead(d *schema.ResourceData, meta interface{}) e launchSpec, err := launchSpecsToSet(config.LaunchSpecifications, conn) if err != nil { - return fmt.Errorf("error occurred while reading launch specification: %s", err) + return fmt.Errorf("error occurred while reading launch specification: %w", err) } d.Set("replace_unhealthy_instances", config.ReplaceUnhealthyInstances) @@ -1318,20 +1318,20 @@ func resourceAwsSpotFleetRequestRead(d *schema.ResourceData, meta interface{}) e if len(config.LaunchTemplateConfigs) > 0 { if err := d.Set("launch_template_config", flattenFleetLaunchTemplateConfig(config.LaunchTemplateConfigs)); err != nil { - return fmt.Errorf("error setting launch_template_config: %s", err) + return fmt.Errorf("error setting launch_template_config: %w", err) } } if config.OnDemandTargetCapacity != nil { - d.Set("on_demand_target_capacity", aws.Int64Value(config.OnDemandTargetCapacity)) + d.Set("on_demand_target_capacity", config.OnDemandTargetCapacity) } if config.OnDemandAllocationStrategy != nil { - d.Set("on_demand_allocation_strategy", aws.StringValue(config.OnDemandAllocationStrategy)) + d.Set("on_demand_allocation_strategy", config.OnDemandAllocationStrategy) } if config.OnDemandMaxTotalPrice != nil { - d.Set("on_demand_max_total_price", aws.StringValue(config.OnDemandMaxTotalPrice)) + d.Set("on_demand_max_total_price", config.OnDemandMaxTotalPrice) } if config.LoadBalancersConfig != nil { @@ -1353,7 +1353,7 @@ func resourceAwsSpotFleetRequestRead(d *schema.ResourceData, meta interface{}) e flatTgs = append(flatTgs, tg.Arn) } if err := d.Set("target_group_arns", flattenStringSet(flatTgs)); err != nil { - return fmt.Errorf("error setting target_group_arns: %s", err) + return fmt.Errorf("error setting target_group_arns: %w", err) } } } From 2976f491d2a569a12b62d2f184abe0f0dbb21735 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 20:28:55 +0300 Subject: [PATCH 0507/1208] fmt --- aws/resource_aws_spot_fleet_request.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index 5d6c76c42321..ec324fca79eb 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -1132,7 +1132,7 @@ func resourceAwsSpotFleetRequestStateRefreshFunc(d *schema.ResourceData, meta in resp, err := conn.DescribeSpotFleetRequests(req) if err != nil { - log.Printf("Error on retrieving Spot Fleet Request when waiting: %w", err) + log.Printf("Error on retrieving Spot Fleet Request when waiting: %s", err) return nil, "", nil } @@ -1158,7 +1158,7 @@ func resourceAwsSpotFleetRequestFulfillmentRefreshFunc(id string, conn *ec2.EC2) resp, err := conn.DescribeSpotFleetRequests(req) if err != nil { - log.Printf("Error on retrieving Spot Fleet Request when waiting: %w", err) + log.Printf("Error on retrieving Spot Fleet Request when waiting: %s", err) return nil, "", nil } @@ -1343,7 +1343,7 @@ func resourceAwsSpotFleetRequestRead(d *schema.ResourceData, meta interface{}) e flatLbs = append(flatLbs, lb.Name) } if err := d.Set("load_balancers", flattenStringSet(flatLbs)); err != nil { - return fmt.Errorf("error setting load_balancers: %s", err) + return fmt.Errorf("error setting load_balancers: %w", err) } } @@ -1641,7 +1641,7 @@ func resourceAwsSpotFleetRequestUpdate(d *schema.ResourceData, meta interface{}) if updateFlag { log.Printf("[DEBUG] Modifying Spot Fleet Request: %#v", req) if _, err := conn.ModifySpotFleetRequest(req); err != nil { - return fmt.Errorf("error updating spot request (%s): %s", d.Id(), err) + return fmt.Errorf("error updating spot request (%s): %w", d.Id(), err) } log.Println("[INFO] Waiting for Spot Fleet Request to be modified") @@ -1663,7 +1663,7 @@ func resourceAwsSpotFleetRequestUpdate(d *schema.ResourceData, meta interface{}) if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating tags: %s", err) + return fmt.Errorf("error updating tags: %w", err) } } @@ -1678,7 +1678,7 @@ func resourceAwsSpotFleetRequestDelete(d *schema.ResourceData, meta interface{}) log.Printf("[INFO] Cancelling spot fleet request: %s", d.Id()) err := deleteSpotFleetRequest(d.Id(), terminateInstances, d.Timeout(schema.TimeoutDelete), conn) if err != nil { - return fmt.Errorf("error deleting spot request (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting spot request (%s): %w", d.Id(), err) } return nil @@ -1704,7 +1704,7 @@ func deleteSpotFleetRequest(spotFleetRequestID string, terminateInstances bool, }) if err != nil || resp == nil { - return 0, fmt.Errorf("error reading Spot Fleet Instances (%s): %s", spotFleetRequestID, err) + return 0, fmt.Errorf("error reading Spot Fleet Instances (%s): %w", spotFleetRequestID, err) } return len(resp.ActiveInstances), nil From 721cbbe3305ae222d158d377965ca9253e630572 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 16 Jun 2021 15:06:25 -0400 Subject: [PATCH 0508/1208] r/aws_spot_fleet_request: Don't validate EC2 instance types. --- .changelog/13127.txt | 4 ---- aws/resource_aws_spot_fleet_request.go | 14 ++++++-------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.changelog/13127.txt b/.changelog/13127.txt index 896ccfac0de7..519a42cb1793 100644 --- a/.changelog/13127.txt +++ b/.changelog/13127.txt @@ -1,7 +1,3 @@ -```release-note:enhancement -resource/aws_spot_fleet_request: Add plan time validation `instance_type` -``` - ```release-note:enhancement resource/aws_spot_fleet_request: Add `on_demand_allocation_strategy`, `on_demand_max_total_price`, and `on_demand_target_capacity` arguments ``` \ No newline at end of file diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index ec324fca79eb..dd35a8622b9f 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -242,10 +242,9 @@ func resourceAwsSpotFleetRequest() *schema.Resource { ForceNew: true, }, "instance_type": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice(ec2.InstanceType_Values(), false), + Type: schema.TypeString, + Required: true, + ForceNew: true, }, "key_name": { Type: schema.TypeString, @@ -363,10 +362,9 @@ func resourceAwsSpotFleetRequest() *schema.Resource { ForceNew: true, }, "instance_type": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice(ec2.InstanceType_Values(), false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, }, "spot_price": { Type: schema.TypeString, From 41715c9f24642aa7d85e7a47c02857edd71177b7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 16 Jun 2021 15:41:46 -0400 Subject: [PATCH 0509/1208] r/aws_spot_fleet_request: Instead of 'd.GetOkExists', always set in value. Tidy up 'resourceAwsSpotFleetRequestUpdate'. --- aws/resource_aws_spot_fleet_request.go | 52 ++++++++------------------ 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/aws/resource_aws_spot_fleet_request.go b/aws/resource_aws_spot_fleet_request.go index dd35a8622b9f..2cd909d1ada1 100644 --- a/aws/resource_aws_spot_fleet_request.go +++ b/aws/resource_aws_spot_fleet_request.go @@ -986,9 +986,7 @@ func resourceAwsSpotFleetRequestCreate(d *schema.ResourceData, meta interface{}) spotFleetConfig.SpotPrice = aws.String(v.(string)) } - if v, ok := d.GetOkExists("on_demand_target_capacity"); ok { - spotFleetConfig.OnDemandTargetCapacity = aws.Int64(int64(v.(int))) - } + spotFleetConfig.OnDemandTargetCapacity = aws.Int64(int64(d.Get("on_demand_target_capacity").(int))) if v, ok := d.GetOk("on_demand_allocation_strategy"); ok { spotFleetConfig.OnDemandAllocationStrategy = aws.String(v.(string)) @@ -1320,17 +1318,9 @@ func resourceAwsSpotFleetRequestRead(d *schema.ResourceData, meta interface{}) e } } - if config.OnDemandTargetCapacity != nil { - d.Set("on_demand_target_capacity", config.OnDemandTargetCapacity) - } - - if config.OnDemandAllocationStrategy != nil { - d.Set("on_demand_allocation_strategy", config.OnDemandAllocationStrategy) - } - - if config.OnDemandMaxTotalPrice != nil { - d.Set("on_demand_max_total_price", config.OnDemandMaxTotalPrice) - } + d.Set("on_demand_target_capacity", config.OnDemandTargetCapacity) + d.Set("on_demand_allocation_strategy", config.OnDemandAllocationStrategy) + d.Set("on_demand_max_total_price", config.OnDemandMaxTotalPrice) if config.LoadBalancersConfig != nil { lbConf := config.LoadBalancersConfig @@ -1608,35 +1598,25 @@ func resourceAwsSpotFleetRequestUpdate(d *schema.ResourceData, meta interface{}) // http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifySpotFleetRequest.html conn := meta.(*AWSClient).ec2conn - req := &ec2.ModifySpotFleetRequestInput{ - SpotFleetRequestId: aws.String(d.Id()), - } - - updateFlag := false - - if d.HasChange("target_capacity") { - if val, ok := d.GetOkExists("target_capacity"); ok { - req.TargetCapacity = aws.Int64(int64(val.(int))) - updateFlag = true + if d.HasChangesExcept("tags", "tags_all") { + req := &ec2.ModifySpotFleetRequestInput{ + SpotFleetRequestId: aws.String(d.Id()), } - } - if d.HasChange("on_demand_target_capacity") { - if val, ok := d.GetOkExists("on_demand_target_capacity"); ok { - req.OnDemandTargetCapacity = aws.Int64(int64(val.(int))) - updateFlag = true + if d.HasChange("target_capacity") { + req.TargetCapacity = aws.Int64(int64(d.Get("target_capacity").(int))) } - } - if d.HasChange("excess_capacity_termination_policy") { - if val, ok := d.GetOk("excess_capacity_termination_policy"); ok { - req.ExcessCapacityTerminationPolicy = aws.String(val.(string)) + if d.HasChange("on_demand_target_capacity") { + req.OnDemandTargetCapacity = aws.Int64(int64(d.Get("on_demand_target_capacity").(int))) } - updateFlag = true - } + if d.HasChange("excess_capacity_termination_policy") { + if val, ok := d.GetOk("excess_capacity_termination_policy"); ok { + req.ExcessCapacityTerminationPolicy = aws.String(val.(string)) + } + } - if updateFlag { log.Printf("[DEBUG] Modifying Spot Fleet Request: %#v", req) if _, err := conn.ModifySpotFleetRequest(req); err != nil { return fmt.Errorf("error updating spot request (%s): %w", d.Id(), err) From ad9e989a5e7ee2964077f51580bd2264afe2ba79 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 16 Jun 2021 21:59:18 +0000 Subject: [PATCH 0510/1208] Update CHANGELOG.md for #19834 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3db2e05ccc4..04d280615d57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,15 +4,23 @@ FEATURES: * **New Data Source:** `aws_appmesh_virtual_service` ([#19774](https://github.com/hashicorp/terraform-provider-aws/issues/19774)) * **New Resource:** `aws_budgets_budget_action` ([#19554](https://github.com/hashicorp/terraform-provider-aws/issues/19554)) +* **New Resource:** `aws_route53_resolver_firewall_config` ([#18733](https://github.com/hashicorp/terraform-provider-aws/issues/18733)) ENHANCEMENTS: +* resource/aws_cloudwatch_log_metric_filter: Add support for `unit` in the `metric_transformation` block. ([#19804](https://github.com/hashicorp/terraform-provider-aws/issues/19804)) * resource/aws_datasync_location_nfs: Add `mount_options` argument. ([#19767](https://github.com/hashicorp/terraform-provider-aws/issues/19767)) * resource/aws_datasync_location_nfs: Add plan time validation for `on_prem_config.agent_arns`, `server_hostname`, and `subdirectory`. ([#19767](https://github.com/hashicorp/terraform-provider-aws/issues/19767)) * resource/aws_datasync_location_nfs: Add support for updating. ([#19767](https://github.com/hashicorp/terraform-provider-aws/issues/19767)) * resource/aws_ecs_cluster: Add plan time validation for `name`. ([#19785](https://github.com/hashicorp/terraform-provider-aws/issues/19785)) * resource/aws_ecs_cluster: Add support for `configuration`. ([#19785](https://github.com/hashicorp/terraform-provider-aws/issues/19785)) +BUG FIXES: + +* resource/aws_cognito_identity_provider: Fix updating `idp_identifiers` crash. ([#19819](https://github.com/hashicorp/terraform-provider-aws/issues/19819)) +* resource/aws_glue_trigger: Fix default timeouts for Create and Delete operations ([#19827](https://github.com/hashicorp/terraform-provider-aws/issues/19827)) +* resource/aws_sqs_queue: Correctly handle the default `kms_data_key_reuse_period_seconds` value of `300` for unencrypted queues ([#19834](https://github.com/hashicorp/terraform-provider-aws/issues/19834)) + ## 3.45.0 (June 10, 2021) FEATURES: From d2a7bb3868a75849af9cba30f1d9d665a74f835e Mon Sep 17 00:00:00 2001 From: FrancescoFucile-CAZ Date: Thu, 17 Jun 2021 11:46:21 +0100 Subject: [PATCH 0511/1208] add test for "update". --- ...ce_aws_cloudwatch_event_bus_policy_test.go | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index def6b086d397..d4df55f68bfa 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -38,6 +38,38 @@ func TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { }) } +func TestAccAWSCloudwatchEventBusPolicy_update(t *testing.T) { + resourceName := "aws_cloudwatch_event_bus_policy.test" + rstring := acctest.RandString(5) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventBusDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudwatchEventBusPolicyConfig(rstring), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), + testAccAWSCloudWatchEventBusPolicyDocument(resourceName), + ), + }, + { + Config: testAccAWSCloudwatchEventBusPolicyConfigUpdated(rstring), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), + testAccAWSCloudWatchEventBusPolicyDocument(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSCloudWatchEventBusPolicy_disappears(t *testing.T) { resourceName := "aws_cloudwatch_event_bus_policy.test" rstring := acctest.RandString(5) @@ -162,3 +194,47 @@ resource "aws_cloudwatch_event_bus_policy" "test" { } `, name) } + +func testAccAWSCloudwatchEventBusPolicyConfigUpdated(name string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q +} + +data "aws_iam_policy_document" "access" { + statement { + sid = "test-resource-policy-1" + effect = "Allow" + principals { + identifiers = ["ecs.amazonaws.com"] + type = "Service" + } + actions = [ + "events:PutEvents", + ] + resources = [ + aws_cloudwatch_event_bus.test.arn, + ] + } + statement { + sid = "test-resource-policy-2" + effect = "Allow" + principals { + identifiers = ["ecs.amazonaws.com"] + type = "Service" + } + actions = [ + "events:PutRule" + ] + resources = [ + aws_cloudwatch_event_bus.test.arn, + ] + } +} + +resource "aws_cloudwatch_event_bus_policy" "test" { + policy = data.aws_iam_policy_document.access.json + event_bus_name = aws_cloudwatch_event_bus.test.name +} +`, name) +} From d3e9ec01ecc9d34f9d7ebc7447c6a34b3450c0bb Mon Sep 17 00:00:00 2001 From: FrancescoFucile-CAZ Date: Thu, 17 Jun 2021 14:34:17 +0100 Subject: [PATCH 0512/1208] merge "update" test with "basic" test. --- ...ce_aws_cloudwatch_event_bus_policy_test.go | 29 ++----------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index d4df55f68bfa..fb4d2dd680c8 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -17,31 +17,6 @@ func TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { resourceName := "aws_cloudwatch_event_bus_policy.test" rstring := acctest.RandString(5) - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSCloudWatchEventBusDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSCloudwatchEventBusPolicyConfig(rstring), - Check: resource.ComposeTestCheckFunc( - testAccAWSCloudWatchEventBusPolicyDocument(resourceName), - testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccAWSCloudwatchEventBusPolicy_update(t *testing.T) { - resourceName := "aws_cloudwatch_event_bus_policy.test" - rstring := acctest.RandString(5) - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -55,7 +30,7 @@ func TestAccAWSCloudwatchEventBusPolicy_update(t *testing.T) { ), }, { - Config: testAccAWSCloudwatchEventBusPolicyConfigUpdated(rstring), + Config: testAccAWSCloudwatchEventBusPolicyConfigUpdate(rstring), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), testAccAWSCloudWatchEventBusPolicyDocument(resourceName), @@ -195,7 +170,7 @@ resource "aws_cloudwatch_event_bus_policy" "test" { `, name) } -func testAccAWSCloudwatchEventBusPolicyConfigUpdated(name string) string { +func testAccAWSCloudwatchEventBusPolicyConfigUpdate(name string) string { return fmt.Sprintf(` resource "aws_cloudwatch_event_bus" "test" { name = %[1]q From 31730bf34b64d0314eb03f2e68740c707abb1562 Mon Sep 17 00:00:00 2001 From: FrancescoFucile-CAZ Date: Thu, 17 Jun 2021 14:40:45 +0100 Subject: [PATCH 0513/1208] ducoment example for policy with multiple statements. --- .../cloudwatch_event_bus_policy.html.markdown | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/website/docs/r/cloudwatch_event_bus_policy.html.markdown b/website/docs/r/cloudwatch_event_bus_policy.html.markdown index 150290784bd6..2ba904fda18f 100644 --- a/website/docs/r/cloudwatch_event_bus_policy.html.markdown +++ b/website/docs/r/cloudwatch_event_bus_policy.html.markdown @@ -80,6 +80,60 @@ resource "aws_cloudwatch_event_bus_policy" "test" { } ``` +### Multiple Statements + +```hcl +data "aws_iam_policy_document" "test" { + + statement { + sid = "DevAccountAccess" + effect = "Allow" + actions = [ + "events:PutEvents", + ] + resources = [ + "arn:aws:events:eu-west-1:111111111111:event-bus/default" + ] + + principals { + type = "AWS" + identifiers = ["123456789012"] + } + } + + statement { + sid = "OrganizationAccess" + effect = "Allow" + actions = [ + "events:DescribeRule", + "events:ListRules", + "events:ListTargetsByRule", + "events:ListTagsForResource", + ] + resources = [ + "arn:aws:events:eu-west-1:11111111111111:rule/*", + "arn:aws:events:eu-west-1:111111111111:event-bus/default" + ] + + principals { + type = "AWS" + identifiers = ["*"] + } + + condition { + test = "StringEquals" + variable = "aws:PrincipalOrgID" + values = aws_organizations_organization.example.id + } + } +} + +resource "aws_cloudwatch_event_bus_policy" "test" { + policy = data.aws_iam_policy_document.access.json + event_bus_name = aws_cloudwatch_event_bus.test.name +} +``` + ## Argument Reference The following arguments are supported: From 9800bb06c1d22ff3d9135038da9208c9ba4c13f0 Mon Sep 17 00:00:00 2001 From: FrancescoFucile-CAZ Date: Thu, 17 Jun 2021 15:08:52 +0100 Subject: [PATCH 0514/1208] rename "eventBusPolicyResourcePolicyDocument". --- aws/resource_aws_cloudwatch_event_bus_policy_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index fb4d2dd680c8..7f3963a10ad7 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -109,8 +109,8 @@ func testAccAWSCloudWatchEventBusPolicyDocument(pr string) resource.TestCheckFun return fmt.Errorf("No ID is set") } - var policyFromState map[string]interface{} - err := json.Unmarshal([]byte(eventBusPolicyResource.Primary.Attributes["policy"]), &policyFromState) + var eventBusPolicyResourcePolicyDocument map[string]interface{} + err := json.Unmarshal([]byte(eventBusPolicyResource.Primary.Attributes["policy"]), &eventBusPolicyResourcePolicyDocument) eventBusName := eventBusPolicyResource.Primary.ID @@ -131,7 +131,7 @@ func testAccAWSCloudWatchEventBusPolicyDocument(pr string) resource.TestCheckFun return fmt.Errorf("Not found: %s", pr) } - if !reflect.DeepEqual(describedEventBusPolicy, policyFromState) { + if !reflect.DeepEqual(describedEventBusPolicy, eventBusPolicyResourcePolicyDocument) { return fmt.Errorf("CloudWatch Events bus policy mismatch for '%s'", pr) } From a8398feb30a51db3da20ae02371eccad610fc83b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 11:06:45 -0400 Subject: [PATCH 0515/1208] Add CHANGELOG entry. --- .changelog/19810.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19810.txt diff --git a/.changelog/19810.txt b/.changelog/19810.txt new file mode 100644 index 000000000000..738092c4cd3e --- /dev/null +++ b/.changelog/19810.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_eks_node_group: Allow minimum value of `0` for `desired_size` and `min_size` in the `scaling_config` configuration block +``` \ No newline at end of file From a69fd497dcedbb5a7d040f1418b96aa5e15309e7 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 16:06:37 -0400 Subject: [PATCH 0516/1208] r/lakeformation_perm: Fix update bug --- aws/resource_aws_lakeformation_permissions.go | 115 +++++++++++++----- 1 file changed, 87 insertions(+), 28 deletions(-) diff --git a/aws/resource_aws_lakeformation_permissions.go b/aws/resource_aws_lakeformation_permissions.go index 23286da77b8b..2d39193cc94f 100644 --- a/aws/resource_aws_lakeformation_permissions.go +++ b/aws/resource_aws_lakeformation_permissions.go @@ -21,7 +21,6 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { return &schema.Resource{ Create: resourceAwsLakeFormationPermissionsCreate, Read: resourceAwsLakeFormationPermissionsRead, - Update: resourceAwsLakeFormationPermissionsCreate, Delete: resourceAwsLakeFormationPermissionsDelete, Schema: map[string]*schema.Schema{ @@ -33,8 +32,9 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { }, "catalog_resource": { Type: schema.TypeBool, - Optional: true, Default: false, + ForceNew: true, + Optional: true, ExactlyOneOf: []string{ "catalog_resource", "data_location", @@ -45,9 +45,10 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { }, "data_location": { Type: schema.TypeList, - Optional: true, Computed: true, + ForceNew: true, MaxItems: 1, + Optional: true, ExactlyOneOf: []string{ "catalog_resource", "data_location", @@ -59,13 +60,15 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { Schema: map[string]*schema.Schema{ "arn": { Type: schema.TypeString, + ForceNew: true, Required: true, ValidateFunc: validateArn, }, "catalog_id": { Type: schema.TypeString, - Optional: true, Computed: true, + ForceNew: true, + Optional: true, ValidateFunc: validateAwsAccountId, }, }, @@ -73,9 +76,10 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { }, "database": { Type: schema.TypeList, - Optional: true, Computed: true, + ForceNew: true, MaxItems: 1, + Optional: true, ExactlyOneOf: []string{ "catalog_resource", "data_location", @@ -87,12 +91,14 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { Schema: map[string]*schema.Schema{ "catalog_id": { Type: schema.TypeString, - Optional: true, Computed: true, + ForceNew: true, + Optional: true, ValidateFunc: validateAwsAccountId, }, "name": { Type: schema.TypeString, + ForceNew: true, Required: true, }, }, @@ -100,9 +106,9 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { }, "permissions": { Type: schema.TypeList, - Required: true, ForceNew: true, MinItems: 1, + Required: true, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.StringInSlice(lakeformation.Permission_Values(), false), @@ -110,9 +116,9 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { }, "permissions_with_grant_option": { Type: schema.TypeList, - Optional: true, - ForceNew: true, Computed: true, + ForceNew: true, + Optional: true, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.StringInSlice(lakeformation.Permission_Values(), false), @@ -120,15 +126,16 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { }, "principal": { Type: schema.TypeString, - Required: true, ForceNew: true, + Required: true, ValidateFunc: validatePrincipal, }, "table": { Type: schema.TypeList, - Optional: true, Computed: true, + ForceNew: true, MaxItems: 1, + Optional: true, ExactlyOneOf: []string{ "catalog_resource", "data_location", @@ -140,18 +147,21 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { Schema: map[string]*schema.Schema{ "catalog_id": { Type: schema.TypeString, - Optional: true, Computed: true, + ForceNew: true, + Optional: true, ValidateFunc: validateAwsAccountId, }, "database_name": { Type: schema.TypeString, + ForceNew: true, Required: true, }, "name": { Type: schema.TypeString, - Optional: true, Computed: true, + ForceNew: true, + Optional: true, AtLeastOneOf: []string{ "table.0.name", "table.0.wildcard", @@ -159,8 +169,9 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { }, "wildcard": { Type: schema.TypeBool, - Optional: true, Default: false, + ForceNew: true, + Optional: true, AtLeastOneOf: []string{ "table.0.name", "table.0.wildcard", @@ -171,9 +182,10 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { }, "table_with_columns": { Type: schema.TypeList, - Optional: true, Computed: true, + ForceNew: true, MaxItems: 1, + Optional: true, ExactlyOneOf: []string{ "catalog_resource", "data_location", @@ -185,13 +197,16 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { Schema: map[string]*schema.Schema{ "catalog_id": { Type: schema.TypeString, - Optional: true, Computed: true, + ForceNew: true, + Optional: true, ValidateFunc: validateAwsAccountId, }, "column_names": { - Type: schema.TypeList, + Type: schema.TypeSet, + ForceNew: true, Optional: true, + Set: schema.HashString, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, @@ -203,11 +218,14 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { }, "database_name": { Type: schema.TypeString, + ForceNew: true, Required: true, }, "excluded_column_names": { - Type: schema.TypeList, + Type: schema.TypeSet, + ForceNew: true, Optional: true, + Set: schema.HashString, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, @@ -215,12 +233,14 @@ func resourceAwsLakeFormationPermissions() *schema.Resource { }, "name": { Type: schema.TypeString, + ForceNew: true, Required: true, }, "wildcard": { Type: schema.TypeBool, - Optional: true, Default: false, + ForceNew: true, + Optional: true, AtLeastOneOf: []string{ "table_with_columns.0.column_names", "table_with_columns.0.wildcard", @@ -405,18 +425,33 @@ func resourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta interf if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, lakeformation.ErrCodeEntityNotFoundException) { log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state", d.Id()) d.SetId("") + + if true { + return fmt.Errorf("death note: %d", 1) + } + return nil } if !d.IsNewResource() && tfawserr.ErrMessageContains(err, "AccessDeniedException", "Resource does not exist") { log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state: %s", d.Id(), err) d.SetId("") + + if true { + return fmt.Errorf("death note: %d", 2) + } + return nil } if !d.IsNewResource() && len(allPermissions) == 0 { log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state (0 permissions)", d.Id()) d.SetId("") + + if true { + return fmt.Errorf("death note: %d", 3) + } + return nil } @@ -449,11 +484,26 @@ func resourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta interf } if tableType == TableTypeTableWithColumns { + columnNames := make([]*string, 0) + excludedColumnNames := make([]*string, 0) + + if v, ok := d.GetOk("table_with_columns.0.column_names"); ok { + if v, ok := v.(*schema.Set); ok && v.Len() > 0 { + columnNames = expandStringSet(v) + } + } + + if v, ok := d.GetOk("table_with_columns.0.excluded_column_names"); ok { + if v, ok := v.(*schema.Set); ok && v.Len() > 0 { + excludedColumnNames = expandStringSet(v) + } + } + cleanPermissions = filterLakeFormationTableWithColumnsPermissions( d.Get("table_with_columns.0.database_name").(string), d.Get("table_with_columns.0.wildcard").(bool), - expandStringList(d.Get("table_with_columns.0.column_names").([]interface{})), - expandStringList(d.Get("table_with_columns.0.excluded_column_names").([]interface{})), + columnNames, + excludedColumnNames, allPermissions, ) } @@ -461,6 +511,11 @@ func resourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta interf if len(cleanPermissions) == 0 { log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state", d.Id()) d.SetId("") + + if true { + return fmt.Errorf("death note: %d, %v", 4, allPermissions) + } + return nil } @@ -887,17 +942,21 @@ func expandLakeFormationTableWithColumnsResource(tfMap map[string]interface{}) * apiObject.CatalogId = aws.String(v) } - if v, ok := tfMap["column_names"]; ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - apiObject.ColumnNames = expandStringList(v.([]interface{})) + if v, ok := tfMap["column_names"]; ok { + if v, ok := v.(*schema.Set); ok && v.Len() > 0 { + apiObject.ColumnNames = expandStringSet(v) + } } if v, ok := tfMap["database_name"].(string); ok && v != "" { apiObject.DatabaseName = aws.String(v) } - if v, ok := tfMap["excluded_column_names"]; ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - apiObject.ColumnWildcard = &lakeformation.ColumnWildcard{ - ExcludedColumnNames: expandStringList(v.([]interface{})), + if v, ok := tfMap["excluded_column_names"]; ok { + if v, ok := v.(*schema.Set); ok && v.Len() > 0 { + apiObject.ColumnWildcard = &lakeformation.ColumnWildcard{ + ExcludedColumnNames: expandStringSet(v), + } } } @@ -923,7 +982,7 @@ func flattenLakeFormationTableWithColumnsResource(apiObject *lakeformation.Table tfMap["catalog_id"] = aws.StringValue(v) } - tfMap["column_names"] = flattenStringList(apiObject.ColumnNames) + tfMap["column_names"] = flattenStringSet(apiObject.ColumnNames) if v := apiObject.DatabaseName; v != nil { tfMap["database_name"] = aws.StringValue(v) @@ -931,7 +990,7 @@ func flattenLakeFormationTableWithColumnsResource(apiObject *lakeformation.Table if v := apiObject.ColumnWildcard; v != nil { tfMap["wildcard"] = true - tfMap["excluded_column_names"] = flattenStringList(v.ExcludedColumnNames) + tfMap["excluded_column_names"] = flattenStringSet(v.ExcludedColumnNames) } if v := apiObject.Name; v != nil { From be4898398c47423e9709036d41849d23e50c4039 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 16:07:29 -0400 Subject: [PATCH 0517/1208] tests/r/lakeformation_perm: Test bug fix --- ...urce_aws_lakeformation_permissions_test.go | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_lakeformation_permissions_test.go b/aws/resource_aws_lakeformation_permissions_test.go index 69857161931f..89d32b05a3c4 100644 --- a/aws/resource_aws_lakeformation_permissions_test.go +++ b/aws/resource_aws_lakeformation_permissions_test.go @@ -169,7 +169,7 @@ func testAccAWSLakeFormationPermissions_tableWithColumns(t *testing.T) { CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName), + Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName, "\"event\", \"timestamp\""), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), @@ -183,6 +183,51 @@ func testAccAWSLakeFormationPermissions_tableWithColumns(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), ), }, + { + Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName, "\"timestamp\", \"event\""), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "2"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.1", "timestamp"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), + ), + }, + { + Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName, "\"timestamp\", \"event\", \"transactionamount\""), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "3"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.1", "timestamp"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.2", "transactionamount"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), + ), + }, + { + Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName, "\"event\""), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "1"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), + ), + }, }, }) } @@ -806,7 +851,7 @@ resource "aws_lakeformation_permissions" "test" { `, rName) } -func testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName string) string { +func testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName string, columns string) string { return fmt.Sprintf(` data "aws_partition" "current" {} @@ -853,7 +898,7 @@ resource "aws_glue_catalog_table" "test" { } columns { - name = "value" + name = "transactionamount" type = "double" } } @@ -870,13 +915,13 @@ resource "aws_lakeformation_permissions" "test" { table_with_columns { database_name = aws_glue_catalog_table.test.database_name name = aws_glue_catalog_table.test.name - column_names = ["event", "timestamp"] + column_names = [%[2]s] } # for consistency, ensure that admins are setup before testing depends_on = [aws_lakeformation_data_lake_settings.test] } -`, rName) +`, rName, columns) } func testAccAWSLakeFormationPermissionsConfig_implicitTableWithColumnsPermissions(rName string) string { From a0cb7b1da4efa4fcb35b376856762ff5bb85ea80 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 16:08:12 -0400 Subject: [PATCH 0518/1208] docs/r/lakeformation_perm: Update docs --- website/docs/r/lakeformation_permissions.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index 4d824c32c6e0..391916f2cef8 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -99,7 +99,7 @@ The following arguments are optional: The following arguments are required: -* `column_names` - (Required, at least one of `column_names` or `wildcard`) List of column names for the table. +* `column_names` - (Required, at least one of `column_names` or `wildcard`) Set of column names for the table. * `database_name` – (Required) Name of the database for the table with columns resource. Unique to the Data Catalog. * `name` – (Required) Name of the table resource. * `wildcard` - (Required, at least one of `column_names` or `wildcard`) Whether to use a column wildcard. If `excluded_column_names` is included, `wildcard` must be set to `true` to avoid Terraform reporting a difference. @@ -107,7 +107,7 @@ The following arguments are required: The following arguments are optional: * `catalog_id` - (Optional) Identifier for the Data Catalog. By default, it is the account ID of the caller. -* `excluded_column_names` - (Optional) List of column names for the table to exclude. If `excluded_column_names` is included, `wildcard` must be set to `true` to avoid Terraform reporting a difference. +* `excluded_column_names` - (Optional) Set of column names for the table to exclude. If `excluded_column_names` is included, `wildcard` must be set to `true` to avoid Terraform reporting a difference. ## Attributes Reference From f9f91a023a4a82bca6673b8bae91d40c1b93dbee Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 16:10:24 -0400 Subject: [PATCH 0519/1208] r/lakeformation_perm: Add changelog --- .changelog/19817.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19817.txt diff --git a/.changelog/19817.txt b/.changelog/19817.txt new file mode 100644 index 000000000000..9bd9e76d960b --- /dev/null +++ b/.changelog/19817.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_lakeformation_permissions: Fix bug preventing updates (inconsistent result) +``` \ No newline at end of file From a9d025a5b5c1c2c87f9fb08378c6c27d07f75726 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 15:54:42 -0400 Subject: [PATCH 0520/1208] r/lakeformation_perms: Update changelog --- .changelog/19817.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.changelog/19817.txt b/.changelog/19817.txt index 9bd9e76d960b..4ef139133bc3 100644 --- a/.changelog/19817.txt +++ b/.changelog/19817.txt @@ -1,3 +1,15 @@ ```release-note:bug resource/aws_lakeformation_permissions: Fix bug preventing updates (inconsistent result) +``` + +```release-note:bug +resource/aws_lakeformation_permissions: Fix bug where resource is not properly removed from state +``` + +```release-note:bug +resource/aws_lakeformation_permissions: Fix diffs resulting only from order of column names and exclude column names +``` + +```release-note:bug +data-source/aws_lakeformation_permissions: Fix diffs resulting from order of column names and exclude column names ``` \ No newline at end of file From 3d3e0c19bc6fc3aa8f32faad36dc6c22e23726e3 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 15:55:25 -0400 Subject: [PATCH 0521/1208] ds/lakeformation_perms: Fix list order diffs --- ...ta_source_aws_lakeformation_permissions.go | 98 ++++++------------- 1 file changed, 30 insertions(+), 68 deletions(-) diff --git a/aws/data_source_aws_lakeformation_permissions.go b/aws/data_source_aws_lakeformation_permissions.go index 2529d491d12b..9a9c48e777c9 100644 --- a/aws/data_source_aws_lakeformation_permissions.go +++ b/aws/data_source_aws_lakeformation_permissions.go @@ -6,13 +6,11 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/lakeformation" - "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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/hashcode" - iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" + tflakeformation "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lakeformation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lakeformation/waiter" ) func dataSourceAwsLakeFormationPermissions() *schema.Resource { @@ -134,8 +132,9 @@ func dataSourceAwsLakeFormationPermissions() *schema.Resource { ValidateFunc: validateAwsAccountId, }, "column_names": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, + Set: schema.HashString, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, @@ -146,8 +145,9 @@ func dataSourceAwsLakeFormationPermissions() *schema.Resource { Required: true, }, "excluded_column_names": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, + Set: schema.HashString, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.NoZeroValues, @@ -198,89 +198,49 @@ func dataSourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta inte if v, ok := d.GetOk("table"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.Resource.Table = expandLakeFormationTableResource(v.([]interface{})[0].(map[string]interface{})) - tableType = TableTypeTable + tableType = tflakeformation.TableTypeTable } if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { // can't ListPermissions for TableWithColumns, so use Table instead input.Resource.Table = expandLakeFormationTableWithColumnsResourceAsTable(v.([]interface{})[0].(map[string]interface{})) - tableType = TableTypeTableWithColumns + tableType = tflakeformation.TableTypeTableWithColumns } - log.Printf("[DEBUG] Reading Lake Formation permissions: %v", input) - var allPermissions []*lakeformation.PrincipalResourcePermissions - - err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { - err := conn.ListPermissionsPages(input, func(resp *lakeformation.ListPermissionsOutput, lastPage bool) bool { - for _, permission := range resp.PrincipalResourcePermissions { - if permission == nil { - continue - } + columnNames := make([]*string, 0) + excludedColumnNames := make([]*string, 0) + columnWildcard := false - allPermissions = append(allPermissions, permission) - } - return !lastPage - }) + if tableType == tflakeformation.TableTypeTableWithColumns { + if v, ok := d.GetOk("table_with_columns.0.wildcard"); ok { + columnWildcard = v.(bool) + } - if err != nil { - if tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "Invalid principal") { - return resource.RetryableError(err) + if v, ok := d.GetOk("table_with_columns.0.column_names"); ok { + if v, ok := v.(*schema.Set); ok && v.Len() > 0 { + columnNames = expandStringSet(v) } - return resource.NonRetryableError(fmt.Errorf("error reading Lake Formation Permissions: %w", err)) } - return nil - }) - - if tfresource.TimedOut(err) { - err = conn.ListPermissionsPages(input, func(resp *lakeformation.ListPermissionsOutput, lastPage bool) bool { - for _, permission := range resp.PrincipalResourcePermissions { - if permission == nil { - continue - } - allPermissions = append(allPermissions, permission) + if v, ok := d.GetOk("table_with_columns.0.excluded_column_names"); ok { + if v, ok := v.(*schema.Set); ok && v.Len() > 0 { + excludedColumnNames = expandStringSet(v) } - return !lastPage - }) + } } + log.Printf("[DEBUG] Reading Lake Formation permissions: %v", input) + + allPermissions, err := waiter.PermissionsReady(conn, input, tableType, columnNames, excludedColumnNames, columnWildcard) + d.SetId(fmt.Sprintf("%d", hashcode.String(input.String()))) if err != nil { return fmt.Errorf("error reading Lake Formation permissions: %w", err) } - var cleanPermissions []*lakeformation.PrincipalResourcePermissions - - if input.Resource.Catalog != nil { - cleanPermissions = filterLakeFormationCatalogPermissions(allPermissions) - } - - if input.Resource.DataLocation != nil { - cleanPermissions = filterLakeFormationDataLocationPermissions(allPermissions) - } - - if input.Resource.Database != nil { - cleanPermissions = filterLakeFormationDatabasePermissions(allPermissions) - } - - if tableType == TableTypeTable { - cleanPermissions = filterLakeFormationTablePermissions( - aws.StringValue(input.Resource.Table.Name), - input.Resource.Table.TableWildcard != nil, - allPermissions, - ) - } - - if tableType == TableTypeTableWithColumns { - cleanPermissions = filterLakeFormationTableWithColumnsPermissions( - d.Get("table_with_columns.0.database_name").(string), - d.Get("table_with_columns.0.wildcard").(bool), - expandStringList(d.Get("table_with_columns.0.column_names").([]interface{})), - expandStringList(d.Get("table_with_columns.0.excluded_column_names").([]interface{})), - allPermissions, - ) - } + // clean permissions = filter out permissions that do not pertain to this specific resource + cleanPermissions := tflakeformation.FilterPermissions(input, tableType, columnNames, excludedColumnNames, columnWildcard, allPermissions) if len(cleanPermissions) != len(allPermissions) { log.Printf("[INFO] Resource Lake Formation clean permissions (%d) and all permissions (%d) have different lengths (this is not necessarily a problem): %s", len(cleanPermissions), len(allPermissions), d.Id()) @@ -292,6 +252,8 @@ func dataSourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta inte if cleanPermissions[0].Resource.Catalog != nil { d.Set("catalog_resource", true) + } else { + d.Set("catalog_resource", false) } if cleanPermissions[0].Resource.DataLocation != nil { From 69fc95b688972f6a6b02c3ad8dede5a3c68ddd9c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 15:56:09 -0400 Subject: [PATCH 0522/1208] r/lakeformation_perms: Enable cross package use of filter --- aws/resource_aws_lakeformation_permissions.go | 294 ++++-------------- 1 file changed, 67 insertions(+), 227 deletions(-) diff --git a/aws/resource_aws_lakeformation_permissions.go b/aws/resource_aws_lakeformation_permissions.go index 2d39193cc94f..3351f47237ab 100644 --- a/aws/resource_aws_lakeformation_permissions.go +++ b/aws/resource_aws_lakeformation_permissions.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "reflect" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/lakeformation" @@ -14,6 +13,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + tflakeformation "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lakeformation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lakeformation/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -376,83 +377,59 @@ func resourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta interf if v, ok := d.GetOk("table"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.Resource.Table = expandLakeFormationTableResource(v.([]interface{})[0].(map[string]interface{})) - tableType = TableTypeTable + tableType = tflakeformation.TableTypeTable } if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { // can't ListPermissions for TableWithColumns, so use Table instead input.Resource.Table = expandLakeFormationTableWithColumnsResourceAsTable(v.([]interface{})[0].(map[string]interface{})) - tableType = TableTypeTableWithColumns + tableType = tflakeformation.TableTypeTableWithColumns } - log.Printf("[DEBUG] Reading Lake Formation permissions: %v", input) - var allPermissions []*lakeformation.PrincipalResourcePermissions - - err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { - err := conn.ListPermissionsPages(input, func(resp *lakeformation.ListPermissionsOutput, lastPage bool) bool { - for _, permission := range resp.PrincipalResourcePermissions { - if permission == nil { - continue - } + columnNames := make([]*string, 0) + excludedColumnNames := make([]*string, 0) + columnWildcard := false - allPermissions = append(allPermissions, permission) - } - return !lastPage - }) + if tableType == tflakeformation.TableTypeTableWithColumns { + if v, ok := d.GetOk("table_with_columns.0.wildcard"); ok { + columnWildcard = v.(bool) + } - if err != nil { - if tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "Invalid principal") { - return resource.RetryableError(err) + if v, ok := d.GetOk("table_with_columns.0.column_names"); ok { + if v, ok := v.(*schema.Set); ok && v.Len() > 0 { + columnNames = expandStringSet(v) } - return resource.NonRetryableError(fmt.Errorf("error reading Lake Formation Permissions: %w", err)) } - return nil - }) - if tfresource.TimedOut(err) { - err = conn.ListPermissionsPages(input, func(resp *lakeformation.ListPermissionsOutput, lastPage bool) bool { - for _, permission := range resp.PrincipalResourcePermissions { - if permission == nil { - continue - } - - allPermissions = append(allPermissions, permission) + if v, ok := d.GetOk("table_with_columns.0.excluded_column_names"); ok { + if v, ok := v.(*schema.Set); ok && v.Len() > 0 { + excludedColumnNames = expandStringSet(v) } - return !lastPage - }) - } - - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, lakeformation.ErrCodeEntityNotFoundException) { - log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state", d.Id()) - d.SetId("") - - if true { - return fmt.Errorf("death note: %d", 1) } - - return nil } - if !d.IsNewResource() && tfawserr.ErrMessageContains(err, "AccessDeniedException", "Resource does not exist") { - log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state: %s", d.Id(), err) - d.SetId("") + log.Printf("[DEBUG] Reading Lake Formation permissions: %v", input) - if true { - return fmt.Errorf("death note: %d", 2) - } + allPermissions, err := waiter.PermissionsReady(conn, input, tableType, columnNames, excludedColumnNames, columnWildcard) - return nil - } - - if !d.IsNewResource() && len(allPermissions) == 0 { - log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state (0 permissions)", d.Id()) - d.SetId("") + if !d.IsNewResource() { + if tfawserr.ErrCodeEquals(err, lakeformation.ErrCodeEntityNotFoundException) { + log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } - if true { - return fmt.Errorf("death note: %d", 3) + if tfawserr.ErrMessageContains(err, "AccessDeniedException", "Resource does not exist") { + log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state: %s", d.Id(), err) + d.SetId("") + return nil } - return nil + if len(allPermissions) == 0 { + log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state (0 permissions)", d.Id()) + d.SetId("") + return nil + } } if err != nil { @@ -460,62 +437,15 @@ func resourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta interf } // clean permissions = filter out permissions that do not pertain to this specific resource - - var cleanPermissions []*lakeformation.PrincipalResourcePermissions - - if input.Resource.Catalog != nil { - cleanPermissions = filterLakeFormationCatalogPermissions(allPermissions) - } - - if input.Resource.DataLocation != nil { - cleanPermissions = filterLakeFormationDataLocationPermissions(allPermissions) - } - - if input.Resource.Database != nil { - cleanPermissions = filterLakeFormationDatabasePermissions(allPermissions) - } - - if tableType == TableTypeTable { - cleanPermissions = filterLakeFormationTablePermissions( - aws.StringValue(input.Resource.Table.Name), - input.Resource.Table.TableWildcard != nil, - allPermissions, - ) - } - - if tableType == TableTypeTableWithColumns { - columnNames := make([]*string, 0) - excludedColumnNames := make([]*string, 0) - - if v, ok := d.GetOk("table_with_columns.0.column_names"); ok { - if v, ok := v.(*schema.Set); ok && v.Len() > 0 { - columnNames = expandStringSet(v) - } - } - - if v, ok := d.GetOk("table_with_columns.0.excluded_column_names"); ok { - if v, ok := v.(*schema.Set); ok && v.Len() > 0 { - excludedColumnNames = expandStringSet(v) - } - } - - cleanPermissions = filterLakeFormationTableWithColumnsPermissions( - d.Get("table_with_columns.0.database_name").(string), - d.Get("table_with_columns.0.wildcard").(bool), - columnNames, - excludedColumnNames, - allPermissions, - ) - } + cleanPermissions := tflakeformation.FilterPermissions(input, tableType, columnNames, excludedColumnNames, columnWildcard, allPermissions) if len(cleanPermissions) == 0 { - log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state", d.Id()) - d.SetId("") - - if true { - return fmt.Errorf("death note: %d, %v", 4, allPermissions) - } - + log.Printf("[WARN] No Lake Formation permissions (%s) found", d.Id()) + d.Set("catalog_resource", false) + d.Set("data_location", nil) + d.Set("database", nil) + d.Set("table_with_columns", nil) + d.Set("table", nil) return nil } @@ -529,6 +459,8 @@ func resourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta interf if cleanPermissions[0].Resource.Catalog != nil { d.Set("catalog_resource", true) + } else { + d.Set("catalog_resource", false) } if cleanPermissions[0].Resource.DataLocation != nil { @@ -592,7 +524,8 @@ func resourceAwsLakeFormationPermissionsDelete(d *schema.ResourceData, meta inte conn := meta.(*AWSClient).lakeformationconn input := &lakeformation.RevokePermissionsInput{ - Permissions: expandStringList(d.Get("permissions").([]interface{})), + Permissions: expandStringList(d.Get("permissions").([]interface{})), + PermissionsWithGrantOption: expandStringList(d.Get("permissions_with_grant_option").([]interface{})), Principal: &lakeformation.DataLakePrincipal{ DataLakePrincipalIdentifier: aws.String(d.Get("principal").(string)), }, @@ -603,10 +536,6 @@ func resourceAwsLakeFormationPermissionsDelete(d *schema.ResourceData, meta inte input.CatalogId = aws.String(v.(string)) } - if v, ok := d.GetOk("permissions_with_grant_option"); ok { - input.PermissionsWithGrantOption = expandStringList(v.([]interface{})) - } - if _, ok := d.GetOk("catalog_resource"); ok { input.Resource.Catalog = expandLakeFormationCatalogResource() } @@ -633,7 +562,7 @@ func resourceAwsLakeFormationPermissionsDelete(d *schema.ResourceData, meta inte return nil } - err := resource.Retry(2*time.Minute, func() *resource.RetryError { + err := resource.Retry(waiter.PermissionsDeleteRetryTimeout, func() *resource.RetryError { var err error _, err = conn.RevokePermissions(input) if err != nil { @@ -656,127 +585,38 @@ func resourceAwsLakeFormationPermissionsDelete(d *schema.ResourceData, meta inte _, err = conn.RevokePermissions(input) } - if err != nil { - return fmt.Errorf("unable to revoke LakeFormation Permissions (input: %v): %w", input, err) - } - - return nil -} - -const ( - TableNameAllTables = "ALL_TABLES" - TableTypeTable = "Table" - TableTypeTableWithColumns = "TableWithColumns" -) - -func filterLakeFormationTablePermissions(tableName string, tableWildcard bool, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { - // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on Table, Name = (Table Name) - // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) - // LIST PERMS = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard - - // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on Table, TableWildcard - // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, TableWildcard, Name = ALL_TABLES - // LIST PERMS = SELECT on TableWithColumns, Name = ALL_TABLES, ColumnWildcard - - var cleanPermissions []*lakeformation.PrincipalResourcePermissions - - for _, perm := range allPermissions { - if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnWildcard != nil { - if aws.StringValue(perm.Resource.TableWithColumns.Name) == tableName || (tableWildcard && aws.StringValue(perm.Resource.TableWithColumns.Name) == TableNameAllTables) { - if len(perm.Permissions) > 0 && aws.StringValue(perm.Permissions[0]) == lakeformation.PermissionSelect { - cleanPermissions = append(cleanPermissions, perm) - continue - } - - if len(perm.PermissionsWithGrantOption) > 0 && aws.StringValue(perm.PermissionsWithGrantOption[0]) == lakeformation.PermissionSelect { - cleanPermissions = append(cleanPermissions, perm) - continue - } - } - } - - if perm.Resource.Table != nil { - if aws.StringValue(perm.Resource.Table.Name) == tableName { - cleanPermissions = append(cleanPermissions, perm) - continue - } - - if perm.Resource.Table.TableWildcard != nil && tableWildcard { - cleanPermissions = append(cleanPermissions, perm) - continue - } - } - continue + if tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "No permissions revoked. Grantee has no") { + return nil } - return cleanPermissions -} - -func filterLakeFormationTableWithColumnsPermissions(tableName string, columnWildcard bool, columnNames []*string, excludedColumnNames []*string, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { - // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard - // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) - // LIST PERMS = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard - - var cleanPermissions []*lakeformation.PrincipalResourcePermissions - - for _, perm := range allPermissions { - if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnNames != nil { - if StringSlicesEqualIgnoreOrder(perm.Resource.TableWithColumns.ColumnNames, columnNames) { - cleanPermissions = append(cleanPermissions, perm) - continue - } - } - - if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnWildcard != nil && (columnWildcard || len(excludedColumnNames) > 0) { - if (perm.Resource.TableWithColumns.ColumnWildcard.ExcludedColumnNames == nil && len(excludedColumnNames) == 0) || StringSlicesEqualIgnoreOrder(perm.Resource.TableWithColumns.ColumnWildcard.ExcludedColumnNames, excludedColumnNames) { - cleanPermissions = append(cleanPermissions, perm) - continue - } - } - - if perm.Resource.Table != nil && aws.StringValue(perm.Resource.Table.Name) == tableName { - cleanPermissions = append(cleanPermissions, perm) - continue - } + if err != nil { + return fmt.Errorf("unable to revoke LakeFormation Permissions (input: %v): %w", input, err) } - return cleanPermissions -} - -func filterLakeFormationCatalogPermissions(allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { - var cleanPermissions []*lakeformation.PrincipalResourcePermissions - - for _, perm := range allPermissions { - if perm.Resource.Catalog != nil { - cleanPermissions = append(cleanPermissions, perm) - } - } + // Attempted to add a waiter here to wait for delete to complete. However, ListPermissions() returns + // permissions, at least for catalog/CREATE_DATABASE permission, even if they do not exist. That makes + // knowing when the delete is complete impossible. Instead, we'll retry until we get the right error. - return cleanPermissions -} + // Knowing when the delete is complete is complicated: + // You can't just wait until permissions = 0 because there could be many other unrelated permissions + // on the resource and filtering is non-trivial for table with columns. -func filterLakeFormationDataLocationPermissions(allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { - var cleanPermissions []*lakeformation.PrincipalResourcePermissions + err = resource.Retry(waiter.PermissionsDeleteRetryTimeout, func() *resource.RetryError { + var err error + _, err = conn.RevokePermissions(input) - for _, perm := range allPermissions { - if perm.Resource.DataLocation != nil { - cleanPermissions = append(cleanPermissions, perm) + if !tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "No permissions revoked. Grantee has no") { + return resource.RetryableError(err) } - } - return cleanPermissions -} - -func filterLakeFormationDatabasePermissions(allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { - var cleanPermissions []*lakeformation.PrincipalResourcePermissions + return nil + }) - for _, perm := range allPermissions { - if perm.Resource.Database != nil { - cleanPermissions = append(cleanPermissions, perm) - } + if err != nil && !tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "No permissions revoked. Grantee has no") { + return fmt.Errorf("unable to revoke LakeFormation Permissions (input: %v): %w", input, err) } - return cleanPermissions + return nil } func expandLakeFormationCatalogResource() *lakeformation.CatalogResource { @@ -919,7 +759,7 @@ func flattenLakeFormationTableResource(apiObject *lakeformation.TableResource) m } if v := apiObject.Name; v != nil { - if aws.StringValue(v) != TableNameAllTables || apiObject.TableWildcard == nil { + if aws.StringValue(v) != tflakeformation.TableNameAllTables || apiObject.TableWildcard == nil { tfMap["name"] = aws.StringValue(v) } } From 70f9ebf4c28286958a2670165bfa33a487af71ab Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 15:56:41 -0400 Subject: [PATCH 0523/1208] tests/r/lakeformation_perms: Rework twc tests --- ...urce_aws_lakeformation_permissions_test.go | 94 +++++++++++-------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/aws/resource_aws_lakeformation_permissions_test.go b/aws/resource_aws_lakeformation_permissions_test.go index 89d32b05a3c4..4f571f4a5d10 100644 --- a/aws/resource_aws_lakeformation_permissions_test.go +++ b/aws/resource_aws_lakeformation_permissions_test.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + tflakeformation "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lakeformation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -41,6 +42,28 @@ func testAccAWSLakeFormationPermissions_basic(t *testing.T) { }) } +func testAccAWSLakeFormationPermissions_disappears(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lakeformation_permissions.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, lakeformation.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName, "\"event\", \"timestamp\""), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsLakeFormationPermissions(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccAWSLakeFormationPermissions_dataLocation(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" @@ -455,7 +478,7 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, tableType := "" if v, ok := rs.Primary.Attributes["table.#"]; ok && v != "" && v != "0" { - tableType = TableTypeTable + tableType = tflakeformation.TableTypeTable tfMap := map[string]interface{}{} @@ -467,7 +490,7 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, tfMap["database_name"] = v } - if v := rs.Primary.Attributes["table.0.name"]; v != "" && v != TableNameAllTables { + if v := rs.Primary.Attributes["table.0.name"]; v != "" && v != tflakeformation.TableNameAllTables { tfMap["name"] = v } @@ -479,7 +502,7 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, } if v, ok := rs.Primary.Attributes["table_with_columns.#"]; ok && v != "" && v != "0" { - tableType = TableTypeTableWithColumns + tableType = tflakeformation.TableTypeTableWithColumns tfMap := map[string]interface{}{} @@ -548,53 +571,46 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, return 0, fmt.Errorf("error listing Lake Formation permissions after retry: %w", err) } - // clean permissions = filter out permissions that do not pertain to this specific resource + columnNames := make([]*string, 0) + excludedColumnNames := make([]*string, 0) + columnWildcard := false - var cleanPermissions []*lakeformation.PrincipalResourcePermissions + if tableType == tflakeformation.TableTypeTableWithColumns { + if v := rs.Primary.Attributes["table.0.wildcard"]; v != "" && v == "true" { + columnWildcard = true + } - if input.Resource.Catalog != nil { - cleanPermissions = filterLakeFormationCatalogPermissions(allPermissions) - } + colCount := 0 - if input.Resource.DataLocation != nil { - cleanPermissions = filterLakeFormationDataLocationPermissions(allPermissions) - } + if v := rs.Primary.Attributes["table_with_columns.0.column_names.#"]; v != "" { + colCount, err = strconv.Atoi(rs.Primary.Attributes["table_with_columns.0.column_names.#"]) - if input.Resource.Database != nil { - cleanPermissions = filterLakeFormationDatabasePermissions(allPermissions) - } + if err != nil { + return 0, fmt.Errorf("could not convert string (%s) Atoi for column_names: %w", rs.Primary.Attributes["table_with_columns.0.column_names.#"], err) + } + } - if tableType == TableTypeTable { - cleanPermissions = filterLakeFormationTablePermissions( - aws.StringValue(input.Resource.Table.Name), - input.Resource.Table.TableWildcard != nil, - allPermissions, - ) - } + for i := 0; i < colCount; i++ { + columnNames = append(columnNames, aws.String(rs.Primary.Attributes[fmt.Sprintf("table_with_columns.0.column_names.%d", i)])) + } + + colCount = 0 + + if v := rs.Primary.Attributes["table_with_columns.0.excluded_column_names.#"]; v != "" { + colCount, err = strconv.Atoi(rs.Primary.Attributes["table_with_columns.0.excluded_column_names.#"]) - var columnNames []string - if cols, err := strconv.Atoi(rs.Primary.Attributes["table_with_columns.0.column_names.#"]); err == nil { - for i := 0; i < cols; i++ { - columnNames = append(columnNames, rs.Primary.Attributes[fmt.Sprintf("table_with_columns.0.column_names.%d", i)]) + if err != nil { + return 0, fmt.Errorf("could not convert string (%s) Atoi for excluded_column_names: %w", rs.Primary.Attributes["table_with_columns.0.excluded_column_names.#"], err) + } } - } - var excludedColumnNames []string - if cols, err := strconv.Atoi(rs.Primary.Attributes["table_with_columns.0.excluded_column_names.#"]); err == nil { - for i := 0; i < cols; i++ { - excludedColumnNames = append(excludedColumnNames, rs.Primary.Attributes[fmt.Sprintf("table_with_columns.0.excluded_column_names.%d", i)]) + for i := 0; i < colCount; i++ { + columnNames = append(columnNames, aws.String(rs.Primary.Attributes[fmt.Sprintf("table_with_columns.0.excluded_column_names.%d", i)])) } } - if tableType == TableTypeTableWithColumns { - cleanPermissions = filterLakeFormationTableWithColumnsPermissions( - rs.Primary.Attributes["table_with_columns.0.database_name"], - rs.Primary.Attributes["table_with_columns.0.wildcard"] == "true", - aws.StringSlice(columnNames), - aws.StringSlice(excludedColumnNames), - allPermissions, - ) - } + // clean permissions = filter out permissions that do not pertain to this specific resource + cleanPermissions := tflakeformation.FilterPermissions(input, tableType, columnNames, excludedColumnNames, columnWildcard, allPermissions) return len(cleanPermissions), nil } From c54a9eb842123f86c9ea1f682b4c97f42178c53a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 15:57:03 -0400 Subject: [PATCH 0524/1208] tests/lakeformation: Add disappears --- aws/resource_aws_lakeformation_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_lakeformation_test.go b/aws/resource_aws_lakeformation_test.go index 11a8488e00b5..08c0fdfe2f6a 100644 --- a/aws/resource_aws_lakeformation_test.go +++ b/aws/resource_aws_lakeformation_test.go @@ -16,6 +16,7 @@ func TestAccAWSLakeFormation_serial(t *testing.T) { "basic": testAccAWSLakeFormationPermissions_basic, "dataLocation": testAccAWSLakeFormationPermissions_dataLocation, "database": testAccAWSLakeFormationPermissions_database, + "disappears": testAccAWSLakeFormationPermissions_disappears, }, "TablePermissions": { "columnWildcardPermissions": testAccAWSLakeFormationPermissions_columnWildcardPermissions, From f6957ea00742e682da2b05b6eb085635fc753e19 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 15:57:34 -0400 Subject: [PATCH 0525/1208] i/lakeformation: Use statuser --- aws/internal/service/lakeformation/filter.go | 167 ++++++++++++++++++ .../service/lakeformation/waiter/status.go | 48 +++++ .../service/lakeformation/waiter/waiter.go | 35 ++++ 3 files changed, 250 insertions(+) create mode 100644 aws/internal/service/lakeformation/filter.go create mode 100644 aws/internal/service/lakeformation/waiter/status.go create mode 100644 aws/internal/service/lakeformation/waiter/waiter.go diff --git a/aws/internal/service/lakeformation/filter.go b/aws/internal/service/lakeformation/filter.go new file mode 100644 index 000000000000..c86504991d0f --- /dev/null +++ b/aws/internal/service/lakeformation/filter.go @@ -0,0 +1,167 @@ +package lakeformation + +import ( + "reflect" + "sort" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lakeformation" +) + +const ( + TableNameAllTables = "ALL_TABLES" + TableTypeTable = "Table" + TableTypeTableWithColumns = "TableWithColumns" +) + +func FilterPermissions(input *lakeformation.ListPermissionsInput, tableType string, columnNames []*string, excludedColumnNames []*string, columnWildcard bool, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { + // clean permissions = filter out permissions that do not pertain to this specific resource + + var cleanPermissions []*lakeformation.PrincipalResourcePermissions + + if input.Resource.Catalog != nil { + cleanPermissions = FilterLakeFormationCatalogPermissions(allPermissions) + } + + if input.Resource.DataLocation != nil { + cleanPermissions = FilterLakeFormationDataLocationPermissions(allPermissions) + } + + if input.Resource.Database != nil { + cleanPermissions = FilterLakeFormationDatabasePermissions(allPermissions) + } + + if tableType == TableTypeTable { + cleanPermissions = FilterLakeFormationTablePermissions(input.Resource.Table, allPermissions) + } + + if tableType == TableTypeTableWithColumns { + cleanPermissions = FilterLakeFormationTableWithColumnsPermissions(input.Resource.Table, columnNames, excludedColumnNames, columnWildcard, allPermissions) + } + + return cleanPermissions +} + +func FilterLakeFormationTablePermissions(table *lakeformation.TableResource, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { + // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on Table, Name = (Table Name) + // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) + // LIST PERMS = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard + + // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on Table, TableWildcard + // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, TableWildcard, Name = ALL_TABLES + // LIST PERMS = SELECT on TableWithColumns, Name = ALL_TABLES, ColumnWildcard + + var cleanPermissions []*lakeformation.PrincipalResourcePermissions + + for _, perm := range allPermissions { + if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnWildcard != nil { + if aws.StringValue(perm.Resource.TableWithColumns.Name) == aws.StringValue(table.Name) || (table.TableWildcard != nil && aws.StringValue(perm.Resource.TableWithColumns.Name) == TableNameAllTables) { + if len(perm.Permissions) > 0 && aws.StringValue(perm.Permissions[0]) == lakeformation.PermissionSelect { + cleanPermissions = append(cleanPermissions, perm) + continue + } + + if len(perm.PermissionsWithGrantOption) > 0 && aws.StringValue(perm.PermissionsWithGrantOption[0]) == lakeformation.PermissionSelect { + cleanPermissions = append(cleanPermissions, perm) + continue + } + } + } + + if perm.Resource.Table != nil { + if aws.StringValue(perm.Resource.Table.Name) == aws.StringValue(table.Name) { + cleanPermissions = append(cleanPermissions, perm) + continue + } + + if perm.Resource.Table.TableWildcard != nil && table.TableWildcard != nil { + cleanPermissions = append(cleanPermissions, perm) + continue + } + } + continue + } + + return cleanPermissions +} + +func FilterLakeFormationTableWithColumnsPermissions(twc *lakeformation.TableResource, columnNames []*string, excludedColumnNames []*string, columnWildcard bool, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { + // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard + // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) + // LIST PERMS = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard + + var cleanPermissions []*lakeformation.PrincipalResourcePermissions + + for _, perm := range allPermissions { + if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnNames != nil { + if StringSlicesEqualIgnoreOrder(perm.Resource.TableWithColumns.ColumnNames, columnNames) { + cleanPermissions = append(cleanPermissions, perm) + continue + } + } + + if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnWildcard != nil && (columnWildcard || len(excludedColumnNames) > 0) { + if (perm.Resource.TableWithColumns.ColumnWildcard.ExcludedColumnNames == nil && len(excludedColumnNames) == 0) || StringSlicesEqualIgnoreOrder(perm.Resource.TableWithColumns.ColumnWildcard.ExcludedColumnNames, excludedColumnNames) { + cleanPermissions = append(cleanPermissions, perm) + continue + } + } + + if perm.Resource.Table != nil && aws.StringValue(perm.Resource.Table.Name) == aws.StringValue(twc.Name) { + cleanPermissions = append(cleanPermissions, perm) + continue + } + } + + return cleanPermissions +} + +func FilterLakeFormationCatalogPermissions(allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { + var cleanPermissions []*lakeformation.PrincipalResourcePermissions + + for _, perm := range allPermissions { + if perm.Resource.Catalog != nil { + cleanPermissions = append(cleanPermissions, perm) + } + } + + return cleanPermissions +} + +func FilterLakeFormationDataLocationPermissions(allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { + var cleanPermissions []*lakeformation.PrincipalResourcePermissions + + for _, perm := range allPermissions { + if perm.Resource.DataLocation != nil { + cleanPermissions = append(cleanPermissions, perm) + } + } + + return cleanPermissions +} + +func FilterLakeFormationDatabasePermissions(allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { + var cleanPermissions []*lakeformation.PrincipalResourcePermissions + + for _, perm := range allPermissions { + if perm.Resource.Database != nil { + cleanPermissions = append(cleanPermissions, perm) + } + } + + return cleanPermissions +} + +func StringSlicesEqualIgnoreOrder(s1, s2 []*string) bool { + if len(s1) != len(s2) { + return false + } + + v1 := aws.StringValueSlice(s1) + v2 := aws.StringValueSlice(s2) + + sort.Strings(v1) + sort.Strings(v2) + + return reflect.DeepEqual(v1, v2) +} diff --git a/aws/internal/service/lakeformation/waiter/status.go b/aws/internal/service/lakeformation/waiter/status.go new file mode 100644 index 000000000000..fca281e92165 --- /dev/null +++ b/aws/internal/service/lakeformation/waiter/status.go @@ -0,0 +1,48 @@ +package waiter + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/service/lakeformation" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + tflakeformation "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lakeformation" +) + +func PermissionsStatus(conn *lakeformation.LakeFormation, input *lakeformation.ListPermissionsInput, tableType string, columnNames []*string, excludedColumnNames []*string, columnWildcard bool) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + var permissions []*lakeformation.PrincipalResourcePermissions + + err := conn.ListPermissionsPages(input, func(resp *lakeformation.ListPermissionsOutput, lastPage bool) bool { + for _, permission := range resp.PrincipalResourcePermissions { + if permission == nil { + continue + } + + permissions = append(permissions, permission) + } + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, lakeformation.ErrCodeEntityNotFoundException) { + return nil, StatusNotFound, err + } + + if tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "Invalid principal") { + return nil, StatusIAMDelay, nil + } + + if err != nil { + return nil, StatusFailed, fmt.Errorf("error listing permissions: %w", err) + } + + // clean permissions = filter out permissions that do not pertain to this specific resource + cleanPermissions := tflakeformation.FilterPermissions(input, tableType, columnNames, excludedColumnNames, columnWildcard, permissions) + + if len(cleanPermissions) == 0 { + return nil, StatusNotFound, nil + } + + return permissions, StatusAvailable, nil + } +} diff --git a/aws/internal/service/lakeformation/waiter/waiter.go b/aws/internal/service/lakeformation/waiter/waiter.go new file mode 100644 index 000000000000..80e66a211594 --- /dev/null +++ b/aws/internal/service/lakeformation/waiter/waiter.go @@ -0,0 +1,35 @@ +package waiter + +import ( + "time" + + "github.com/aws/aws-sdk-go/service/lakeformation" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + PermissionsReadyTimeout = 1 * time.Minute + PermissionsDeleteRetryTimeout = 3 * time.Minute + + StatusAvailable = "AVAILABLE" + StatusNotFound = "NOT FOUND" + StatusFailed = "FAILED" + StatusIAMDelay = "IAM DELAY" +) + +func PermissionsReady(conn *lakeformation.LakeFormation, input *lakeformation.ListPermissionsInput, tableType string, columnNames []*string, excludedColumnNames []*string, columnWildcard bool) ([]*lakeformation.PrincipalResourcePermissions, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusNotFound, StatusIAMDelay}, + Target: []string{StatusAvailable}, + Refresh: PermissionsStatus(conn, input, tableType, columnNames, excludedColumnNames, columnWildcard), + Timeout: PermissionsReadyTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.([]*lakeformation.PrincipalResourcePermissions); ok { + return output, err + } + + return nil, err +} From c86c0ef1f5a658301872be0a26448f471eb1e19f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 15:57:54 -0400 Subject: [PATCH 0526/1208] docs/ds/lakeformation_perms: Update docs --- website/docs/d/lakeformation_permissions.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/d/lakeformation_permissions.html.markdown b/website/docs/d/lakeformation_permissions.html.markdown index 05b943ddc4ee..017c062039b0 100644 --- a/website/docs/d/lakeformation_permissions.html.markdown +++ b/website/docs/d/lakeformation_permissions.html.markdown @@ -99,8 +99,8 @@ The following arguments are required: The following arguments are optional: * `catalog_id` - (Optional) Identifier for the Data Catalog. By default, it is the account ID of the caller. -* `column_names` - (Optional) List of column names for the table. At least one of `column_names` or `excluded_column_names` is required. -* `excluded_column_names` - (Optional) List of column names for the table to exclude. At least one of `column_names` or `excluded_column_names` is required. +* `column_names` - (Optional) Set of column names for the table. At least one of `column_names` or `excluded_column_names` is required. +* `excluded_column_names` - (Optional) Set of column names for the table to exclude. At least one of `column_names` or `excluded_column_names` is required. ## Attributes Reference From 98f022bef26b36f1fa0e7f4987c66311eca7cfd4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 16:05:45 -0400 Subject: [PATCH 0527/1208] r/lakeformation_perms: Appease linter gods --- aws/resource_aws_lakeformation_permissions.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/resource_aws_lakeformation_permissions.go b/aws/resource_aws_lakeformation_permissions.go index 3351f47237ab..93dc46901588 100644 --- a/aws/resource_aws_lakeformation_permissions.go +++ b/aws/resource_aws_lakeformation_permissions.go @@ -612,6 +612,10 @@ func resourceAwsLakeFormationPermissionsDelete(d *schema.ResourceData, meta inte return nil }) + if tfresource.TimedOut(err) { + _, err = conn.RevokePermissions(input) + } + if err != nil && !tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "No permissions revoked. Grantee has no") { return fmt.Errorf("unable to revoke LakeFormation Permissions (input: %v): %w", input, err) } From 14dd94574130013acd28c5ddacb916136559351e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 17:12:53 -0400 Subject: [PATCH 0528/1208] i/lakeformation: Simplify logic --- aws/internal/service/lakeformation/filter.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/aws/internal/service/lakeformation/filter.go b/aws/internal/service/lakeformation/filter.go index c86504991d0f..595ae773044a 100644 --- a/aws/internal/service/lakeformation/filter.go +++ b/aws/internal/service/lakeformation/filter.go @@ -101,7 +101,12 @@ func FilterLakeFormationTableWithColumnsPermissions(twc *lakeformation.TableReso } if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnWildcard != nil && (columnWildcard || len(excludedColumnNames) > 0) { - if (perm.Resource.TableWithColumns.ColumnWildcard.ExcludedColumnNames == nil && len(excludedColumnNames) == 0) || StringSlicesEqualIgnoreOrder(perm.Resource.TableWithColumns.ColumnWildcard.ExcludedColumnNames, excludedColumnNames) { + if perm.Resource.TableWithColumns.ColumnWildcard.ExcludedColumnNames == nil && len(excludedColumnNames) == 0 { + cleanPermissions = append(cleanPermissions, perm) + continue + } + + if len(excludedColumnNames) > 0 && StringSlicesEqualIgnoreOrder(perm.Resource.TableWithColumns.ColumnWildcard.ExcludedColumnNames, excludedColumnNames) { cleanPermissions = append(cleanPermissions, perm) continue } From f85d60fd8e988fedadb4f30caaa915316ac3a35d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 17:13:24 -0400 Subject: [PATCH 0529/1208] tests/r/lakeformation_permissions: Fix tests --- ...urce_aws_lakeformation_permissions_test.go | 102 +++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_lakeformation_permissions_test.go b/aws/resource_aws_lakeformation_permissions_test.go index 4f571f4a5d10..48b1db0edbb7 100644 --- a/aws/resource_aws_lakeformation_permissions_test.go +++ b/aws/resource_aws_lakeformation_permissions_test.go @@ -384,6 +384,30 @@ func testAccAWSLakeFormationPermissions_columnWildcardPermissions(t *testing.T) }) } +func testAccAWSLakeFormationPermissions_columnWildcardExcludedColumnsPermissions(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lakeformation_permissions.test" + roleName := "aws_iam_role.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, lakeformation.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLakeFormationPermissionsConfig_columnWildcardExcludedColumnsPermissions(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "0"), + ), + }, + }, + }) +} + func testAccCheckAWSLakeFormationPermissionsDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).lakeformationconn @@ -576,7 +600,7 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, columnWildcard := false if tableType == tflakeformation.TableTypeTableWithColumns { - if v := rs.Primary.Attributes["table.0.wildcard"]; v != "" && v == "true" { + if v := rs.Primary.Attributes["table_with_columns.0.wildcard"]; v != "" && v == "true" { columnWildcard = true } @@ -605,7 +629,7 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, } for i := 0; i < colCount; i++ { - columnNames = append(columnNames, aws.String(rs.Primary.Attributes[fmt.Sprintf("table_with_columns.0.excluded_column_names.%d", i)])) + excludedColumnNames = append(excludedColumnNames, aws.String(rs.Primary.Attributes[fmt.Sprintf("table_with_columns.0.excluded_column_names.%d", i)])) } } @@ -1309,3 +1333,77 @@ resource "aws_lakeformation_permissions" "test" { } `, rName) } + +func testAccAWSLakeFormationPermissionsConfig_columnWildcardExcludedColumnsPermissions(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + path = "/" + + assume_role_policy = < Date: Wed, 16 Jun 2021 17:13:50 -0400 Subject: [PATCH 0530/1208] tests/lakeformation: Break into better groupings --- aws/resource_aws_lakeformation_test.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_lakeformation_test.go b/aws/resource_aws_lakeformation_test.go index 08c0fdfe2f6a..6f012aefe4e4 100644 --- a/aws/resource_aws_lakeformation_test.go +++ b/aws/resource_aws_lakeformation_test.go @@ -19,14 +19,17 @@ func TestAccAWSLakeFormation_serial(t *testing.T) { "disappears": testAccAWSLakeFormationPermissions_disappears, }, "TablePermissions": { - "columnWildcardPermissions": testAccAWSLakeFormationPermissions_columnWildcardPermissions, - "implicitTableWithColumnsPermissions": testAccAWSLakeFormationPermissions_implicitTableWithColumnsPermissions, - "implicitTablePermissions": testAccAWSLakeFormationPermissions_implicitTablePermissions, - "selectPermissions": testAccAWSLakeFormationPermissions_selectPermissions, - "tableName": testAccAWSLakeFormationPermissions_tableName, - "tableWildcard": testAccAWSLakeFormationPermissions_tableWildcard, - "tableWildcardPermissions": testAccAWSLakeFormationPermissions_tableWildcardPermissions, - "tableWithColumns": testAccAWSLakeFormationPermissions_tableWithColumns, + "implicitTablePermissions": testAccAWSLakeFormationPermissions_implicitTablePermissions, + "selectPermissions": testAccAWSLakeFormationPermissions_selectPermissions, + "tableName": testAccAWSLakeFormationPermissions_tableName, + "tableWildcard": testAccAWSLakeFormationPermissions_tableWildcard, + "tableWildcardPermissions": testAccAWSLakeFormationPermissions_tableWildcardPermissions, + }, + "TableWithColumnsPermissions": { + "columnWildcardExcludedColumnsPermissions": testAccAWSLakeFormationPermissions_columnWildcardExcludedColumnsPermissions, + "columnWildcardPermissions": testAccAWSLakeFormationPermissions_columnWildcardPermissions, + "implicitTableWithColumnsPermissions": testAccAWSLakeFormationPermissions_implicitTableWithColumnsPermissions, + "tableWithColumns": testAccAWSLakeFormationPermissions_tableWithColumns, }, "DataSourcePermissions": { "basicDataSource": testAccAWSLakeFormationPermissionsDataSource_basic, From 82235d0f4459848b24350f4f2380befb69a30519 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 16 Jun 2021 17:20:31 -0400 Subject: [PATCH 0531/1208] tests/lakeformation_perms: Appease linter gods --- aws/resource_aws_lakeformation_permissions_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_lakeformation_permissions_test.go b/aws/resource_aws_lakeformation_permissions_test.go index 48b1db0edbb7..8933a6796c72 100644 --- a/aws/resource_aws_lakeformation_permissions_test.go +++ b/aws/resource_aws_lakeformation_permissions_test.go @@ -1399,7 +1399,7 @@ resource "aws_lakeformation_permissions" "test" { database_name = aws_glue_catalog_table.test.database_name name = aws_glue_catalog_table.test.name wildcard = true - excluded_column_names = ["value"] + excluded_column_names = ["value"] } # for consistency, ensure that admins are setup before testing From 314e02c82c8d5d1b68264d12bad3990d1eb2fdd0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 09:57:19 -0400 Subject: [PATCH 0532/1208] r/aws_lakeformation_permissions: Fix 'testAccAWSLakeFormationPermissions_dataLocation'. Previous acceptance test output: === RUN TestAccAWSLakeFormation_serial/BasicPermissions/dataLocation testing_new.go:63: Error running post-test destroy, there may be dangling resources: exit status 1 2021/06/17 09:38:54 [DEBUG] Using modified User-Agent: Terraform/0.12.31 HashiCorp-terraform-exec/0.13.3 Error: error deregistering Lake Formation Resource (arn:aws:s3:::tf-acc-test-7389732714506454004): InvalidInputException: Must manually delete service-linked role to deregister last S3 location. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSLakeFormation_serial/BasicPermissions/dataLocation' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSLakeFormation_serial/BasicPermissions/dataLocation -timeout 180m === RUN TestAccAWSLakeFormation_serial === RUN TestAccAWSLakeFormation_serial/BasicPermissions === RUN TestAccAWSLakeFormation_serial/BasicPermissions/dataLocation --- PASS: TestAccAWSLakeFormation_serial (29.94s) --- PASS: TestAccAWSLakeFormation_serial/BasicPermissions (29.94s) --- PASS: TestAccAWSLakeFormation_serial/BasicPermissions/dataLocation (29.94s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 33.278s --- aws/resource_aws_lakeformation_permissions_test.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_lakeformation_permissions_test.go b/aws/resource_aws_lakeformation_permissions_test.go index 8933a6796c72..bfd87e3fd9fe 100644 --- a/aws/resource_aws_lakeformation_permissions_test.go +++ b/aws/resource_aws_lakeformation_permissions_test.go @@ -699,7 +699,15 @@ resource "aws_iam_role" "test" { }, "Effect": "Allow", "Sid": "" - } + }, + { + "Action": "sts:AssumeRole", + "Principal": { + "Service": "s3.amazonaws.com" + }, + "Effect": "Allow", + "Sid": "" + } ] } EOF @@ -712,7 +720,8 @@ resource "aws_s3_bucket" "test" { } resource "aws_lakeformation_resource" "test" { - arn = aws_s3_bucket.test.arn + arn = aws_s3_bucket.test.arn + role_arn = aws_iam_role.test.arn } data "aws_caller_identity" "current" {} From 3d1a96c3a367a36b5792ee098e5c05721dde5ba2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 12:09:55 -0400 Subject: [PATCH 0533/1208] i/lakeformation: Add filter unit tests --- .../service/lakeformation/filter_test.go | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 aws/internal/service/lakeformation/filter_test.go diff --git a/aws/internal/service/lakeformation/filter_test.go b/aws/internal/service/lakeformation/filter_test.go new file mode 100644 index 000000000000..19ca02352e85 --- /dev/null +++ b/aws/internal/service/lakeformation/filter_test.go @@ -0,0 +1,96 @@ +package lakeformation + +import ( + "fmt" + "reflect" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lakeformation" +) + +func TestFilterPermissions(t *testing.T) { + // primitives to make test cases easier + accountID := "481516234248" + dbName := "Hiliji" + altDBName := "Hiuhbum" + tableName := "Ladocmoc" + + principal := &lakeformation.DataLakePrincipal{ + DataLakePrincipalIdentifier: aws.String(fmt.Sprintf("arn:aws-us-gov:iam::%s:role/Zepotiz-Bulgaria", accountID)), + } + + testCases := []struct { + Name string + Input *lakeformation.ListPermissionsInput + TableType string + ColumnNames []*string + ExcludedColumnNames []*string + ColumnWildcard bool + All []*lakeformation.PrincipalResourcePermissions + ExpectedClean []*lakeformation.PrincipalResourcePermissions + }{ + { + Name: "empty", + Input: &lakeformation.ListPermissionsInput{ + Principal: principal, + Resource: &lakeformation.Resource{}, + }, + All: nil, + ExpectedClean: nil, + }, + { + Name: "emptyWithInput", + Input: &lakeformation.ListPermissionsInput{ + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + All: nil, + ExpectedClean: nil, + }, + { + Name: "wrongTableResource", + Input: &lakeformation.ListPermissionsInput{ + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + All: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(altDBName), + Name: aws.String(tableName), + }, + }, + }, + }, + ExpectedClean: nil, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + got := FilterPermissions(testCase.Input, testCase.TableType, testCase.ColumnNames, testCase.ExcludedColumnNames, testCase.ColumnWildcard, testCase.All) + + if !reflect.DeepEqual(testCase.ExpectedClean, got) { + t.Errorf("got %v, expected %v", got, testCase.ExpectedClean) + } + }) + } +} From 5054871a7d3d0b43e0c3e5b101dbc2a6e17fd506 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 11:50:45 -0400 Subject: [PATCH 0534/1208] r/aws_eks_node_group: Test that 0 is allowed for 'desired_size' and 'min_size'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSEksNodeGroup_ScalingConfig_Zero_DesiredSize_MinSize' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSEksNodeGroup_ScalingConfig_Zero_DesiredSize_MinSize -timeout 180m === RUN TestAccAWSEksNodeGroup_ScalingConfig_Zero_DesiredSize_MinSize === PAUSE TestAccAWSEksNodeGroup_ScalingConfig_Zero_DesiredSize_MinSize === CONT TestAccAWSEksNodeGroup_ScalingConfig_Zero_DesiredSize_MinSize --- PASS: TestAccAWSEksNodeGroup_ScalingConfig_Zero_DesiredSize_MinSize (1044.31s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 1047.577s --- aws/resource_aws_eks_node_group.go | 4 +- aws/resource_aws_eks_node_group_test.go | 51 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_eks_node_group.go b/aws/resource_aws_eks_node_group.go index b772e406082c..f47913cd031d 100644 --- a/aws/resource_aws_eks_node_group.go +++ b/aws/resource_aws_eks_node_group.go @@ -606,7 +606,7 @@ func expandEksNodegroupScalingConfig(l []interface{}) *eks.NodegroupScalingConfi config := &eks.NodegroupScalingConfig{} - if v, ok := m["desired_size"].(int); ok && v != 0 { + if v, ok := m["desired_size"].(int); ok { config.DesiredSize = aws.Int64(int64(v)) } @@ -614,7 +614,7 @@ func expandEksNodegroupScalingConfig(l []interface{}) *eks.NodegroupScalingConfi config.MaxSize = aws.Int64(int64(v)) } - if v, ok := m["min_size"].(int); ok && v != 0 { + if v, ok := m["min_size"].(int); ok { config.MinSize = aws.Int64(int64(v)) } diff --git a/aws/resource_aws_eks_node_group_test.go b/aws/resource_aws_eks_node_group_test.go index 55a1ad905c5f..b3a685e6039b 100644 --- a/aws/resource_aws_eks_node_group_test.go +++ b/aws/resource_aws_eks_node_group_test.go @@ -772,6 +772,57 @@ func TestAccAWSEksNodeGroup_ScalingConfig_MinSize(t *testing.T) { }) } +func TestAccAWSEksNodeGroup_ScalingConfig_Zero_DesiredSize_MinSize(t *testing.T) { + var nodeGroup1, nodeGroup2 eks.Nodegroup + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_eks_node_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEksNodeGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksNodeGroupConfigScalingConfigSizes(rName, 0, 1, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), + resource.TestCheckResourceAttr(resourceName, "scaling_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scaling_config.0.desired_size", "0"), + resource.TestCheckResourceAttr(resourceName, "scaling_config.0.max_size", "1"), + resource.TestCheckResourceAttr(resourceName, "scaling_config.0.min_size", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSEksNodeGroupConfigScalingConfigSizes(rName, 1, 2, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup2), + testAccCheckAWSEksNodeGroupNotRecreated(&nodeGroup1, &nodeGroup2), + resource.TestCheckResourceAttr(resourceName, "scaling_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scaling_config.0.desired_size", "1"), + resource.TestCheckResourceAttr(resourceName, "scaling_config.0.max_size", "2"), + resource.TestCheckResourceAttr(resourceName, "scaling_config.0.min_size", "1"), + ), + }, + { + Config: testAccAWSEksNodeGroupConfigScalingConfigSizes(rName, 0, 1, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), + resource.TestCheckResourceAttr(resourceName, "scaling_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scaling_config.0.desired_size", "0"), + resource.TestCheckResourceAttr(resourceName, "scaling_config.0.max_size", "1"), + resource.TestCheckResourceAttr(resourceName, "scaling_config.0.min_size", "0"), + ), + }, + }, + }) +} + func TestAccAWSEksNodeGroup_Tags(t *testing.T) { var nodeGroup1, nodeGroup2, nodeGroup3 eks.Nodegroup rName := acctest.RandomWithPrefix("tf-acc-test") From 261a493b902af7caa47fdd116fbbf85a4ed16415 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 13:07:45 -0400 Subject: [PATCH 0535/1208] i/lakeformation: Add explanation, extra safety check --- aws/internal/service/lakeformation/filter.go | 33 +++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/aws/internal/service/lakeformation/filter.go b/aws/internal/service/lakeformation/filter.go index 595ae773044a..2112ef0922b1 100644 --- a/aws/internal/service/lakeformation/filter.go +++ b/aws/internal/service/lakeformation/filter.go @@ -15,31 +15,40 @@ const ( ) func FilterPermissions(input *lakeformation.ListPermissionsInput, tableType string, columnNames []*string, excludedColumnNames []*string, columnWildcard bool, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { - // clean permissions = filter out permissions that do not pertain to this specific resource - - var cleanPermissions []*lakeformation.PrincipalResourcePermissions + // For most Lake Formation resources, filtering within the provider is unnecessary. The input + // contains everything for AWS to give you back exactly what you want. However, many challenges + // arise with tables and tables with columns. Perhaps the two biggest problems (so far) are as + // follows: + // 1. SELECT - when you grant SELECT, it may be part of a list of permissions. However, when + // listing permissions, SELECT comes back in a separate permission. + // 2. Tables with columns. The ListPermissionsInput does not allow you to include a tables with + // columns resource. This means you might get back more permissions than actually pertain to + // the current situation. The table may have separate permissions that also come back. + // + // Thus, for most cases this is just a pass through filter but attempts to clean out + // permissions in the special cases to avoid extra permissions being included. if input.Resource.Catalog != nil { - cleanPermissions = FilterLakeFormationCatalogPermissions(allPermissions) + return FilterLakeFormationCatalogPermissions(allPermissions) } if input.Resource.DataLocation != nil { - cleanPermissions = FilterLakeFormationDataLocationPermissions(allPermissions) + return FilterLakeFormationDataLocationPermissions(allPermissions) } if input.Resource.Database != nil { - cleanPermissions = FilterLakeFormationDatabasePermissions(allPermissions) + return FilterLakeFormationDatabasePermissions(allPermissions) } - if tableType == TableTypeTable { - cleanPermissions = FilterLakeFormationTablePermissions(input.Resource.Table, allPermissions) + if tableType == TableTypeTableWithColumns { + return FilterLakeFormationTableWithColumnsPermissions(input.Resource.Table, columnNames, excludedColumnNames, columnWildcard, allPermissions) } - if tableType == TableTypeTableWithColumns { - cleanPermissions = FilterLakeFormationTableWithColumnsPermissions(input.Resource.Table, columnNames, excludedColumnNames, columnWildcard, allPermissions) + if input.Resource.Table != nil || tableType == TableTypeTable { + return FilterLakeFormationTablePermissions(input.Resource.Table, allPermissions) } - return cleanPermissions + return nil } func FilterLakeFormationTablePermissions(table *lakeformation.TableResource, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { @@ -68,7 +77,7 @@ func FilterLakeFormationTablePermissions(table *lakeformation.TableResource, all } } - if perm.Resource.Table != nil { + if perm.Resource.Table != nil && aws.StringValue(perm.Resource.Table.DatabaseName) == aws.StringValue(table.DatabaseName) { if aws.StringValue(perm.Resource.Table.Name) == aws.StringValue(table.Name) { cleanPermissions = append(cleanPermissions, perm) continue From 2f46e1fa9457c14a259d7f1cf2175298420f5713 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 13:08:01 -0400 Subject: [PATCH 0536/1208] i/lakeformation: Add filter unit tests --- .../service/lakeformation/filter_test.go | 454 +++++++++++++++++- 1 file changed, 452 insertions(+), 2 deletions(-) diff --git a/aws/internal/service/lakeformation/filter_test.go b/aws/internal/service/lakeformation/filter_test.go index 19ca02352e85..d44b4cf38777 100644 --- a/aws/internal/service/lakeformation/filter_test.go +++ b/aws/internal/service/lakeformation/filter_test.go @@ -55,7 +55,7 @@ func TestFilterPermissions(t *testing.T) { ExpectedClean: nil, }, { - Name: "wrongTableResource", + Name: "wrongTableResource", // this may not actually be possible but we account for it Input: &lakeformation.ListPermissionsInput{ Principal: principal, Resource: &lakeformation.Resource{ @@ -82,6 +82,456 @@ func TestFilterPermissions(t *testing.T) { }, ExpectedClean: nil, }, + { + Name: "tableResource", + Input: &lakeformation.ListPermissionsInput{ + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + All: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + }, + ExpectedClean: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + }, + }, + { + Name: "tableResourceSelectPerm", + Input: &lakeformation.ListPermissionsInput{ + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + All: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + ColumnWildcard: &lakeformation.ColumnWildcard{}, + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + }, + ExpectedClean: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + ColumnWildcard: &lakeformation.ColumnWildcard{}, + }, + }, + }, + }, + }, + { + Name: "tableResourceSelectPermGrant", + Input: &lakeformation.ListPermissionsInput{ + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + All: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + PermissionsWithGrantOption: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{lakeformation.PermissionSelect}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + ColumnWildcard: &lakeformation.ColumnWildcard{}, + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter}), + PermissionsWithGrantOption: aws.StringSlice([]string{lakeformation.PermissionAlter}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + }, + ExpectedClean: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + PermissionsWithGrantOption: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{lakeformation.PermissionSelect}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + ColumnWildcard: &lakeformation.ColumnWildcard{}, + }, + }, + }, + }, + }, + { + Name: "twcBasic", + Input: &lakeformation.ListPermissionsInput{ + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + TableType: TableTypeTableWithColumns, + ColumnNames: aws.StringSlice([]string{"value"}), + All: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + ColumnNames: aws.StringSlice([]string{"value"}), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + ColumnNames: aws.StringSlice([]string{"fred"}), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + }, + ExpectedClean: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + ColumnNames: aws.StringSlice([]string{"value"}), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + }, + }, + { + Name: "twcWildcard", + Input: &lakeformation.ListPermissionsInput{ + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + TableType: TableTypeTableWithColumns, + ColumnWildcard: true, + All: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + ColumnWildcard: &lakeformation.ColumnWildcard{}, + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + ColumnNames: aws.StringSlice([]string{"fred"}), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + }, + ExpectedClean: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + ColumnWildcard: &lakeformation.ColumnWildcard{}, + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + }, + }, + { + Name: "twcWildcardExcluded", + Input: &lakeformation.ListPermissionsInput{ + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + TableType: TableTypeTableWithColumns, + ColumnWildcard: true, + ExcludedColumnNames: aws.StringSlice([]string{"value"}), + All: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + ColumnWildcard: &lakeformation.ColumnWildcard{ + ExcludedColumnNames: aws.StringSlice([]string{"value"}), + }, + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + ColumnNames: aws.StringSlice([]string{"fred"}), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + }, + ExpectedClean: []*lakeformation.PrincipalResourcePermissions{ + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionAlter, lakeformation.PermissionDelete}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + Table: &lakeformation.TableResource{ + CatalogId: aws.String(accountID), + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + { + Permissions: aws.StringSlice([]string{lakeformation.PermissionSelect}), + PermissionsWithGrantOption: aws.StringSlice([]string{}), + Principal: principal, + Resource: &lakeformation.Resource{ + TableWithColumns: &lakeformation.TableWithColumnsResource{ + CatalogId: aws.String(accountID), + ColumnWildcard: &lakeformation.ColumnWildcard{ + ExcludedColumnNames: aws.StringSlice([]string{"value"}), + }, + DatabaseName: aws.String(dbName), + Name: aws.String(tableName), + }, + }, + }, + }, + }, } for _, testCase := range testCases { @@ -89,7 +539,7 @@ func TestFilterPermissions(t *testing.T) { got := FilterPermissions(testCase.Input, testCase.TableType, testCase.ColumnNames, testCase.ExcludedColumnNames, testCase.ColumnWildcard, testCase.All) if !reflect.DeepEqual(testCase.ExpectedClean, got) { - t.Errorf("got %v, expected %v", got, testCase.ExpectedClean) + t.Errorf("got %v, expected %v, input %v", got, testCase.ExpectedClean, testCase.Input) } }) } From 8fa959a8f804362c8624687d585a516e041d051e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 13:11:48 -0400 Subject: [PATCH 0537/1208] i/lakeformation: Fix comments --- aws/internal/service/lakeformation/filter.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/aws/internal/service/lakeformation/filter.go b/aws/internal/service/lakeformation/filter.go index 2112ef0922b1..5e655ffa7406 100644 --- a/aws/internal/service/lakeformation/filter.go +++ b/aws/internal/service/lakeformation/filter.go @@ -52,13 +52,13 @@ func FilterPermissions(input *lakeformation.ListPermissionsInput, tableType stri } func FilterLakeFormationTablePermissions(table *lakeformation.TableResource, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { - // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on Table, Name = (Table Name) - // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) - // LIST PERMS = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard + // CREATE PERMS (in) = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on Table, Name = (Table Name) + // LIST PERMS (out) = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) + // LIST PERMS (out) = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard - // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on Table, TableWildcard - // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, TableWildcard, Name = ALL_TABLES - // LIST PERMS = SELECT on TableWithColumns, Name = ALL_TABLES, ColumnWildcard + // CREATE PERMS (in) = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on Table, TableWildcard + // LIST PERMS (out) = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, TableWildcard, Name = ALL_TABLES + // LIST PERMS (out) = SELECT on TableWithColumns, Name = ALL_TABLES, ColumnWildcard var cleanPermissions []*lakeformation.PrincipalResourcePermissions @@ -95,9 +95,9 @@ func FilterLakeFormationTablePermissions(table *lakeformation.TableResource, all } func FilterLakeFormationTableWithColumnsPermissions(twc *lakeformation.TableResource, columnNames []*string, excludedColumnNames []*string, columnWildcard bool, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { - // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard - // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) - // LIST PERMS = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard + // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard + // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) + // LIST PERMS = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard var cleanPermissions []*lakeformation.PrincipalResourcePermissions From 5bf5b84aaa1356fbf08812389de957119586a83f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 13:12:58 -0400 Subject: [PATCH 0538/1208] i/lakeformation: Fix comments --- aws/internal/service/lakeformation/filter.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/internal/service/lakeformation/filter.go b/aws/internal/service/lakeformation/filter.go index 5e655ffa7406..916df407ebd1 100644 --- a/aws/internal/service/lakeformation/filter.go +++ b/aws/internal/service/lakeformation/filter.go @@ -95,9 +95,9 @@ func FilterLakeFormationTablePermissions(table *lakeformation.TableResource, all } func FilterLakeFormationTableWithColumnsPermissions(twc *lakeformation.TableResource, columnNames []*string, excludedColumnNames []*string, columnWildcard bool, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { - // CREATE PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard - // LIST PERMS = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) - // LIST PERMS = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard + // CREATE PERMS (in) = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard + // LIST PERMS (out) = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) + // LIST PERMS (out) = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard var cleanPermissions []*lakeformation.PrincipalResourcePermissions From e05b408b3af0f92ad4b6b83a851474a930b3ed71 Mon Sep 17 00:00:00 2001 From: FrancescoFucile-CAZ Date: Thu, 17 Jun 2021 18:42:26 +0100 Subject: [PATCH 0539/1208] Add missing error checks to tests. Enforce consistency for tests names. Fix linting for TF configuration defined in tests. Add "attributes reference" paragraph in resource docs. --- ...source_aws_cloudwatch_event_bus_policy_test.go | 15 +++++++++++---- .../r/cloudwatch_event_bus_policy.html.markdown | 10 ++++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_bus_policy_test.go b/aws/resource_aws_cloudwatch_event_bus_policy_test.go index 7f3963a10ad7..20e26be7641a 100644 --- a/aws/resource_aws_cloudwatch_event_bus_policy_test.go +++ b/aws/resource_aws_cloudwatch_event_bus_policy_test.go @@ -19,6 +19,7 @@ func TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSCloudWatchEventBusDestroy, Steps: []resource.TestStep{ @@ -26,14 +27,14 @@ func TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { Config: testAccAWSCloudwatchEventBusPolicyConfig(rstring), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), - testAccAWSCloudWatchEventBusPolicyDocument(resourceName), + testAccAWSCloudwatchEventBusPolicyDocument(resourceName), ), }, { Config: testAccAWSCloudwatchEventBusPolicyConfigUpdate(rstring), Check: resource.ComposeTestCheckFunc( testAccCheckAWSCloudwatchEventBusPolicyExists(resourceName), - testAccAWSCloudWatchEventBusPolicyDocument(resourceName), + testAccAWSCloudwatchEventBusPolicyDocument(resourceName), ), }, { @@ -45,7 +46,7 @@ func TestAccAWSCloudwatchEventBusPolicy_basic(t *testing.T) { }) } -func TestAccAWSCloudWatchEventBusPolicy_disappears(t *testing.T) { +func TestAccAWSCloudwatchEventBusPolicy_disappears(t *testing.T) { resourceName := "aws_cloudwatch_event_bus_policy.test" rstring := acctest.RandString(5) @@ -98,7 +99,7 @@ func testAccCheckAWSCloudwatchEventBusPolicyExists(pr string) resource.TestCheck } } -func testAccAWSCloudWatchEventBusPolicyDocument(pr string) resource.TestCheckFunc { +func testAccAWSCloudwatchEventBusPolicyDocument(pr string) resource.TestCheckFunc { return func(state *terraform.State) error { eventBusPolicyResource, ok := state.RootModule().Resources[pr] if !ok { @@ -111,6 +112,9 @@ func testAccAWSCloudWatchEventBusPolicyDocument(pr string) resource.TestCheckFun var eventBusPolicyResourcePolicyDocument map[string]interface{} err := json.Unmarshal([]byte(eventBusPolicyResource.Primary.Attributes["policy"]), &eventBusPolicyResourcePolicyDocument) + if err != nil { + return fmt.Errorf("Parsing CloudWatch Events bus policy for '%s' failed: %w", pr, err) + } eventBusName := eventBusPolicyResource.Primary.ID @@ -120,6 +124,9 @@ func testAccAWSCloudWatchEventBusPolicyDocument(pr string) resource.TestCheckFun cloudWatchEventsConnection := testAccProvider.Meta().(*AWSClient).cloudwatcheventsconn describedEventBus, err := cloudWatchEventsConnection.DescribeEventBus(input) + if err != nil { + return fmt.Errorf("Reading CloudWatch Events bus policy for '%s' failed: %w", pr, err) + } var describedEventBusPolicy map[string]interface{} err = json.Unmarshal([]byte(*describedEventBus.Policy), &describedEventBusPolicy) diff --git a/website/docs/r/cloudwatch_event_bus_policy.html.markdown b/website/docs/r/cloudwatch_event_bus_policy.html.markdown index 2ba904fda18f..d49b0b6aa311 100644 --- a/website/docs/r/cloudwatch_event_bus_policy.html.markdown +++ b/website/docs/r/cloudwatch_event_bus_policy.html.markdown @@ -84,7 +84,7 @@ resource "aws_cloudwatch_event_bus_policy" "test" { ```hcl data "aws_iam_policy_document" "test" { - + statement { sid = "DevAccountAccess" effect = "Allow" @@ -100,7 +100,7 @@ data "aws_iam_policy_document" "test" { identifiers = ["123456789012"] } } - + statement { sid = "OrganizationAccess" effect = "Allow" @@ -141,6 +141,12 @@ The following arguments are supported: * `policy` - (Required) The text of the policy. For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). * `event_bus_name` - (Optional) The event bus to set the permissions on. If you omit this, the permissions are set on the `default` event bus. +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The name of the EventBrige event bus. + ## Import EventBridge permissions can be imported using the `event_bus_name`, e.g. From c149356a897ba68f369d9419a9a2f130641e6c13 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 17 Jun 2021 17:43:28 +0000 Subject: [PATCH 0540/1208] Update CHANGELOG.md for #19817 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04d280615d57..fea90ff986ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,11 +14,16 @@ ENHANCEMENTS: * resource/aws_datasync_location_nfs: Add support for updating. ([#19767](https://github.com/hashicorp/terraform-provider-aws/issues/19767)) * resource/aws_ecs_cluster: Add plan time validation for `name`. ([#19785](https://github.com/hashicorp/terraform-provider-aws/issues/19785)) * resource/aws_ecs_cluster: Add support for `configuration`. ([#19785](https://github.com/hashicorp/terraform-provider-aws/issues/19785)) +* resource/aws_spot_fleet_request: Add `on_demand_allocation_strategy`, `on_demand_max_total_price`, and `on_demand_target_capacity` arguments ([#13127](https://github.com/hashicorp/terraform-provider-aws/issues/13127)) BUG FIXES: +* data-source/aws_lakeformation_permissions: Fix diffs resulting from order of column names and exclude column names ([#19817](https://github.com/hashicorp/terraform-provider-aws/issues/19817)) * resource/aws_cognito_identity_provider: Fix updating `idp_identifiers` crash. ([#19819](https://github.com/hashicorp/terraform-provider-aws/issues/19819)) * resource/aws_glue_trigger: Fix default timeouts for Create and Delete operations ([#19827](https://github.com/hashicorp/terraform-provider-aws/issues/19827)) +* resource/aws_lakeformation_permissions: Fix bug preventing updates (inconsistent result) ([#19817](https://github.com/hashicorp/terraform-provider-aws/issues/19817)) +* resource/aws_lakeformation_permissions: Fix bug where resource is not properly removed from state ([#19817](https://github.com/hashicorp/terraform-provider-aws/issues/19817)) +* resource/aws_lakeformation_permissions: Fix diffs resulting only from order of column names and exclude column names ([#19817](https://github.com/hashicorp/terraform-provider-aws/issues/19817)) * resource/aws_sqs_queue: Correctly handle the default `kms_data_key_reuse_period_seconds` value of `300` for unencrypted queues ([#19834](https://github.com/hashicorp/terraform-provider-aws/issues/19834)) ## 3.45.0 (June 10, 2021) From 1bf7a93834a6e731ebfa4d2967f276d69485f791 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 13:47:28 -0400 Subject: [PATCH 0541/1208] r/aws_eks_node_group: Use supported Kubernetes versions in acceptance tests. --- aws/resource_aws_eks_node_group_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_eks_node_group_test.go b/aws/resource_aws_eks_node_group_test.go index b3a685e6039b..927f63027014 100644 --- a/aws/resource_aws_eks_node_group_test.go +++ b/aws/resource_aws_eks_node_group_test.go @@ -318,10 +318,10 @@ func TestAccAWSEksNodeGroup_ForceUpdateVersion(t *testing.T) { CheckDestroy: testAccCheckAWSEksNodeGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksNodeGroupConfigForceUpdateVersion(rName, "1.15"), + Config: testAccAWSEksNodeGroupConfigForceUpdateVersion(rName, "1.19"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), - resource.TestCheckResourceAttr(resourceName, "version", "1.15"), + resource.TestCheckResourceAttr(resourceName, "version", "1.19"), ), }, { @@ -331,10 +331,10 @@ func TestAccAWSEksNodeGroup_ForceUpdateVersion(t *testing.T) { ImportStateVerifyIgnore: []string{"force_update_version"}, }, { - Config: testAccAWSEksNodeGroupConfigForceUpdateVersion(rName, "1.16"), + Config: testAccAWSEksNodeGroupConfigForceUpdateVersion(rName, "1.20"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), - resource.TestCheckResourceAttr(resourceName, "version", "1.16"), + resource.TestCheckResourceAttr(resourceName, "version", "1.20"), ), }, }, @@ -945,10 +945,10 @@ func TestAccAWSEksNodeGroup_Version(t *testing.T) { CheckDestroy: testAccCheckAWSEksNodeGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksNodeGroupConfigVersion(rName, "1.15"), + Config: testAccAWSEksNodeGroupConfigVersion(rName, "1.19"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup1), - resource.TestCheckResourceAttr(resourceName, "version", "1.15"), + resource.TestCheckResourceAttr(resourceName, "version", "1.19"), ), }, { @@ -957,11 +957,11 @@ func TestAccAWSEksNodeGroup_Version(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSEksNodeGroupConfigVersion(rName, "1.16"), + Config: testAccAWSEksNodeGroupConfigVersion(rName, "1.20"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup2), testAccCheckAWSEksNodeGroupNotRecreated(&nodeGroup1, &nodeGroup2), - resource.TestCheckResourceAttr(resourceName, "version", "1.16"), + resource.TestCheckResourceAttr(resourceName, "version", "1.20"), ), }, }, From d2ea6a1912390d27726239e751ccbb5645927f3c Mon Sep 17 00:00:00 2001 From: Phil Nichol <35630607+philnichol@users.noreply.github.com> Date: Thu, 17 Jun 2021 18:49:08 +0100 Subject: [PATCH 0542/1208] updated route table conflict warning (#19852) * updated route table conflict warning * fixed broken link --- website/docs/r/default_route_table.html.markdown | 3 ++- website/docs/r/main_route_table_association.html.markdown | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/website/docs/r/default_route_table.html.markdown b/website/docs/r/default_route_table.html.markdown index db79fd7435bc..775426780b31 100644 --- a/website/docs/r/default_route_table.html.markdown +++ b/website/docs/r/default_route_table.html.markdown @@ -10,7 +10,7 @@ description: |- Provides a resource to manage a default route table of a VPC. This resource can manage the default route table of the default or a non-default VPC. -~> **NOTE:** This is an advanced resource with special caveats. Please read this document in its entirety before using this resource. The `aws_default_route_table` resource behaves differently from normal resources. Terraform does not _create_ this resource but instead attempts to "adopt" it into management. **Do not** use both `aws_default_route_table` to manage a default route table **and** `aws_main_route_table_association` with the same VPC due to possible route conflicts. +~> **NOTE:** This is an advanced resource with special caveats. Please read this document in its entirety before using this resource. The `aws_default_route_table` resource behaves differently from normal resources. Terraform does not _create_ this resource but instead attempts to "adopt" it into management. **Do not** use both `aws_default_route_table` to manage a default route table **and** `aws_main_route_table_association` with the same VPC due to possible route conflicts. See [aws_main_route_table_association][tf-main-route-table-association] documentation for more details. Every VPC has a default route table that can be managed but not destroyed. When Terraform first adopts a default route table, it **immediately removes all defined routes**. It then proceeds to create any routes specified in the configuration. This step is required so that only the routes specified in the configuration exist in the default route table. @@ -107,3 +107,4 @@ $ terraform import aws_default_route_table.example vpc-33cc44dd [aws-route-tables]: http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Route_Tables.html#Route_Replacing_Main_Table [tf-route-tables]: /docs/providers/aws/r/route_table.html +[tf-main-route-table-association]: /docs/providers/aws/r/main_route_table_association.html \ No newline at end of file diff --git a/website/docs/r/main_route_table_association.html.markdown b/website/docs/r/main_route_table_association.html.markdown index fbe52a4ae521..0963c7d1fec3 100644 --- a/website/docs/r/main_route_table_association.html.markdown +++ b/website/docs/r/main_route_table_association.html.markdown @@ -10,6 +10,9 @@ description: |- Provides a resource for managing the main routing table of a VPC. +~> **NOTE:** **Do not** use both `aws_default_route_table` to manage a default route table **and** `aws_main_route_table_association` with the same VPC due to possible route conflicts. See [aws_default_route_table][tf-default-route-table] documentation for more details. +For more information, see the Amazon VPC User Guide on [Route Tables](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Route_Tables.html). For information about managing normal route tables in Terraform, see [`aws_route_table`](/docs/providers/aws/r/route_table.html). + ## Example Usage ```terraform @@ -42,3 +45,7 @@ The "Delete" action for a `main_route_table_association` consists of resetting this original table as the Main Route Table for the VPC. You'll see this additional Route Table in the AWS console; it must remain intact in order for the `main_route_table_association` delete to work properly. + +[aws-route-tables]: http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Route_Tables.html#Route_Replacing_Main_Table +[tf-route-tables]: /docs/providers/aws/r/route_table.html +[tf-default-route-table]: /docs/providers/aws/r/default_route_table.html \ No newline at end of file From 570f425247cbce87c9417f26ffa9985751fc0095 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Thu, 17 Jun 2021 14:12:31 -0400 Subject: [PATCH 0543/1208] add concurrency and ignore errors when deleting firewall manager web acls --- aws/resource_aws_wafv2_web_acl_test.go | 42 +++++++++++++++++--------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_wafv2_web_acl_test.go b/aws/resource_aws_wafv2_web_acl_test.go index 7451f528b193..d0de3847183a 100644 --- a/aws/resource_aws_wafv2_web_acl_test.go +++ b/aws/resource_aws_wafv2_web_acl_test.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/wafv2" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -24,12 +25,14 @@ func init() { func testSweepWafv2WebAcls(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafv2conn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafv2conn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error input := &wafv2.ListWebACLsInput{ Scope: aws.String(wafv2.ScopeRegional), @@ -41,6 +44,10 @@ func testSweepWafv2WebAcls(region string) error { } for _, webAcl := range page.WebACLs { + if webAcl == nil { + continue + } + id := aws.StringValue(webAcl.Id) r := resourceAwsWafv2WebACL() @@ -49,29 +56,36 @@ func testSweepWafv2WebAcls(region string) error { d.Set("lock_token", webAcl.LockToken) d.Set("name", webAcl.Name) d.Set("scope", input.Scope) - err := r.Delete(d, client) - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAFv2 Web ACL (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } return !lastPage }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAFv2 Web ACL sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing WAFv2 Web ACLs for %s: %w", region, err)) + } + + err = testSweepResourceOrchestrator(sweepResources) + + // Since we cannot exclude Firewall Manager WebACLs from the sweepResources var above, + // we instead catch and ignore the following expected AccessDeniedException. + // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/19149 + if tfawserr.ErrMessageContains(err, "AccessDeniedException", "managed by Firewall Manager") { + return errs.ErrorOrNil() } if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAFv2 Web ACLs: %w", err)) + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAFv2 Web ACLs for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAFv2 Web ACLs sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAwsWafv2WebACL_basic(t *testing.T) { From ef7d0e072fe93251c9244d8dd3140094f7a4159a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 12:46:35 -0400 Subject: [PATCH 0544/1208] provider: Add new data source --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index 09bb2c0de5d4..5e91aefcac2e 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -391,6 +391,7 @@ func Provider() *schema.Provider { "aws_secretsmanager_secret_rotation": dataSourceAwsSecretsManagerSecretRotation(), "aws_secretsmanager_secret_version": dataSourceAwsSecretsManagerSecretVersion(), "aws_servicecatalog_constraint": dataSourceAwsServiceCatalogConstraint(), + "aws_servicecatalog_portfolio": dataSourceAwsServiceCatalogPortfolio(), "aws_servicequotas_service": dataSourceAwsServiceQuotasService(), "aws_servicequotas_service_quota": dataSourceAwsServiceQuotasServiceQuota(), "aws_service_discovery_dns_namespace": dataSourceServiceDiscoveryDnsNamespace(), From 9cdfcfa47cffcee17f87808f2ea75602c3149e35 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 12:47:08 -0400 Subject: [PATCH 0545/1208] ds/servicecat_portfolio: New data source --- ...ata_source_aws_servicecatalog_portfolio.go | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 aws/data_source_aws_servicecatalog_portfolio.go diff --git a/aws/data_source_aws_servicecatalog_portfolio.go b/aws/data_source_aws_servicecatalog_portfolio.go new file mode 100644 index 000000000000..e1ea1cff1f4e --- /dev/null +++ b/aws/data_source_aws_servicecatalog_portfolio.go @@ -0,0 +1,98 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/servicecatalog" + "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" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" +) + +func dataSourceAwsServiceCatalogPortfolio() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsServiceCatalogPortfolioRead, + + Schema: map[string]*schema.Schema{ + "accept_language": { + Type: schema.TypeString, + Optional: true, + Default: "en", + ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "provider_name": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), + }, + } +} + +func dataSourceAwsServiceCatalogPortfolioRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + input := &servicecatalog.DescribePortfolioInput{ + Id: aws.String(d.Get("id").(string)), + } + + if v, ok := d.GetOk("accept_language"); ok { + input.AcceptLanguage = aws.String(v.(string)) + } + + output, err := conn.DescribePortfolio(input) + + if err != nil { + return fmt.Errorf("error getting Service Catalog Portfolio: %w", err) + } + + if output == nil || output.PortfolioDetail == nil { + return fmt.Errorf("error getting Service Catalog Portfolio: empty response") + } + + detail := output.PortfolioDetail + + d.SetId(aws.StringValue(detail.Id)) + + if err := d.Set("created_time", detail.CreatedTime.Format(time.RFC3339)); err != nil { + log.Printf("[DEBUG] Error setting created_time: %s", err) + } + + d.Set("arn", detail.ARN) + d.Set("description", detail.Description) + d.Set("name", detail.DisplayName) + d.Set("provider_name", detail.ProviderName) + + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + tags := keyvaluetags.ServicecatalogKeyValueTags(output.Tags) + + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + + return nil +} From af5495497ee59beaa560d6cde42393cb6ecea493 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 12:47:52 -0400 Subject: [PATCH 0546/1208] tests/ds/servicecat_portfolio: New data source --- ...ource_aws_servicecatalog_portfolio_test.go | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 aws/data_source_aws_servicecatalog_portfolio_test.go diff --git a/aws/data_source_aws_servicecatalog_portfolio_test.go b/aws/data_source_aws_servicecatalog_portfolio_test.go new file mode 100644 index 000000000000..4306faa9df18 --- /dev/null +++ b/aws/data_source_aws_servicecatalog_portfolio_test.go @@ -0,0 +1,44 @@ +package aws + +import ( + "testing" + + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSServiceCatalogPortfolioDataSource_basic(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_servicecatalog_portfolio.test" + resourceName := "aws_servicecatalog_portfolio.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckServiceCatlaogPortfolioDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsServiceCatalogPortfolioDataSourceConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_time", dataSourceName, "created_time"), + resource.TestCheckResourceAttrPair(resourceName, "description", dataSourceName, "description"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "provider_name", dataSourceName, "provider_name"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), + resource.TestCheckResourceAttrPair(resourceName, "tags.Chicane", dataSourceName, "tags.Chicane"), + ), + }, + }, + }) +} + +func testAccCheckAwsServiceCatalogPortfolioDataSourceConfigBasic(rName string) string { + return composeConfig(testAccCheckAwsServiceCatalogPortfolioResourceConfigTags1(rName, "Chicane", "Nick"), ` +data "aws_servicecatalog_portfolio" "test" { + id = aws_servicecatalog_portfolio.test.id +} +`) +} From 0a66ba485093297d5ab2a6398112ba6f999d3920 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 12:48:08 -0400 Subject: [PATCH 0547/1208] docs/ds/servicecat_portfolio: New data source --- .../d/servicecatalog_portfolio.html.markdown | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 website/docs/d/servicecatalog_portfolio.html.markdown diff --git a/website/docs/d/servicecatalog_portfolio.html.markdown b/website/docs/d/servicecatalog_portfolio.html.markdown new file mode 100644 index 000000000000..5bab83d5d4ba --- /dev/null +++ b/website/docs/d/servicecatalog_portfolio.html.markdown @@ -0,0 +1,40 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_portfolio" +description: |- + Provides information for a Service Catalog Portfolio. +--- + +# Data source: aws_servicecatalog_portfolio + +Provides information for a Service Catalog Portfolio. + +## Example Usage + +```terraform +data "aws_servicecatalog_portfolio" "portfolio" { + id = "port-07052002" +} +``` + +## Argument Reference + +The following arguments are required: + +* `id` - (Optional) Portfolio identifier. + +The following arguments are optional: + +* `accept_language` - (Optional) Language code. Valid values: `en` (English), `jp` (Japanese), `zh` (Chinese). Default value is `en`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - Portfolio ARN. +* `created_time` - Time the portfolio was created. +* `description` - Description of the portfolio +* `name` - Portfolio name. +* `provider_name` - Name of the person or organization who owns the portfolio. +* `tags` - Tags applied to the portfolio. From 52222ef730907491027dd4ffe3f8d682445af9c9 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 12:49:49 -0400 Subject: [PATCH 0548/1208] ds/servicecat_portfolio: Add changelog --- .changelog/19500.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19500.txt diff --git a/.changelog/19500.txt b/.changelog/19500.txt new file mode 100644 index 000000000000..d6a9282b976a --- /dev/null +++ b/.changelog/19500.txt @@ -0,0 +1,3 @@ +```release-notes:new-data-source + aws_servicecatalog_portfolio + ``` \ No newline at end of file From ecf8c67d95d3bddf3f04c3a3c1697b2dabaa7287 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 14:26:05 -0400 Subject: [PATCH 0549/1208] ds/servicecat_portfolio: Make tags computed --- aws/data_source_aws_servicecatalog_portfolio.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/data_source_aws_servicecatalog_portfolio.go b/aws/data_source_aws_servicecatalog_portfolio.go index e1ea1cff1f4e..abfda971b046 100644 --- a/aws/data_source_aws_servicecatalog_portfolio.go +++ b/aws/data_source_aws_servicecatalog_portfolio.go @@ -32,6 +32,10 @@ func dataSourceAwsServiceCatalogPortfolio() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "description": { + Type: schema.TypeString, + Computed: true, + }, "id": { Type: schema.TypeString, Required: true, @@ -40,15 +44,11 @@ func dataSourceAwsServiceCatalogPortfolio() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "description": { - Type: schema.TypeString, - Computed: true, - }, "provider_name": { Type: schema.TypeString, Computed: true, }, - "tags": tagsSchema(), + "tags": tagsSchemaComputed(), }, } } From e62f3abbf3c63cc5070f8d2fb8ac7c759ec09a0b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 14:48:38 -0400 Subject: [PATCH 0550/1208] ds/servicecat_port: Fix changelog --- .changelog/19500.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/19500.txt b/.changelog/19500.txt index d6a9282b976a..46d3a1e003a5 100644 --- a/.changelog/19500.txt +++ b/.changelog/19500.txt @@ -1,3 +1,3 @@ -```release-notes:new-data-source +```release-note:new-data-source aws_servicecatalog_portfolio ``` \ No newline at end of file From 63118a4a76289033880acb6984cc37550dabb09b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 14:49:21 -0400 Subject: [PATCH 0551/1208] ds/servicecat_port: Minor fixes --- aws/data_source_aws_servicecatalog_portfolio.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/data_source_aws_servicecatalog_portfolio.go b/aws/data_source_aws_servicecatalog_portfolio.go index abfda971b046..8ad11c0924e5 100644 --- a/aws/data_source_aws_servicecatalog_portfolio.go +++ b/aws/data_source_aws_servicecatalog_portfolio.go @@ -67,18 +67,18 @@ func dataSourceAwsServiceCatalogPortfolioRead(d *schema.ResourceData, meta inter output, err := conn.DescribePortfolio(input) if err != nil { - return fmt.Errorf("error getting Service Catalog Portfolio: %w", err) + return fmt.Errorf("error getting Service Catalog Portfolio (%s): %w", d.Get("id").(string), err) } if output == nil || output.PortfolioDetail == nil { - return fmt.Errorf("error getting Service Catalog Portfolio: empty response") + return fmt.Errorf("error getting Service Catalog Portfolio (%s): empty response", d.Get("id").(string)) } detail := output.PortfolioDetail d.SetId(aws.StringValue(detail.Id)) - if err := d.Set("created_time", detail.CreatedTime.Format(time.RFC3339)); err != nil { + if err := d.Set("created_time", aws.TimeValue(detail.CreatedTime).Format(time.RFC3339)); err != nil { log.Printf("[DEBUG] Error setting created_time: %s", err) } From d6c006a602dc1cfa23e5388b6c35c17991c2f946 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 14:49:50 -0400 Subject: [PATCH 0552/1208] docs/ds/servicecat_port: Fix docs --- website/docs/d/servicecatalog_portfolio.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/d/servicecatalog_portfolio.html.markdown b/website/docs/d/servicecatalog_portfolio.html.markdown index 5bab83d5d4ba..438c25fd3f4f 100644 --- a/website/docs/d/servicecatalog_portfolio.html.markdown +++ b/website/docs/d/servicecatalog_portfolio.html.markdown @@ -6,7 +6,7 @@ description: |- Provides information for a Service Catalog Portfolio. --- -# Data source: aws_servicecatalog_portfolio +# Data Source: aws_servicecatalog_portfolio Provides information for a Service Catalog Portfolio. @@ -22,7 +22,7 @@ data "aws_servicecatalog_portfolio" "portfolio" { The following arguments are required: -* `id` - (Optional) Portfolio identifier. +* `id` - (Required) Portfolio identifier. The following arguments are optional: From bd9002cc937bf376904c318bbf44b0efb8cf7a3b Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Thu, 17 Jun 2021 15:03:42 -0400 Subject: [PATCH 0553/1208] add networkfirewall firewall sweeper dep --- aws/resource_aws_subnet_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_subnet_test.go b/aws/resource_aws_subnet_test.go index 7d6c8b6053c8..e529c9aae20f 100644 --- a/aws/resource_aws_subnet_test.go +++ b/aws/resource_aws_subnet_test.go @@ -45,6 +45,7 @@ func init() { "aws_mq_broker", "aws_msk_cluster", "aws_network_interface", + "aws_networkfirewall_firewall", "aws_redshift_cluster", "aws_route53_resolver_endpoint", "aws_sagemaker_notebook_instance", From 71f75c7af437ba17f61ee0685569774d95b58b7d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 15:09:33 -0400 Subject: [PATCH 0554/1208] r/codedeploy_app: Fix, parallelize sweeper --- aws/resource_aws_codedeploy_app_test.go | 30 ++++++++++++++----------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/aws/resource_aws_codedeploy_app_test.go b/aws/resource_aws_codedeploy_app_test.go index 1c5fcdf7c28f..751c12471ddd 100644 --- a/aws/resource_aws_codedeploy_app_test.go +++ b/aws/resource_aws_codedeploy_app_test.go @@ -23,12 +23,16 @@ func init() { func testSweepCodeDeployApps(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } + conn := client.(*AWSClient).codedeployconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + input := &codedeploy.ListApplicationsInput{} - var sweeperErrs *multierror.Error err = conn.ListApplicationsPages(input, func(page *codedeploy.ListApplicationsOutput, lastPage bool) bool { for _, app := range page.Applications { @@ -40,28 +44,28 @@ func testSweepCodeDeployApps(region string) error { r := resourceAwsCodeDeployApp() d := r.Data(nil) d.SetId(fmt.Sprintf("%s:%s", "xxxx", appName)) - err = r.Delete(d, client) + d.Set("name", appName) - if err != nil { - sweeperErr := fmt.Errorf("error deleting CodeDeploy Application (%s): %w", appName, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - } + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } return !lastPage }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping CodeDeploy Application sweep for %s: %s", region, err) - return nil + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing CodeDeploy Applications for %s: %w", region, err)) } - if err != nil { - return fmt.Errorf("error listing CodeDeploy Applications: %w", err) + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping CodeDeploy Applications for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping CodeDeploy Applications sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAWSCodeDeployApp_basic(t *testing.T) { From 0eade2b84bb090a10effa2051c3e119595cbe316 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 17 Jun 2021 19:09:44 +0000 Subject: [PATCH 0555/1208] Update CHANGELOG.md for #19831 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fea90ff986ad..689c9308aa58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ENHANCEMENTS: * resource/aws_datasync_location_nfs: Add support for updating. ([#19767](https://github.com/hashicorp/terraform-provider-aws/issues/19767)) * resource/aws_ecs_cluster: Add plan time validation for `name`. ([#19785](https://github.com/hashicorp/terraform-provider-aws/issues/19785)) * resource/aws_ecs_cluster: Add support for `configuration`. ([#19785](https://github.com/hashicorp/terraform-provider-aws/issues/19785)) +* resource/aws_eks_node_group: Allow minimum value of `0` for `desired_size` and `min_size` in the `scaling_config` configuration block ([#19810](https://github.com/hashicorp/terraform-provider-aws/issues/19810)) * resource/aws_spot_fleet_request: Add `on_demand_allocation_strategy`, `on_demand_max_total_price`, and `on_demand_target_capacity` arguments ([#13127](https://github.com/hashicorp/terraform-provider-aws/issues/13127)) BUG FIXES: @@ -24,6 +25,7 @@ BUG FIXES: * resource/aws_lakeformation_permissions: Fix bug preventing updates (inconsistent result) ([#19817](https://github.com/hashicorp/terraform-provider-aws/issues/19817)) * resource/aws_lakeformation_permissions: Fix bug where resource is not properly removed from state ([#19817](https://github.com/hashicorp/terraform-provider-aws/issues/19817)) * resource/aws_lakeformation_permissions: Fix diffs resulting only from order of column names and exclude column names ([#19817](https://github.com/hashicorp/terraform-provider-aws/issues/19817)) +* resource/aws_lambda_event_source_mapping: Enhance handling of IAM eventual consistency errors during create ([#19831](https://github.com/hashicorp/terraform-provider-aws/issues/19831)) * resource/aws_sqs_queue: Correctly handle the default `kms_data_key_reuse_period_seconds` value of `300` for unencrypted queues ([#19834](https://github.com/hashicorp/terraform-provider-aws/issues/19834)) ## 3.45.0 (June 10, 2021) From cc109811718b9936a97f05c1901a4d5283e8cd36 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 17 Jun 2021 20:01:04 +0000 Subject: [PATCH 0556/1208] Update CHANGELOG.md for #19500 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 689c9308aa58..3ca9317be6ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ FEATURES: * **New Data Source:** `aws_appmesh_virtual_service` ([#19774](https://github.com/hashicorp/terraform-provider-aws/issues/19774)) +* **New Data Source:** `aws_servicecatalog_portfolio` ([#19500](https://github.com/hashicorp/terraform-provider-aws/issues/19500)) * **New Resource:** `aws_budgets_budget_action` ([#19554](https://github.com/hashicorp/terraform-provider-aws/issues/19554)) * **New Resource:** `aws_route53_resolver_firewall_config` ([#18733](https://github.com/hashicorp/terraform-provider-aws/issues/18733)) From a19cb6df0b90de79ce9d7062ea223e9da36ac3be Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 14:05:32 -0400 Subject: [PATCH 0557/1208] tests/r/waf_byte_match_set: Add sweeper concurrency --- aws/resource_aws_waf_byte_match_set_test.go | 46 +++++++++++---------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/aws/resource_aws_waf_byte_match_set_test.go b/aws/resource_aws_waf_byte_match_set_test.go index d68ceaa84180..1ff3f4170108 100644 --- a/aws/resource_aws_waf_byte_match_set_test.go +++ b/aws/resource_aws_waf_byte_match_set_test.go @@ -29,25 +29,27 @@ func init() { func testSweepWafByteMatchSet(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error input := &waf.ListByteMatchSetsInput{} - err = lister.ListByteMatchSetsPages(conn, input, func(page *waf.ListByteMatchSetsOutput, lastPage bool) bool { + err = lister.ListByteMatchSetsPages(conn, input, func(page *waf.ListByteMatchSetsOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, byteMatchSet := range page.ByteMatchSets { - id := aws.StringValue(byteMatchSet.ByteMatchSetId) - r := resourceAwsWafByteMatchSet() d := r.Data(nil) + + id := aws.StringValue(byteMatchSet.ByteMatchSetId) d.SetId(id) // Need to Read first to fill in byte_match_tuples attribute @@ -56,7 +58,7 @@ func testSweepWafByteMatchSet(region string) error { if err != nil { sweeperErr := fmt.Errorf("error reading WAF Byte Match Set (%s): %w", id, err) log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + errs = multierror.Append(errs, sweeperErr) continue } @@ -65,29 +67,29 @@ func testSweepWafByteMatchSet(region string) error { continue } - err = r.Delete(d, client) - - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF Byte Match Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF Byte Match Set sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF Byte Match Set for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF Byte Match Sets: %w", err)) + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Byte Match Set for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF Byte Match Set sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAWSWafByteMatchSet_basic(t *testing.T) { From b22a9d545e95821065363b5ccffc70abf7898ed8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 14:08:47 -0400 Subject: [PATCH 0558/1208] tests/r/waf_geo_match_set: Add sweeper concurrency --- aws/resource_aws_waf_geo_match_set_test.go | 46 +++++++++++----------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/aws/resource_aws_waf_geo_match_set_test.go b/aws/resource_aws_waf_geo_match_set_test.go index 2646dafc1621..f1bcbbc6638f 100644 --- a/aws/resource_aws_waf_geo_match_set_test.go +++ b/aws/resource_aws_waf_geo_match_set_test.go @@ -29,25 +29,27 @@ func init() { func testSweepWafGeoMatchSet(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error input := &waf.ListGeoMatchSetsInput{} - err = lister.ListGeoMatchSetsPages(conn, input, func(page *waf.ListGeoMatchSetsOutput, lastPage bool) bool { + err = lister.ListGeoMatchSetsPages(conn, input, func(page *waf.ListGeoMatchSetsOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, geoMatchSet := range page.GeoMatchSets { - id := aws.StringValue(geoMatchSet.GeoMatchSetId) - r := resourceAwsWafGeoMatchSet() d := r.Data(nil) + + id := aws.StringValue(geoMatchSet.GeoMatchSetId) d.SetId(id) // Need to Read first to fill in geo_match_constraint attribute @@ -56,7 +58,7 @@ func testSweepWafGeoMatchSet(region string) error { if err != nil { sweeperErr := fmt.Errorf("error reading WAF Geo Match Set (%s): %w", id, err) log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + errs = multierror.Append(errs, sweeperErr) continue } @@ -65,29 +67,29 @@ func testSweepWafGeoMatchSet(region string) error { continue } - err = r.Delete(d, client) - - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF Geo Match Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF Geo Match Set sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF Geo Match Set for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF Geo Match Sets: %w", err)) + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Geo Match Set for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF Geo Match Set sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAWSWafGeoMatchSet_basic(t *testing.T) { From c27563ce43c35b0ab4ae726a8e5e6f0c1cd3669d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 14:12:08 -0400 Subject: [PATCH 0559/1208] tests/r/waf_ipset: Add sweeper concurrency --- aws/resource_aws_waf_ipset_test.go | 46 ++++++++++++++++-------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/aws/resource_aws_waf_ipset_test.go b/aws/resource_aws_waf_ipset_test.go index 2adb16a2bccd..e84601bc24e8 100644 --- a/aws/resource_aws_waf_ipset_test.go +++ b/aws/resource_aws_waf_ipset_test.go @@ -32,25 +32,27 @@ func init() { func testSweepWafIPSet(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error input := &waf.ListIPSetsInput{} - err = lister.ListIPSetsPages(conn, input, func(page *waf.ListIPSetsOutput, lastPage bool) bool { + err = lister.ListIPSetsPages(conn, input, func(page *waf.ListIPSetsOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, ipSet := range page.IPSets { - id := aws.StringValue(ipSet.IPSetId) - r := resourceAwsWafIPSet() d := r.Data(nil) + + id := aws.StringValue(ipSet.IPSetId) d.SetId(id) // Need to Read first to fill in ip_set_descriptors attribute @@ -59,7 +61,7 @@ func testSweepWafIPSet(region string) error { if err != nil { sweeperErr := fmt.Errorf("error reading WAF IP Set (%s): %w", id, err) log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + errs = multierror.Append(errs, sweeperErr) continue } @@ -68,29 +70,31 @@ func testSweepWafIPSet(region string) error { continue } - err = r.Delete(d, client) + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF IP Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + err = r.Delete(d, client) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF IP Set sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF IP Set for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF IP Sets: %w", err)) + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF IP Set for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF IP Set sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAWSWafIPSet_basic(t *testing.T) { From f3dbf444804704225f53d078b51d3c42520ad40d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 14:42:09 -0400 Subject: [PATCH 0560/1208] tests/r/waf_byte_match_set: Add read concurrency --- aws/resource_aws_waf_byte_match_set_test.go | 40 ++++++++++++++------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/aws/resource_aws_waf_byte_match_set_test.go b/aws/resource_aws_waf_byte_match_set_test.go index 1ff3f4170108..99f3295bd607 100644 --- a/aws/resource_aws_waf_byte_match_set_test.go +++ b/aws/resource_aws_waf_byte_match_set_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -40,6 +41,9 @@ func testSweepWafByteMatchSet(region string) error { input := &waf.ListByteMatchSetsInput{} + var g multierror.Group + var mutex = &sync.Mutex{} + err = lister.ListByteMatchSetsPages(conn, input, func(page *waf.ListByteMatchSetsOutput, isLast bool) bool { if page == nil { return !isLast @@ -52,22 +56,28 @@ func testSweepWafByteMatchSet(region string) error { id := aws.StringValue(byteMatchSet.ByteMatchSetId) d.SetId(id) - // Need to Read first to fill in byte_match_tuples attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { + // Need to Read first to fill in byte_match_tuples attribute + err := r.Read(d, client) - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF Byte Match Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - errs = multierror.Append(errs, sweeperErr) - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF Byte Match Set (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } - // In case it was already deleted - if d.Id() == "" { - continue - } + // In case it was already deleted + if d.Id() == "" { + return nil + } - sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + + return nil + }) } return !isLast @@ -77,6 +87,10 @@ func testSweepWafByteMatchSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error listing WAF Byte Match Set for %s: %w", region, err)) } + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Byte Match Sets: %w", err)) + } + if len(sweepResources) > 0 { // Any errors didn't prevent gathering some sweeping work, so do it. if err := testSweepResourceOrchestrator(sweepResources); err != nil { From 6459516a55781a214148bc6ed5a20fa7e00d9d3b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 14:46:53 -0400 Subject: [PATCH 0561/1208] tests/r/waf_geo_match_set: Add read concurrency --- aws/resource_aws_waf_geo_match_set_test.go | 41 +++++++++++++++------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/aws/resource_aws_waf_geo_match_set_test.go b/aws/resource_aws_waf_geo_match_set_test.go index f1bcbbc6638f..0939b9c9da14 100644 --- a/aws/resource_aws_waf_geo_match_set_test.go +++ b/aws/resource_aws_waf_geo_match_set_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -40,6 +41,9 @@ func testSweepWafGeoMatchSet(region string) error { input := &waf.ListGeoMatchSetsInput{} + var g multierror.Group + var mutex = &sync.Mutex{} + err = lister.ListGeoMatchSetsPages(conn, input, func(page *waf.ListGeoMatchSetsOutput, isLast bool) bool { if page == nil { return !isLast @@ -52,22 +56,29 @@ func testSweepWafGeoMatchSet(region string) error { id := aws.StringValue(geoMatchSet.GeoMatchSetId) d.SetId(id) - // Need to Read first to fill in geo_match_constraint attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF Geo Match Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - errs = multierror.Append(errs, sweeperErr) - continue - } + // Need to Read first to fill in geo_match_constraint attribute + err := r.Read(d, client) - // In case it was already deleted - if d.Id() == "" { - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF Geo Match Set (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } + + // In case it was already deleted + if d.Id() == "" { + return nil + } + + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) - sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + return nil + }) } return !isLast @@ -77,6 +88,10 @@ func testSweepWafGeoMatchSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error listing WAF Geo Match Set for %s: %w", region, err)) } + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Geo Match Sets: %w", err)) + } + if len(sweepResources) > 0 { // Any errors didn't prevent gathering some sweeping work, so do it. if err := testSweepResourceOrchestrator(sweepResources); err != nil { From 46442951394a9c6c8956bfd4874f5018d23bfb5c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 14:50:27 -0400 Subject: [PATCH 0562/1208] tests/r/waf_ipset: Add read concurrency --- aws/resource_aws_waf_ipset_test.go | 40 +++++++++++++++++++----------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_waf_ipset_test.go b/aws/resource_aws_waf_ipset_test.go index e84601bc24e8..9137c5e424b2 100644 --- a/aws/resource_aws_waf_ipset_test.go +++ b/aws/resource_aws_waf_ipset_test.go @@ -7,6 +7,7 @@ import ( "reflect" "regexp" "strings" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -40,6 +41,8 @@ func testSweepWafIPSet(region string) error { conn := client.(*AWSClient).wafconn sweepResources := make([]*testSweepResource, 0) var errs *multierror.Error + var g multierror.Group + var mutex = &sync.Mutex{} input := &waf.ListIPSetsInput{} @@ -55,24 +58,29 @@ func testSweepWafIPSet(region string) error { id := aws.StringValue(ipSet.IPSetId) d.SetId(id) - // Need to Read first to fill in ip_set_descriptors attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF IP Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - errs = multierror.Append(errs, sweeperErr) - continue - } + // Need to Read first to fill in ip_set_descriptors attribute + err := r.Read(d, client) - // In case it was already deleted - if d.Id() == "" { - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF IP Set (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } + + // In case it was already deleted + if d.Id() == "" { + return nil + } - sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) - err = r.Delete(d, client) + return nil + }) } return !isLast @@ -82,6 +90,10 @@ func testSweepWafIPSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error listing WAF IP Set for %s: %w", region, err)) } + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF IP Sets: %w", err)) + } + if len(sweepResources) > 0 { // Any errors didn't prevent gathering some sweeping work, so do it. if err := testSweepResourceOrchestrator(sweepResources); err != nil { From 3671afd20079932c660d0b2880c241dffbf39f55 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 14:53:39 -0400 Subject: [PATCH 0563/1208] tests/r/waf_rate_based_rule: Add sweeper concurrency --- aws/resource_aws_waf_rate_based_rule_test.go | 80 ++++++++++++-------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/aws/resource_aws_waf_rate_based_rule_test.go b/aws/resource_aws_waf_rate_based_rule_test.go index 049831b9478b..ec422edc45bb 100644 --- a/aws/resource_aws_waf_rate_based_rule_test.go +++ b/aws/resource_aws_waf_rate_based_rule_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -29,65 +30,80 @@ func init() { func testSweepWafRateBasedRules(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + var g multierror.Group + var mutex = &sync.Mutex{} input := &waf.ListRateBasedRulesInput{} - err = lister.ListRateBasedRulesPages(conn, input, func(page *waf.ListRateBasedRulesOutput, lastPage bool) bool { + err = lister.ListRateBasedRulesPages(conn, input, func(page *waf.ListRateBasedRulesOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, rule := range page.Rules { - id := aws.StringValue(rule.RuleId) - r := resourceAwsWafRateBasedRule() d := r.Data(nil) + + id := aws.StringValue(rule.RuleId) d.SetId(id) - // Need to Read first to fill in predicates attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF Rate Based Rule (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + // Need to Read first to fill in predicates attribute + err := r.Read(d, client) - // In case it was already deleted - if d.Id() == "" { - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF Rate Based Rule (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } - err = r.Delete(d, client) + // In case it was already deleted + if d.Id() == "" { + return nil + } - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF Rate Based Rule (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + + return nil + }) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF Rate Based Rule sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF Rate Based Rule for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF Rate Based Rules: %w", err)) + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Rate Based Rules: %w", err)) + } + + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Rate Based Rule for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF Rate Based Rule sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAWSWafRateBasedRule_basic(t *testing.T) { From 0af45b963b7c73a7b85236311ca42e3f8bbf3d1f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 15:03:06 -0400 Subject: [PATCH 0564/1208] tests/r/waf_regex_match_set: Add sweeper concurrency --- aws/resource_aws_waf_geo_match_set_test.go | 1 - aws/resource_aws_waf_ipset_test.go | 1 - aws/resource_aws_waf_rate_based_rule_test.go | 1 - aws/resource_aws_waf_regex_match_set_test.go | 79 ++++++++++++-------- 4 files changed, 47 insertions(+), 35 deletions(-) diff --git a/aws/resource_aws_waf_geo_match_set_test.go b/aws/resource_aws_waf_geo_match_set_test.go index 0939b9c9da14..2c8b7ff3fb30 100644 --- a/aws/resource_aws_waf_geo_match_set_test.go +++ b/aws/resource_aws_waf_geo_match_set_test.go @@ -58,7 +58,6 @@ func testSweepWafGeoMatchSet(region string) error { // read concurrently and gather errors g.Go(func() error { - // Need to Read first to fill in geo_match_constraint attribute err := r.Read(d, client) diff --git a/aws/resource_aws_waf_ipset_test.go b/aws/resource_aws_waf_ipset_test.go index 9137c5e424b2..eba5cbd863af 100644 --- a/aws/resource_aws_waf_ipset_test.go +++ b/aws/resource_aws_waf_ipset_test.go @@ -60,7 +60,6 @@ func testSweepWafIPSet(region string) error { // read concurrently and gather errors g.Go(func() error { - // Need to Read first to fill in ip_set_descriptors attribute err := r.Read(d, client) diff --git a/aws/resource_aws_waf_rate_based_rule_test.go b/aws/resource_aws_waf_rate_based_rule_test.go index ec422edc45bb..34f1bafc4721 100644 --- a/aws/resource_aws_waf_rate_based_rule_test.go +++ b/aws/resource_aws_waf_rate_based_rule_test.go @@ -57,7 +57,6 @@ func testSweepWafRateBasedRules(region string) error { // read concurrently and gather errors g.Go(func() error { - // Need to Read first to fill in predicates attribute err := r.Read(d, client) diff --git a/aws/resource_aws_waf_regex_match_set_test.go b/aws/resource_aws_waf_regex_match_set_test.go index 22c813c75a29..54769e0146dc 100644 --- a/aws/resource_aws_waf_regex_match_set_test.go +++ b/aws/resource_aws_waf_regex_match_set_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -29,65 +30,79 @@ func init() { func testSweepWafRegexMatchSet(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + var g multierror.Group + var mutex = &sync.Mutex{} input := &waf.ListRegexMatchSetsInput{} - err = lister.ListRegexMatchSetsPages(conn, input, func(page *waf.ListRegexMatchSetsOutput, lastPage bool) bool { + err = lister.ListRegexMatchSetsPages(conn, input, func(page *waf.ListRegexMatchSetsOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, regexMatchSet := range page.RegexMatchSets { - id := aws.StringValue(regexMatchSet.RegexMatchSetId) - r := resourceAwsWafRegexMatchSet() d := r.Data(nil) + + id := aws.StringValue(regexMatchSet.RegexMatchSetId) d.SetId(id) - // Need to Read first to fill in regex_match_tuple attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { + // Need to Read first to fill in regex_match_tuple attribute + err := r.Read(d, client) - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF Regex Match Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF Regex Match Set (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } - // In case it was already deleted - if d.Id() == "" { - continue - } + // In case it was already deleted + if d.Id() == "" { + return nil + } - err = r.Delete(d, client) + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF Regex Match Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + return nil + }) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF Regex Match Set sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF Regex Match Set for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF Regex Match Sets: %w", err)) + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Regex Match Sets: %w", err)) + } + + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Regex Match Set for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF Regex Match Set sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } // Serialized acceptance tests due to WAF account limits From d3f72662dc09078dbc6dada576657a403442aa08 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 15:07:52 -0400 Subject: [PATCH 0565/1208] tests/r/waf_regex_pattern_set: Add sweeper concurrency --- ...resource_aws_waf_regex_pattern_set_test.go | 79 +++++++++++-------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/aws/resource_aws_waf_regex_pattern_set_test.go b/aws/resource_aws_waf_regex_pattern_set_test.go index cf60a8407edc..1e7f177fba09 100644 --- a/aws/resource_aws_waf_regex_pattern_set_test.go +++ b/aws/resource_aws_waf_regex_pattern_set_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -29,65 +30,79 @@ func init() { func testSweepWafRegexPatternSet(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + var g multierror.Group + var mutex = &sync.Mutex{} input := &waf.ListRegexPatternSetsInput{} - err = lister.ListRegexPatternSetsPages(conn, input, func(page *waf.ListRegexPatternSetsOutput, lastPage bool) bool { + err = lister.ListRegexPatternSetsPages(conn, input, func(page *waf.ListRegexPatternSetsOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, regexPatternSet := range page.RegexPatternSets { - id := aws.StringValue(regexPatternSet.RegexPatternSetId) - r := resourceAwsWafRegexPatternSet() d := r.Data(nil) + + id := aws.StringValue(regexPatternSet.RegexPatternSetId) d.SetId(id) - // Need to Read first to fill in regex_pattern_strings attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { + // Need to Read first to fill in regex_pattern_strings attribute + err := r.Read(d, client) - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF Regex Pattern Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF Regex Pattern Set (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } - // In case it was already deleted - if d.Id() == "" { - continue - } + // In case it was already deleted + if d.Id() == "" { + return nil + } - err = r.Delete(d, client) + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF Regex Pattern Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + return nil + }) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF Regex Pattern Set sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF Regex Pattern Set for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF Regex Pattern Sets: %w", err)) + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Regex Pattern Sets: %w", err)) + } + + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Regex Pattern Set for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF Regex Pattern Set sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } // Serialized acceptance tests due to WAF account limits From c0f254f0373af60263ac81f7127e9df0a2cd6712 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 15:14:46 -0400 Subject: [PATCH 0566/1208] tests/r/waf_rule_group: Add sweeper concurrency --- aws/resource_aws_waf_rule_group_test.go | 79 +++++++++++++++---------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/aws/resource_aws_waf_rule_group_test.go b/aws/resource_aws_waf_rule_group_test.go index 3e76773659d4..172037f9dbbd 100644 --- a/aws/resource_aws_waf_rule_group_test.go +++ b/aws/resource_aws_waf_rule_group_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -28,65 +29,79 @@ func init() { func testSweepWafRuleGroups(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + var g multierror.Group + var mutex = &sync.Mutex{} input := &waf.ListRuleGroupsInput{} - err = lister.ListRuleGroupsPages(conn, input, func(page *waf.ListRuleGroupsOutput, lastPage bool) bool { + err = lister.ListRuleGroupsPages(conn, input, func(page *waf.ListRuleGroupsOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, ruleGroup := range page.RuleGroups { - id := aws.StringValue(ruleGroup.RuleGroupId) - r := resourceAwsWafRuleGroup() d := r.Data(nil) + + id := aws.StringValue(ruleGroup.RuleGroupId) d.SetId(id) - // Need to Read first to fill in activated_rule attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { + // Need to Read first to fill in activated_rule attribute + err := r.Read(d, client) - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF Rule Group (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF Rule Group (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } - // In case it was already deleted - if d.Id() == "" { - continue - } + // In case it was already deleted + if d.Id() == "" { + return nil + } - err = r.Delete(d, client) + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF Rule Group (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + return nil + }) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF Rule Group sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF Rule Group for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF Rule Groups: %w", err)) + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Rule Groups: %w", err)) + } + + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Rule Group for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF Rule Group sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAWSWafRuleGroup_basic(t *testing.T) { From 4d59d821b4026bb47fba0ea75e8d5405705a6962 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 15:18:30 -0400 Subject: [PATCH 0567/1208] tests/r/waf_rule: Add sweeper concurrency --- aws/resource_aws_waf_rule_test.go | 79 ++++++++++++++++++------------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/aws/resource_aws_waf_rule_test.go b/aws/resource_aws_waf_rule_test.go index 2e31b4412777..be84290e4b24 100644 --- a/aws/resource_aws_waf_rule_test.go +++ b/aws/resource_aws_waf_rule_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -29,18 +30,22 @@ func init() { func testSweepWafRules(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + var g multierror.Group + var mutex = &sync.Mutex{} input := &waf.ListRulesInput{} - err = lister.ListRulesPages(conn, input, func(page *waf.ListRulesOutput, lastPage bool) bool { + err = lister.ListRulesPages(conn, input, func(page *waf.ListRulesOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, rule := range page.Rules { @@ -48,50 +53,60 @@ func testSweepWafRules(region string) error { continue } - id := aws.StringValue(rule.RuleId) - r := resourceAwsWafRule() d := r.Data(nil) + + id := aws.StringValue(rule.RuleId) d.SetId(id) - // Need to Read first to fill in predicates attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { + // Need to Read first to fill in predicates attribute + err := r.Read(d, client) - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF Rule (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF Rule (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } - // In case it was already deleted - if d.Id() == "" { - continue - } + // In case it was already deleted + if d.Id() == "" { + return nil + } - err = r.Delete(d, client) + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF Rule (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + return nil + }) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF Rule sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF Rules for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF Rules: %w", err)) + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Rules: %w", err)) + } + + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Rules for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF Rule sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAWSWafRule_basic(t *testing.T) { From c572b505a2558609610224c73a93ca2f0a947deb Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 15:22:01 -0400 Subject: [PATCH 0568/1208] tests/r/waf_size_constraint_set: Add sweeper concurrency --- ...source_aws_waf_size_constraint_set_test.go | 79 +++++++++++-------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/aws/resource_aws_waf_size_constraint_set_test.go b/aws/resource_aws_waf_size_constraint_set_test.go index b577de19ad69..8a5f034e988d 100644 --- a/aws/resource_aws_waf_size_constraint_set_test.go +++ b/aws/resource_aws_waf_size_constraint_set_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -30,65 +31,79 @@ func init() { func testSweepWafSizeConstraintSet(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + var g multierror.Group + var mutex = &sync.Mutex{} input := &waf.ListSizeConstraintSetsInput{} - err = lister.ListSizeConstraintSetsPages(conn, input, func(page *waf.ListSizeConstraintSetsOutput, lastPage bool) bool { + err = lister.ListSizeConstraintSetsPages(conn, input, func(page *waf.ListSizeConstraintSetsOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, sizeConstraintSet := range page.SizeConstraintSets { - id := aws.StringValue(sizeConstraintSet.SizeConstraintSetId) - r := resourceAwsWafSizeConstraintSet() d := r.Data(nil) + + id := aws.StringValue(sizeConstraintSet.SizeConstraintSetId) d.SetId(id) - // Need to Read first to fill in size_constraints attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { + // Need to Read first to fill in size_constraints attribute + err := r.Read(d, client) - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF Size Constraint Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF Size Constraint Set (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } - // In case it was already deleted - if d.Id() == "" { - continue - } + // In case it was already deleted + if d.Id() == "" { + return nil + } - err = r.Delete(d, client) + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF Size Constraint Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + return nil + }) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF Size Constraint Set sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF Size Constraint Sets for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF Size Constraint Sets: %w", err)) + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Size Constraint Sets: %w", err)) + } + + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Size Constraint Sets for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF Size Constraint Set sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAWSWafSizeConstraintSet_basic(t *testing.T) { From 2404a91655f507c5b9535906f4fb75b8b57b5d84 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 15:25:24 -0400 Subject: [PATCH 0569/1208] tests/r/waf_sql_injection_match_set: Add sweeper concurrency --- ...ce_aws_waf_sql_injection_match_set_test.go | 79 +++++++++++-------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/aws/resource_aws_waf_sql_injection_match_set_test.go b/aws/resource_aws_waf_sql_injection_match_set_test.go index 9b007fe13849..6da0facdf8ef 100644 --- a/aws/resource_aws_waf_sql_injection_match_set_test.go +++ b/aws/resource_aws_waf_sql_injection_match_set_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -28,65 +29,79 @@ func init() { func testSweepWafSqlInjectionMatchSet(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + var g multierror.Group + var mutex = &sync.Mutex{} input := &waf.ListSqlInjectionMatchSetsInput{} - err = lister.ListSqlInjectionMatchSetsPages(conn, input, func(page *waf.ListSqlInjectionMatchSetsOutput, lastPage bool) bool { + err = lister.ListSqlInjectionMatchSetsPages(conn, input, func(page *waf.ListSqlInjectionMatchSetsOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, sqlInjectionMatchSet := range page.SqlInjectionMatchSets { - id := aws.StringValue(sqlInjectionMatchSet.SqlInjectionMatchSetId) - r := resourceAwsWafSqlInjectionMatchSet() d := r.Data(nil) + + id := aws.StringValue(sqlInjectionMatchSet.SqlInjectionMatchSetId) d.SetId(id) - // Need to Read first to fill in sql_injection_match_tuples attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { + // Need to Read first to fill in sql_injection_match_tuples attribute + err := r.Read(d, client) - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF SQL Injection Match Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF SQL Injection Match Set (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } - // In case it was already deleted - if d.Id() == "" { - continue - } + // In case it was already deleted + if d.Id() == "" { + return nil + } - err = r.Delete(d, client) + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF SQL Injection Match Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + return nil + }) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF SQL Injection Match Set sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF SQL Injection Matches for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF SQL Injection Match Sets: %w", err)) + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF SQL Injection Matches: %w", err)) + } + + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF SQL Injection Matches for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF SQL Injection Match sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAWSWafSqlInjectionMatchSet_basic(t *testing.T) { From e4f592c493c6144bdefe7c1edf5a473680dab2c8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 15:29:18 -0400 Subject: [PATCH 0570/1208] tests/r/waf_web_acl: Add read/sweeper concurrency --- aws/resource_aws_waf_web_acl_test.go | 55 ++++++++++++++++++---------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/aws/resource_aws_waf_web_acl_test.go b/aws/resource_aws_waf_web_acl_test.go index 53bcd8b5a151..9f7754a83273 100644 --- a/aws/resource_aws_waf_web_acl_test.go +++ b/aws/resource_aws_waf_web_acl_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -33,11 +34,14 @@ func testSweepWafWebAcls(region string) error { conn := client.(*AWSClient).wafconn sweepResources := make([]*testSweepResource, 0) var errs *multierror.Error + var g multierror.Group + var mutex = &sync.Mutex{} + input := &waf.ListWebACLsInput{} - err = lister.ListWebACLsPages(conn, input, func(page *waf.ListWebACLsOutput, lastPage bool) bool { + err = lister.ListWebACLsPages(conn, input, func(page *waf.ListWebACLsOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, webACL := range page.WebACLs { @@ -51,33 +55,46 @@ func testSweepWafWebAcls(region string) error { id := aws.StringValue(webACL.WebACLId) d.SetId(id) - // Need to Read first to fill in rules argument - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { + // Need to Read first to fill in rules argument + err := r.Read(d, client) - if err != nil { - readErr := fmt.Errorf("error reading WAF Web ACL (%s): %w", id, err) - log.Printf("[ERROR] %s", readErr) - errs = multierror.Append(errs, readErr) - continue - } + if err != nil { + readErr := fmt.Errorf("error reading WAF Web ACL (%s): %w", id, err) + log.Printf("[ERROR] %s", readErr) + return readErr + } - // In case it was already deleted - if d.Id() == "" { - continue - } + // In case it was already deleted + if d.Id() == "" { + return nil + } - sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + + return nil + }) } - return !lastPage + return !isLast }) if err != nil { - errs = multierror.Append(errs, fmt.Errorf("error describing WAF Web ACLs: %w", err)) + errs = multierror.Append(errs, fmt.Errorf("error listing WAF Web ACLs for %s: %w", region, err)) } - if err = testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Web ACL for %s: %w", region, err)) + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Web ACLs: %w", err)) + } + + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Web ACLs for %s: %w", region, err)) + } } if testSweepSkipSweepError(errs.ErrorOrNil()) { From 1528e3f88dc1acd31d36e65175350f5f1a2ed1d6 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 15:32:19 -0400 Subject: [PATCH 0571/1208] tests/r/waf_xss_match_set: Add sweeper concurrency --- aws/resource_aws_waf_xss_match_set_test.go | 79 +++++++++++++--------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/aws/resource_aws_waf_xss_match_set_test.go b/aws/resource_aws_waf_xss_match_set_test.go index ec2a494f5456..2eeda67398bc 100644 --- a/aws/resource_aws_waf_xss_match_set_test.go +++ b/aws/resource_aws_waf_xss_match_set_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "regexp" + "sync" "testing" "github.com/aws/aws-sdk-go/aws" @@ -29,65 +30,79 @@ func init() { func testSweepWafXssMatchSet(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %s", err) } - conn := client.(*AWSClient).wafconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).wafconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + var g multierror.Group + var mutex = &sync.Mutex{} input := &waf.ListXssMatchSetsInput{} - err = lister.ListXssMatchSetsPages(conn, input, func(page *waf.ListXssMatchSetsOutput, lastPage bool) bool { + err = lister.ListXssMatchSetsPages(conn, input, func(page *waf.ListXssMatchSetsOutput, isLast bool) bool { if page == nil { - return !lastPage + return !isLast } for _, xssMatchSet := range page.XssMatchSets { - id := aws.StringValue(xssMatchSet.XssMatchSetId) - r := resourceAwsWafXssMatchSet() d := r.Data(nil) + + id := aws.StringValue(xssMatchSet.XssMatchSetId) d.SetId(id) - // Need to Read first to fill in xss_match_tuples attribute - err := r.Read(d, client) + // read concurrently and gather errors + g.Go(func() error { + // Need to Read first to fill in xss_match_tuples attribute + err := r.Read(d, client) - if err != nil { - sweeperErr := fmt.Errorf("error reading WAF XSS Match Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + if err != nil { + sweeperErr := fmt.Errorf("error reading WAF XSS Match Set (%s): %w", id, err) + log.Printf("[ERROR] %s", sweeperErr) + return sweeperErr + } - // In case it was already deleted - if d.Id() == "" { - continue - } + // In case it was already deleted + if d.Id() == "" { + return nil + } - err = r.Delete(d, client) + mutex.Lock() + defer mutex.Unlock() + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) - if err != nil { - sweeperErr := fmt.Errorf("error deleting WAF XSS Match Set (%s): %w", id, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + return nil + }) } - return !lastPage + return !isLast }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping WAF XSS Match Set sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing WAF XSS Match Sets for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing WAF XSS Match Sets: %w", err)) + if err = g.Wait().ErrorOrNil(); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF XSS Match Sets: %w", err)) + } + + if len(sweepResources) > 0 { + // Any errors didn't prevent gathering some sweeping work, so do it. + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF XSS Match Sets for %s: %w", region, err)) + } + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping WAF XSS Match Set sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAWSWafXssMatchSet_basic(t *testing.T) { From 482f2d13952a4d2133d8bdbf13a72f658b14e32b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 15:35:19 -0400 Subject: [PATCH 0572/1208] tests/r/waf: Consistent var list --- aws/resource_aws_waf_byte_match_set_test.go | 5 ++--- aws/resource_aws_waf_geo_match_set_test.go | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_waf_byte_match_set_test.go b/aws/resource_aws_waf_byte_match_set_test.go index 99f3295bd607..607c020ada59 100644 --- a/aws/resource_aws_waf_byte_match_set_test.go +++ b/aws/resource_aws_waf_byte_match_set_test.go @@ -38,12 +38,11 @@ func testSweepWafByteMatchSet(region string) error { conn := client.(*AWSClient).wafconn sweepResources := make([]*testSweepResource, 0) var errs *multierror.Error - - input := &waf.ListByteMatchSetsInput{} - var g multierror.Group var mutex = &sync.Mutex{} + input := &waf.ListByteMatchSetsInput{} + err = lister.ListByteMatchSetsPages(conn, input, func(page *waf.ListByteMatchSetsOutput, isLast bool) bool { if page == nil { return !isLast diff --git a/aws/resource_aws_waf_geo_match_set_test.go b/aws/resource_aws_waf_geo_match_set_test.go index 2c8b7ff3fb30..6a1a7d916802 100644 --- a/aws/resource_aws_waf_geo_match_set_test.go +++ b/aws/resource_aws_waf_geo_match_set_test.go @@ -38,12 +38,11 @@ func testSweepWafGeoMatchSet(region string) error { conn := client.(*AWSClient).wafconn sweepResources := make([]*testSweepResource, 0) var errs *multierror.Error - - input := &waf.ListGeoMatchSetsInput{} - var g multierror.Group var mutex = &sync.Mutex{} + input := &waf.ListGeoMatchSetsInput{} + err = lister.ListGeoMatchSetsPages(conn, input, func(page *waf.ListGeoMatchSetsOutput, isLast bool) bool { if page == nil { return !isLast From d216e99ebe41c2b187f818b6ecc15a4b509b0d8d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 7 Apr 2021 15:52:14 -0400 Subject: [PATCH 0573/1208] tests/r/waf: Use consistent var name --- aws/resource_aws_waf_byte_match_set_test.go | 6 +++--- aws/resource_aws_waf_geo_match_set_test.go | 6 +++--- aws/resource_aws_waf_ipset_test.go | 6 +++--- aws/resource_aws_waf_rate_based_rule_test.go | 6 +++--- aws/resource_aws_waf_regex_match_set_test.go | 6 +++--- aws/resource_aws_waf_regex_pattern_set_test.go | 6 +++--- aws/resource_aws_waf_rule_group_test.go | 6 +++--- aws/resource_aws_waf_rule_test.go | 6 +++--- aws/resource_aws_waf_size_constraint_set_test.go | 6 +++--- aws/resource_aws_waf_sql_injection_match_set_test.go | 6 +++--- aws/resource_aws_waf_web_acl_test.go | 6 +++--- aws/resource_aws_waf_xss_match_set_test.go | 6 +++--- 12 files changed, 36 insertions(+), 36 deletions(-) diff --git a/aws/resource_aws_waf_byte_match_set_test.go b/aws/resource_aws_waf_byte_match_set_test.go index 607c020ada59..463a3e812b00 100644 --- a/aws/resource_aws_waf_byte_match_set_test.go +++ b/aws/resource_aws_waf_byte_match_set_test.go @@ -43,9 +43,9 @@ func testSweepWafByteMatchSet(region string) error { input := &waf.ListByteMatchSetsInput{} - err = lister.ListByteMatchSetsPages(conn, input, func(page *waf.ListByteMatchSetsOutput, isLast bool) bool { + err = lister.ListByteMatchSetsPages(conn, input, func(page *waf.ListByteMatchSetsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, byteMatchSet := range page.ByteMatchSets { @@ -79,7 +79,7 @@ func testSweepWafByteMatchSet(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_geo_match_set_test.go b/aws/resource_aws_waf_geo_match_set_test.go index 6a1a7d916802..ce47ef4b5071 100644 --- a/aws/resource_aws_waf_geo_match_set_test.go +++ b/aws/resource_aws_waf_geo_match_set_test.go @@ -43,9 +43,9 @@ func testSweepWafGeoMatchSet(region string) error { input := &waf.ListGeoMatchSetsInput{} - err = lister.ListGeoMatchSetsPages(conn, input, func(page *waf.ListGeoMatchSetsOutput, isLast bool) bool { + err = lister.ListGeoMatchSetsPages(conn, input, func(page *waf.ListGeoMatchSetsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, geoMatchSet := range page.GeoMatchSets { @@ -79,7 +79,7 @@ func testSweepWafGeoMatchSet(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_ipset_test.go b/aws/resource_aws_waf_ipset_test.go index eba5cbd863af..c8dd7d923204 100644 --- a/aws/resource_aws_waf_ipset_test.go +++ b/aws/resource_aws_waf_ipset_test.go @@ -46,9 +46,9 @@ func testSweepWafIPSet(region string) error { input := &waf.ListIPSetsInput{} - err = lister.ListIPSetsPages(conn, input, func(page *waf.ListIPSetsOutput, isLast bool) bool { + err = lister.ListIPSetsPages(conn, input, func(page *waf.ListIPSetsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, ipSet := range page.IPSets { @@ -82,7 +82,7 @@ func testSweepWafIPSet(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_rate_based_rule_test.go b/aws/resource_aws_waf_rate_based_rule_test.go index 34f1bafc4721..a298aa347450 100644 --- a/aws/resource_aws_waf_rate_based_rule_test.go +++ b/aws/resource_aws_waf_rate_based_rule_test.go @@ -43,9 +43,9 @@ func testSweepWafRateBasedRules(region string) error { input := &waf.ListRateBasedRulesInput{} - err = lister.ListRateBasedRulesPages(conn, input, func(page *waf.ListRateBasedRulesOutput, isLast bool) bool { + err = lister.ListRateBasedRulesPages(conn, input, func(page *waf.ListRateBasedRulesOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, rule := range page.Rules { @@ -79,7 +79,7 @@ func testSweepWafRateBasedRules(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_regex_match_set_test.go b/aws/resource_aws_waf_regex_match_set_test.go index 54769e0146dc..6dc4dfff1eb8 100644 --- a/aws/resource_aws_waf_regex_match_set_test.go +++ b/aws/resource_aws_waf_regex_match_set_test.go @@ -43,9 +43,9 @@ func testSweepWafRegexMatchSet(region string) error { input := &waf.ListRegexMatchSetsInput{} - err = lister.ListRegexMatchSetsPages(conn, input, func(page *waf.ListRegexMatchSetsOutput, isLast bool) bool { + err = lister.ListRegexMatchSetsPages(conn, input, func(page *waf.ListRegexMatchSetsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, regexMatchSet := range page.RegexMatchSets { @@ -79,7 +79,7 @@ func testSweepWafRegexMatchSet(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_regex_pattern_set_test.go b/aws/resource_aws_waf_regex_pattern_set_test.go index 1e7f177fba09..a9a536f8819d 100644 --- a/aws/resource_aws_waf_regex_pattern_set_test.go +++ b/aws/resource_aws_waf_regex_pattern_set_test.go @@ -43,9 +43,9 @@ func testSweepWafRegexPatternSet(region string) error { input := &waf.ListRegexPatternSetsInput{} - err = lister.ListRegexPatternSetsPages(conn, input, func(page *waf.ListRegexPatternSetsOutput, isLast bool) bool { + err = lister.ListRegexPatternSetsPages(conn, input, func(page *waf.ListRegexPatternSetsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, regexPatternSet := range page.RegexPatternSets { @@ -79,7 +79,7 @@ func testSweepWafRegexPatternSet(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_rule_group_test.go b/aws/resource_aws_waf_rule_group_test.go index 172037f9dbbd..249d45006eed 100644 --- a/aws/resource_aws_waf_rule_group_test.go +++ b/aws/resource_aws_waf_rule_group_test.go @@ -42,9 +42,9 @@ func testSweepWafRuleGroups(region string) error { input := &waf.ListRuleGroupsInput{} - err = lister.ListRuleGroupsPages(conn, input, func(page *waf.ListRuleGroupsOutput, isLast bool) bool { + err = lister.ListRuleGroupsPages(conn, input, func(page *waf.ListRuleGroupsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, ruleGroup := range page.RuleGroups { @@ -78,7 +78,7 @@ func testSweepWafRuleGroups(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_rule_test.go b/aws/resource_aws_waf_rule_test.go index be84290e4b24..624f38f67c47 100644 --- a/aws/resource_aws_waf_rule_test.go +++ b/aws/resource_aws_waf_rule_test.go @@ -43,9 +43,9 @@ func testSweepWafRules(region string) error { input := &waf.ListRulesInput{} - err = lister.ListRulesPages(conn, input, func(page *waf.ListRulesOutput, isLast bool) bool { + err = lister.ListRulesPages(conn, input, func(page *waf.ListRulesOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, rule := range page.Rules { @@ -83,7 +83,7 @@ func testSweepWafRules(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_size_constraint_set_test.go b/aws/resource_aws_waf_size_constraint_set_test.go index 8a5f034e988d..2e8fbcbcf05a 100644 --- a/aws/resource_aws_waf_size_constraint_set_test.go +++ b/aws/resource_aws_waf_size_constraint_set_test.go @@ -44,9 +44,9 @@ func testSweepWafSizeConstraintSet(region string) error { input := &waf.ListSizeConstraintSetsInput{} - err = lister.ListSizeConstraintSetsPages(conn, input, func(page *waf.ListSizeConstraintSetsOutput, isLast bool) bool { + err = lister.ListSizeConstraintSetsPages(conn, input, func(page *waf.ListSizeConstraintSetsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, sizeConstraintSet := range page.SizeConstraintSets { @@ -80,7 +80,7 @@ func testSweepWafSizeConstraintSet(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_sql_injection_match_set_test.go b/aws/resource_aws_waf_sql_injection_match_set_test.go index 6da0facdf8ef..0ef056b81393 100644 --- a/aws/resource_aws_waf_sql_injection_match_set_test.go +++ b/aws/resource_aws_waf_sql_injection_match_set_test.go @@ -42,9 +42,9 @@ func testSweepWafSqlInjectionMatchSet(region string) error { input := &waf.ListSqlInjectionMatchSetsInput{} - err = lister.ListSqlInjectionMatchSetsPages(conn, input, func(page *waf.ListSqlInjectionMatchSetsOutput, isLast bool) bool { + err = lister.ListSqlInjectionMatchSetsPages(conn, input, func(page *waf.ListSqlInjectionMatchSetsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, sqlInjectionMatchSet := range page.SqlInjectionMatchSets { @@ -78,7 +78,7 @@ func testSweepWafSqlInjectionMatchSet(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_web_acl_test.go b/aws/resource_aws_waf_web_acl_test.go index 9f7754a83273..17cf50095b37 100644 --- a/aws/resource_aws_waf_web_acl_test.go +++ b/aws/resource_aws_waf_web_acl_test.go @@ -39,9 +39,9 @@ func testSweepWafWebAcls(region string) error { input := &waf.ListWebACLsInput{} - err = lister.ListWebACLsPages(conn, input, func(page *waf.ListWebACLsOutput, isLast bool) bool { + err = lister.ListWebACLsPages(conn, input, func(page *waf.ListWebACLsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, webACL := range page.WebACLs { @@ -79,7 +79,7 @@ func testSweepWafWebAcls(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { diff --git a/aws/resource_aws_waf_xss_match_set_test.go b/aws/resource_aws_waf_xss_match_set_test.go index 2eeda67398bc..81697a3606d8 100644 --- a/aws/resource_aws_waf_xss_match_set_test.go +++ b/aws/resource_aws_waf_xss_match_set_test.go @@ -43,9 +43,9 @@ func testSweepWafXssMatchSet(region string) error { input := &waf.ListXssMatchSetsInput{} - err = lister.ListXssMatchSetsPages(conn, input, func(page *waf.ListXssMatchSetsOutput, isLast bool) bool { + err = lister.ListXssMatchSetsPages(conn, input, func(page *waf.ListXssMatchSetsOutput, lastPage bool) bool { if page == nil { - return !isLast + return !lastPage } for _, xssMatchSet := range page.XssMatchSets { @@ -79,7 +79,7 @@ func testSweepWafXssMatchSet(region string) error { }) } - return !isLast + return !lastPage }) if err != nil { From ab9605e96534c55abfe1616a2b53deb5b289a9d4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Apr 2021 12:40:38 -0400 Subject: [PATCH 0574/1208] tests/r/waf: Remove unneeded len check --- aws/resource_aws_waf_byte_match_set_test.go | 7 ++----- aws/resource_aws_waf_geo_match_set_test.go | 7 ++----- aws/resource_aws_waf_ipset_test.go | 7 ++----- aws/resource_aws_waf_rate_based_rule_test.go | 7 ++----- aws/resource_aws_waf_regex_match_set_test.go | 7 ++----- aws/resource_aws_waf_regex_pattern_set_test.go | 7 ++----- aws/resource_aws_waf_rule_group_test.go | 7 ++----- aws/resource_aws_waf_rule_test.go | 7 ++----- aws/resource_aws_waf_size_constraint_set_test.go | 7 ++----- aws/resource_aws_waf_sql_injection_match_set_test.go | 7 ++----- aws/resource_aws_waf_web_acl_test.go | 7 ++----- aws/resource_aws_waf_xss_match_set_test.go | 7 ++----- 12 files changed, 24 insertions(+), 60 deletions(-) diff --git a/aws/resource_aws_waf_byte_match_set_test.go b/aws/resource_aws_waf_byte_match_set_test.go index 463a3e812b00..5c528bd72874 100644 --- a/aws/resource_aws_waf_byte_match_set_test.go +++ b/aws/resource_aws_waf_byte_match_set_test.go @@ -90,11 +90,8 @@ func testSweepWafByteMatchSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Byte Match Sets: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Byte Match Set for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Byte Match Set for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_geo_match_set_test.go b/aws/resource_aws_waf_geo_match_set_test.go index ce47ef4b5071..8ba529a51ba2 100644 --- a/aws/resource_aws_waf_geo_match_set_test.go +++ b/aws/resource_aws_waf_geo_match_set_test.go @@ -90,11 +90,8 @@ func testSweepWafGeoMatchSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Geo Match Sets: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Geo Match Set for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Geo Match Set for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_ipset_test.go b/aws/resource_aws_waf_ipset_test.go index c8dd7d923204..683f11a0c9c2 100644 --- a/aws/resource_aws_waf_ipset_test.go +++ b/aws/resource_aws_waf_ipset_test.go @@ -93,11 +93,8 @@ func testSweepWafIPSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF IP Sets: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF IP Set for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF IP Set for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_rate_based_rule_test.go b/aws/resource_aws_waf_rate_based_rule_test.go index a298aa347450..6f2aebe39b1b 100644 --- a/aws/resource_aws_waf_rate_based_rule_test.go +++ b/aws/resource_aws_waf_rate_based_rule_test.go @@ -90,11 +90,8 @@ func testSweepWafRateBasedRules(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Rate Based Rules: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Rate Based Rule for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Rate Based Rule for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_regex_match_set_test.go b/aws/resource_aws_waf_regex_match_set_test.go index 6dc4dfff1eb8..e5598bf613b3 100644 --- a/aws/resource_aws_waf_regex_match_set_test.go +++ b/aws/resource_aws_waf_regex_match_set_test.go @@ -90,11 +90,8 @@ func testSweepWafRegexMatchSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Regex Match Sets: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Regex Match Set for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Regex Match Set for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_regex_pattern_set_test.go b/aws/resource_aws_waf_regex_pattern_set_test.go index a9a536f8819d..0ca98ca2982f 100644 --- a/aws/resource_aws_waf_regex_pattern_set_test.go +++ b/aws/resource_aws_waf_regex_pattern_set_test.go @@ -90,11 +90,8 @@ func testSweepWafRegexPatternSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Regex Pattern Sets: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Regex Pattern Set for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Regex Pattern Set for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_rule_group_test.go b/aws/resource_aws_waf_rule_group_test.go index 249d45006eed..a61cdf80a725 100644 --- a/aws/resource_aws_waf_rule_group_test.go +++ b/aws/resource_aws_waf_rule_group_test.go @@ -89,11 +89,8 @@ func testSweepWafRuleGroups(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Rule Groups: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Rule Group for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Rule Group for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_rule_test.go b/aws/resource_aws_waf_rule_test.go index 624f38f67c47..95154b35165b 100644 --- a/aws/resource_aws_waf_rule_test.go +++ b/aws/resource_aws_waf_rule_test.go @@ -94,11 +94,8 @@ func testSweepWafRules(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Rules: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Rules for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Rules for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_size_constraint_set_test.go b/aws/resource_aws_waf_size_constraint_set_test.go index 2e8fbcbcf05a..d0a6c6b36010 100644 --- a/aws/resource_aws_waf_size_constraint_set_test.go +++ b/aws/resource_aws_waf_size_constraint_set_test.go @@ -91,11 +91,8 @@ func testSweepWafSizeConstraintSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Size Constraint Sets: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Size Constraint Sets for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Size Constraint Sets for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_sql_injection_match_set_test.go b/aws/resource_aws_waf_sql_injection_match_set_test.go index 0ef056b81393..8c475541c0a9 100644 --- a/aws/resource_aws_waf_sql_injection_match_set_test.go +++ b/aws/resource_aws_waf_sql_injection_match_set_test.go @@ -89,11 +89,8 @@ func testSweepWafSqlInjectionMatchSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF SQL Injection Matches: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF SQL Injection Matches for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF SQL Injection Matches for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_web_acl_test.go b/aws/resource_aws_waf_web_acl_test.go index 17cf50095b37..2a151fdd23d7 100644 --- a/aws/resource_aws_waf_web_acl_test.go +++ b/aws/resource_aws_waf_web_acl_test.go @@ -90,11 +90,8 @@ func testSweepWafWebAcls(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF Web ACLs: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Web ACLs for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF Web ACLs for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { diff --git a/aws/resource_aws_waf_xss_match_set_test.go b/aws/resource_aws_waf_xss_match_set_test.go index 81697a3606d8..e70e8fc0e7d7 100644 --- a/aws/resource_aws_waf_xss_match_set_test.go +++ b/aws/resource_aws_waf_xss_match_set_test.go @@ -90,11 +90,8 @@ func testSweepWafXssMatchSet(region string) error { errs = multierror.Append(errs, fmt.Errorf("error concurrently reading WAF XSS Match Sets: %w", err)) } - if len(sweepResources) > 0 { - // Any errors didn't prevent gathering some sweeping work, so do it. - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF XSS Match Sets for %s: %w", region, err)) - } + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping WAF XSS Match Sets for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { From eadbe9b544a601f735a85f59bdba5a9337bd643b Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Thu, 17 Jun 2021 16:20:46 -0400 Subject: [PATCH 0575/1208] update tests to use exisiting image --- aws/resource_aws_apprunner_service_test.go | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/aws/resource_aws_apprunner_service_test.go b/aws/resource_aws_apprunner_service_test.go index 7f3d0ce996e5..f774c7c8254e 100644 --- a/aws/resource_aws_apprunner_service_test.go +++ b/aws/resource_aws_apprunner_service_test.go @@ -112,8 +112,8 @@ func TestAccAwsAppRunnerService_ImageRepository_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "source_configuration.0.auto_deployments_enabled", "false"), resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.#", "1"), resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_configuration.0.port", "8000"), - resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_identifier", "public.ecr.aws/jg/hello:latest"), + resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_configuration.0.port", "80"), + resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_identifier", "public.ecr.aws/nginx/nginx:latest"), resource.TestCheckResourceAttr(resourceName, "source_configuration.0.image_repository.0.image_repository_type", apprunner.ImageRepositoryTypeEcrPublic), resource.TestCheckResourceAttr(resourceName, "status", apprunner.ServiceStatusRunning), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), @@ -483,9 +483,9 @@ resource "aws_apprunner_service" "test" { auto_deployments_enabled = false image_repository { image_configuration { - port = "8000" + port = "80" } - image_identifier = "public.ecr.aws/jg/hello:latest" + image_identifier = "public.ecr.aws/nginx/nginx:latest" image_repository_type = "ECR_PUBLIC" } } @@ -501,12 +501,12 @@ resource "aws_apprunner_service" "test" { auto_deployments_enabled = false image_repository { image_configuration { - port = "8000" + port = "80" runtime_environment_variables = { APP_NAME = %[1]q } } - image_identifier = "public.ecr.aws/jg/hello:latest" + image_identifier = "public.ecr.aws/nginx/nginx:latest" image_repository_type = "ECR_PUBLIC" } } @@ -529,9 +529,9 @@ resource "aws_apprunner_service" "test" { auto_deployments_enabled = false image_repository { image_configuration { - port = "8000" + port = "80" } - image_identifier = "public.ecr.aws/jg/hello:latest" + image_identifier = "public.ecr.aws/nginx/nginx:latest" image_repository_type = "ECR_PUBLIC" } } @@ -557,9 +557,9 @@ resource "aws_apprunner_service" "test" { auto_deployments_enabled = false image_repository { image_configuration { - port = "8000" + port = "80" } - image_identifier = "public.ecr.aws/jg/hello:latest" + image_identifier = "public.ecr.aws/nginx/nginx:latest" image_repository_type = "ECR_PUBLIC" } } @@ -581,9 +581,9 @@ resource "aws_apprunner_service" "test" { auto_deployments_enabled = false image_repository { image_configuration { - port = "8000" + port = "80" } - image_identifier = "public.ecr.aws/jg/hello:latest" + image_identifier = "public.ecr.aws/nginx/nginx:latest" image_repository_type = "ECR_PUBLIC" } } @@ -606,9 +606,9 @@ resource "aws_apprunner_service" "test" { auto_deployments_enabled = false image_repository { image_configuration { - port = "8000" + port = "80" } - image_identifier = "public.ecr.aws/jg/hello:latest" + image_identifier = "public.ecr.aws/nginx/nginx:latest" image_repository_type = "ECR_PUBLIC" } } @@ -659,9 +659,9 @@ resource "aws_apprunner_service" "test" { auto_deployments_enabled = false image_repository { image_configuration { - port = "8000" + port = "80" } - image_identifier = "public.ecr.aws/jg/hello:latest" + image_identifier = "public.ecr.aws/nginx/nginx:latest" image_repository_type = "ECR_PUBLIC" } } @@ -686,9 +686,9 @@ resource "aws_apprunner_service" "test" { auto_deployments_enabled = false image_repository { image_configuration { - port = "8000" + port = "80" } - image_identifier = "public.ecr.aws/jg/hello:latest" + image_identifier = "public.ecr.aws/nginx/nginx:latest" image_repository_type = "ECR_PUBLIC" } } @@ -704,9 +704,9 @@ resource "aws_apprunner_service" "test" { auto_deployments_enabled = false image_repository { image_configuration { - port = "8000" + port = "80" } - image_identifier = "public.ecr.aws/jg/hello:latest" + image_identifier = "public.ecr.aws/nginx/nginx:latest" image_repository_type = "ECR_PUBLIC" } } @@ -726,9 +726,9 @@ resource "aws_apprunner_service" "test" { auto_deployments_enabled = false image_repository { image_configuration { - port = "8000" + port = "80" } - image_identifier = "public.ecr.aws/jg/hello:latest" + image_identifier = "public.ecr.aws/nginx/nginx:latest" image_repository_type = "ECR_PUBLIC" } } From a149856369bfe0accb022949edfc8859a0eee1f5 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 19:03:00 -0400 Subject: [PATCH 0576/1208] tests/sweeper: Make sweeper smarter with throttling errors --- aws/aws_sweeper_test.go | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/aws/aws_sweeper_test.go b/aws/aws_sweeper_test.go index a16da090e850..623a66e39dc9 100644 --- a/aws/aws_sweeper_test.go +++ b/aws/aws_sweeper_test.go @@ -4,12 +4,18 @@ import ( "fmt" "os" "testing" + "time" "github.com/hashicorp/aws-sdk-go-base/tfawserr" multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/envvar" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +const ( + SweepThrottlingRetryTimeout = 5 * time.Minute ) // sweeperAwsClients is a shared cache of regional AWSClient @@ -77,7 +83,26 @@ func testSweepResourceOrchestrator(sweepResources []*testSweepResource) error { sweepResource := sweepResource g.Go(func() error { - return testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) + err := resource.Retry(SweepThrottlingRetryTimeout, func() *resource.RetryError { + var err error + + err = testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) + + if err != nil { + if tfawserr.ErrCodeContains(err, "ThrottlingException: Rate exceeded") { + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + } + return nil + }) + + if tfresource.TimedOut(err) { + err = testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) + } + + return err }) } From fa883ebe4e93fb116ca0f57be0ce593dbd2cb288 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Thu, 17 Jun 2021 16:07:39 -0700 Subject: [PATCH 0577/1208] Add CHANGELOG entry --- .changelog/19820.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19820.txt diff --git a/.changelog/19820.txt b/.changelog/19820.txt new file mode 100644 index 000000000000..2f08ee6f8a29 --- /dev/null +++ b/.changelog/19820.txt @@ -0,0 +1,3 @@ +```release-note:bug +data-source/aws_directory_service_directory: Check VpcSettings and ConnectSettings for nil values +``` From 6e65c26b5919ba2b0a6c3d140ddde030d0da35da Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Jun 2021 16:09:41 -0700 Subject: [PATCH 0578/1208] Centralizes IAM Role filtering and applies it to IAM Instance Profiles as well --- aws/resource_aws_iam_instance_profile_test.go | 48 +++++++++---- aws/resource_aws_iam_role_test.go | 71 +++++++++++-------- 2 files changed, 74 insertions(+), 45 deletions(-) diff --git a/aws/resource_aws_iam_instance_profile_test.go b/aws/resource_aws_iam_instance_profile_test.go index a869a75630a1..59406c138b20 100644 --- a/aws/resource_aws_iam_instance_profile_test.go +++ b/aws/resource_aws_iam_instance_profile_test.go @@ -31,31 +31,49 @@ func testSweepIamInstanceProfile(region string) error { var sweeperErrs *multierror.Error - out, err := conn.ListInstanceProfiles(&iam.ListInstanceProfilesInput{}) + err = conn.ListInstanceProfilesPages(&iam.ListInstanceProfilesInput{}, func(page *iam.ListInstanceProfilesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } - for _, instanceProfile := range out.InstanceProfiles { - name := aws.StringValue(instanceProfile.InstanceProfileName) + for _, instanceProfile := range page.InstanceProfiles { + name := aws.StringValue(instanceProfile.InstanceProfileName) - r := resourceAwsIamInstanceProfile() - d := r.Data(nil) - d.SetId(name) - err := r.Delete(d, client) + if !iamRoleNameFilter(name) { + log.Printf("[INFO] Skipping IAM Instance Profile (%s): no match on allow-list", name) + continue + } - if err != nil { - sweeperErr := fmt.Errorf("error deleting IAM Instance Profile (%s): %w", name, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue + r := resourceAwsIamInstanceProfile() + d := r.Data(nil) + d.SetId(name) + + roles := instanceProfile.Roles + if r := len(roles); r > 1 { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("unexpected number of roles for IAM Instance Profile (%s): %d", name, r)) + } else if r == 1 { + d.Set("role", roles[0].RoleName) + } + + log.Printf("[INFO] Sweeping IAM Instance Profile %q", name) + err := r.Delete(d, client) + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error deleting IAM Instance Profile (%s): %w", name, err)) + continue + } } - } + + return !lastPage + }) if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping IAM Instance Profile sweep for %s: %s", region, err) + log.Printf("[WARN] Skipping IAM Instance Profile sweep for %q: %s", region, err) return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors } if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error describing IAM Instance Profiles: %w", err)) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing IAM Instance Profiles: %w", err)) } return sweeperErrs.ErrorOrNil() diff --git a/aws/resource_aws_iam_role_test.go b/aws/resource_aws_iam_role_test.go index 719063df138d..26fd7291753a 100644 --- a/aws/resource_aws_iam_role_test.go +++ b/aws/resource_aws_iam_role_test.go @@ -46,57 +46,69 @@ func init() { }) } -func testSweepIamRoles(region string) error { - client, err := sharedClientForRegion(region) - if err != nil { - return fmt.Errorf("error getting client: %s", err) +func iamRoleNameFilter(name string) bool { + // The standard naming pattern for resources is generated by acctest.RandomWithPrefix("tf-acc-test"). + // Some roles automatically generated by AWS will add a prefix to the associated resource name, so look for + // this pattern anywhere in the name, not just as a prefix. + // Some names use "tf_acc_test" instead, so catch those, too. + standardNameRegexp := regexp.MustCompile(`tf[-_]acc[-_]test`) + if standardNameRegexp.MatchString(name) { + return true } - conn := client.(*AWSClient).iamconn + + // Some acceptance tests use acctest.RandString(10) rather than acctest.RandomWithPrefix() + // Others use other lengths, e.g. acctest.RandString(8), but this one is risky enough, so leave it as-is + randString10 := regexp.MustCompile(`^[a-zA-Z0-9]{10}$`) + if randString10.MatchString(name) { + return true + } + + // We have a lot of role name prefixes for role names that don't match the standard pattern. This is not an + // exhaustive list. prefixes := []string{ "another_rds", - "batch_tf_acc_test", "codepipeline-", "cognito_authenticated_", "cognito_unauthenticated_", "CWLtoKinesisRole_", - "ecs_instance_role", - "ecs_tf", "EMR_AutoScaling_DefaultRole_", - "enhanced-monitoring-role-", "es-domain-role-", "event_", - "firehose", - "foo_role", - "foo-role", "foobar", "iam_emr", - "iam_for_lambda", "iam_for_sfn", "rds", "role", "sns-delivery-status", "ssm_role", "ssm-role", - "terraform-", "test", "tf", } - // Some acceptance tests use acctest.RandString(10) rather than acctest.RandomWithPrefix() - regex := regexp.MustCompile(`^[a-zA-Z0-9]{10}$`) - roles := make([]*iam.Role, 0) + for _, prefix := range prefixes { + if strings.HasPrefix(name, prefix) { + return true + } + } + return false +} + +func testSweepIamRoles(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %w", err) + } + conn := client.(*AWSClient).iamconn + + roles := make([]string, 0) err = conn.ListRolesPages(&iam.ListRolesInput{}, func(page *iam.ListRolesOutput, lastPage bool) bool { for _, role := range page.Roles { - if regex.MatchString(aws.StringValue(role.RoleName)) { - roles = append(roles, role) - continue - } - - for _, prefix := range prefixes { - if strings.HasPrefix(aws.StringValue(role.RoleName), prefix) { - roles = append(roles, role) - break - } + roleName := aws.StringValue(role.RoleName) + if iamRoleNameFilter(roleName) { + roles = append(roles, roleName) + } else { + log.Printf("[INFO] Skipping IAM Role (%s): no match on allow-list", roleName) } } @@ -109,7 +121,7 @@ func testSweepIamRoles(region string) error { } if err != nil { - return fmt.Errorf("Error retrieving IAM Roles: %s", err) + return fmt.Errorf("Error retrieving IAM Roles: %w", err) } if len(roles) == 0 { @@ -119,8 +131,7 @@ func testSweepIamRoles(region string) error { var sweeperErrs *multierror.Error - for _, role := range roles { - roleName := aws.StringValue(role.RoleName) + for _, roleName := range roles { log.Printf("[DEBUG] Deleting IAM Role (%s)", roleName) err := deleteIamRole(conn, roleName, true, true, true) From 1502cec5cd52590cb8b1666c0a9b87697e111a17 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 17 Jun 2021 23:10:11 +0000 Subject: [PATCH 0579/1208] Update CHANGELOG.md for #19820 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ca9317be6ec..456383285900 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ ENHANCEMENTS: BUG FIXES: +* data-source/aws_directory_service_directory: Check VpcSettings and ConnectSettings for nil values ([#19820](https://github.com/hashicorp/terraform-provider-aws/issues/19820)) * data-source/aws_lakeformation_permissions: Fix diffs resulting from order of column names and exclude column names ([#19817](https://github.com/hashicorp/terraform-provider-aws/issues/19817)) * resource/aws_cognito_identity_provider: Fix updating `idp_identifiers` crash. ([#19819](https://github.com/hashicorp/terraform-provider-aws/issues/19819)) * resource/aws_glue_trigger: Fix default timeouts for Create and Delete operations ([#19827](https://github.com/hashicorp/terraform-provider-aws/issues/19827)) From fc452c77d793c61aa6cacbb880510cd4585683c5 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 19:16:51 -0400 Subject: [PATCH 0580/1208] tests/sweeper: Appease linting gods --- aws/aws_sweeper_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aws/aws_sweeper_test.go b/aws/aws_sweeper_test.go index 623a66e39dc9..5ce03b6a4ad3 100644 --- a/aws/aws_sweeper_test.go +++ b/aws/aws_sweeper_test.go @@ -84,9 +84,7 @@ func testSweepResourceOrchestrator(sweepResources []*testSweepResource) error { g.Go(func() error { err := resource.Retry(SweepThrottlingRetryTimeout, func() *resource.RetryError { - var err error - - err = testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) + err := testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) if err != nil { if tfawserr.ErrCodeContains(err, "ThrottlingException: Rate exceeded") { @@ -95,6 +93,7 @@ func testSweepResourceOrchestrator(sweepResources []*testSweepResource) error { return resource.NonRetryableError(err) } + return nil }) From 7137144749f3adeff197a23d5f01c8a94cdf15d3 Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Thu, 17 Jun 2021 23:25:59 +0000 Subject: [PATCH 0581/1208] v3.46.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 456383285900..bf99cac792e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 3.46.0 (Unreleased) +## 3.46.0 (June 17, 2021) FEATURES: From 72b340fc6d714895bf10cccedaaee87a7a397269 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 17 Jun 2021 23:33:06 +0000 Subject: [PATCH 0582/1208] Update CHANGELOG.md after v3.46.0 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf99cac792e0..616208a02cc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## 3.47.0 (Unreleased) ## 3.46.0 (June 17, 2021) FEATURES: From a4fd9ccc93d81a651e122b90725fa5ad56496e6c Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Thu, 17 Jun 2021 20:32:29 -0400 Subject: [PATCH 0583/1208] loop through versions --- aws/resource_aws_imagebuilder_image_test.go | 43 ++++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_imagebuilder_image_test.go b/aws/resource_aws_imagebuilder_image_test.go index e9cf3058945b..ce3bd9009bcf 100644 --- a/aws/resource_aws_imagebuilder_image_test.go +++ b/aws/resource_aws_imagebuilder_image_test.go @@ -45,20 +45,51 @@ func testSweepImageBuilderImages(region string) error { continue } - arn := aws.StringValue(imageVersion.Arn) + imageVersionArn := aws.StringValue(imageVersion.Arn) - r := resourceAwsImageBuilderImage() - d := r.Data(nil) - d.SetId(arn) + input := &imagebuilder.ListImageBuildVersionsInput{ + ImageVersionArn: imageVersion.Arn, + } + + var imageBuildVersionArns []string + + err := conn.ListImageBuildVersionsPages(input, func(page *imagebuilder.ListImageBuildVersionsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, imageSummary := range page.ImageSummaryList { + if imageSummary == nil { + continue + } + + imageBuildVersionArns = append(imageBuildVersionArns, aws.StringValue(imageSummary.Arn)) + } - err := r.Delete(d, client) + return !lastPage + }) if err != nil { - sweeperErr := fmt.Errorf("error deleting Image Builder Image (%s): %w", arn, err) + sweeperErr := fmt.Errorf("error listing Image Builder Image Build Versions for image (%s): %w", imageVersionArn, err) log.Printf("[ERROR] %s", sweeperErr) sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) continue } + + for _, imageBuildVersionArn := range imageBuildVersionArns { + r := resourceAwsImageBuilderImage() + d := r.Data(nil) + d.SetId(imageBuildVersionArn) + + err := r.Delete(d, client) + + if err != nil { + sweeperErr := fmt.Errorf("error deleting Image Builder Image (%s): %w", imageBuildVersionArn, err) + log.Printf("[ERROR] %s", sweeperErr) + sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + continue + } + } } return !lastPage From 5319e81116aa154303e6a6a9a4a8dc2227c83f4c Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Thu, 17 Jun 2021 20:58:57 -0400 Subject: [PATCH 0584/1208] find image build version arns and add concurrency --- aws/resource_aws_imagebuilder_image_test.go | 55 ++++++++++----------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/aws/resource_aws_imagebuilder_image_test.go b/aws/resource_aws_imagebuilder_image_test.go index ce3bd9009bcf..016d3198ac7a 100644 --- a/aws/resource_aws_imagebuilder_image_test.go +++ b/aws/resource_aws_imagebuilder_image_test.go @@ -24,12 +24,14 @@ func init() { func testSweepImageBuilderImages(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("error getting client: %w", err) } - conn := client.(*AWSClient).imagebuilderconn - var sweeperErrs *multierror.Error + conn := client.(*AWSClient).imagebuilderconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error input := &imagebuilder.ListImagesInput{ Owner: aws.String(imagebuilder.OwnershipSelf), @@ -45,14 +47,15 @@ func testSweepImageBuilderImages(region string) error { continue } + // Retrieve the Image's Build Version ARNs required as input + // to the resourceAwsImageBuilderImage()'s Delete operation + // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/19851 imageVersionArn := aws.StringValue(imageVersion.Arn) input := &imagebuilder.ListImageBuildVersionsInput{ ImageVersionArn: imageVersion.Arn, } - var imageBuildVersionArns []string - err := conn.ListImageBuildVersionsPages(input, func(page *imagebuilder.ListImageBuildVersionsOutput, lastPage bool) bool { if page == nil { return !lastPage @@ -63,48 +66,40 @@ func testSweepImageBuilderImages(region string) error { continue } - imageBuildVersionArns = append(imageBuildVersionArns, aws.StringValue(imageSummary.Arn)) + imageBuildVersionArn := aws.StringValue(imageSummary.Arn) + + r := resourceAwsImageBuilderImage() + d := r.Data(nil) + d.SetId(imageBuildVersionArn) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } return !lastPage }) if err != nil { - sweeperErr := fmt.Errorf("error listing Image Builder Image Build Versions for image (%s): %w", imageVersionArn, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } - - for _, imageBuildVersionArn := range imageBuildVersionArns { - r := resourceAwsImageBuilderImage() - d := r.Data(nil) - d.SetId(imageBuildVersionArn) - - err := r.Delete(d, client) - - if err != nil { - sweeperErr := fmt.Errorf("error deleting Image Builder Image (%s): %w", imageBuildVersionArn, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + errs = multierror.Append(errs, fmt.Errorf("error listing Image Builder Image Build Versions for image (%s): %w", imageVersionArn, err)) } } return !lastPage }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping Image Builder Image sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing Image Builder Images for %s: %w", region, err)) } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Image Builder Images: %w", err)) + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Image Builder Images for %s: %w", region, err)) + } + + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Image Builder Image sweep for %s: %s", region, err) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAwsImageBuilderImage_basic(t *testing.T) { From 0bd22e2c693aebdccd385eba07602c95647fbfc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Jun 2021 06:10:58 +0000 Subject: [PATCH 0585/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.61 to 1.38.64 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.61 to 1.38.64. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.61...v1.38.64) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 96b8ff0dcd5e..39dc0ea060fd 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.61 + github.com/aws/aws-sdk-go v1.38.64 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index fa0527d79983..f127cb957cc8 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.61 h1:wizuqQZe0K4iYJ+Slrs0aSQ4P94FAwqBUHwk46Iz5UA= -github.com/aws/aws-sdk-go v1.38.61/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.64 h1:aE178SZNBpAT9T2U5hacKJiyiRE/Li2Hax6xddVuyGA= +github.com/aws/aws-sdk-go v1.38.64/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From b93fca7ba8930a826cc358599e374796a0af888e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Jun 2021 06:11:25 +0000 Subject: [PATCH 0586/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.61 to 1.38.64. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.61...v1.38.64) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../github.com/aws/aws-sdk-go/aws/ec2metadata/service.go | 4 ++-- .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index af2198430626..8abf77b85da4 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.61 + github.com/aws/aws-sdk-go v1.38.64 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 8946ff99ab3f..d14dc6138d03 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.61 h1:wizuqQZe0K4iYJ+Slrs0aSQ4P94FAwqBUHwk46Iz5UA= -github.com/aws/aws-sdk-go v1.38.61/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.64 h1:aE178SZNBpAT9T2U5hacKJiyiRE/Li2Hax6xddVuyGA= +github.com/aws/aws-sdk-go v1.38.64/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go index 8f35b3464ba1..df63bade1048 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go @@ -13,7 +13,6 @@ package ec2metadata import ( "bytes" - "errors" "io" "net/http" "net/url" @@ -234,7 +233,8 @@ func unmarshalError(r *request.Request) { // Response body format is not consistent between metadata endpoints. // Grab the error message as a string and include that as the source error - r.Error = awserr.NewRequestFailure(awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New(b.String())), + r.Error = awserr.NewRequestFailure( + awserr.New("EC2MetadataError", "failed to make EC2Metadata request\n"+b.String(), nil), r.HTTPResponse.StatusCode, r.RequestID) } diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index ef8b3498c241..a4136ac05fcb 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.61" +const SDKVersion = "1.38.64" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 80713f01fa3f..bb94845e0c39 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.61 +# github.com/aws/aws-sdk-go v1.38.64 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 37d6933a739461430eb787558af0c3763ba6cc98 Mon Sep 17 00:00:00 2001 From: FrancescoFucile-CAZ Date: Fri, 18 Jun 2021 09:43:03 +0100 Subject: [PATCH 0587/1208] fix typo in documentation. --- website/docs/r/cloudwatch_event_bus_policy.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cloudwatch_event_bus_policy.html.markdown b/website/docs/r/cloudwatch_event_bus_policy.html.markdown index d49b0b6aa311..8118baae00e7 100644 --- a/website/docs/r/cloudwatch_event_bus_policy.html.markdown +++ b/website/docs/r/cloudwatch_event_bus_policy.html.markdown @@ -145,7 +145,7 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: -* `id` - The name of the EventBrige event bus. +* `id` - The name of the EventBridge event bus. ## Import From ced3e7804196bcf38404f2cf0ef3f2f26fe29439 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:28:30 -0400 Subject: [PATCH 0588/1208] add missing period in R53 record resource comment Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 5e0061b0ce49..5567a2d863e5 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -42,7 +42,7 @@ func resourceAwsRoute53Record() *schema.Resource { StateFunc: func(v interface{}) string { // AWS Provider aws_acm_certification.domain_validation_options.resource_record_name // references (and perhaps others) contain a trailing period, requiring a custom StateFunc - // to trim the string to prevent Route53 API error + // to trim the string to prevent Route53 API error. value := strings.TrimSuffix(v.(string), ".") return strings.ToLower(value) }, From fbb49e2de7ab64fca74fff0491a50c5b27362dc8 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:31:01 -0400 Subject: [PATCH 0589/1208] add missing comma & period in R53 resource comment Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 5567a2d863e5..9805f986399c 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -260,8 +260,8 @@ func resourceAwsRoute53RecordUpdate(d *schema.ResourceData, meta interface{}) er return resourceAwsRoute53RecordCreate(d, meta) } - // Otherwise we delete the existing record and create a new record within - // a transactional change + // Otherwise, we delete the existing record and create a new record within + // a transactional change. conn := meta.(*AWSClient).r53conn zone := cleanZoneID(d.Get("zone_id").(string)) From 31d72b8cff165c3a6a8d0345a0db82a2c0ec2e89 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:32:52 -0400 Subject: [PATCH 0590/1208] add missing period in R53 record comment Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 9805f986399c..a9861a5ab838 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -407,7 +407,7 @@ func resourceAwsRoute53RecordCreate(d *schema.ResourceData, meta interface{}) er return err } - // Protect existing DNS records which might be managed in another way + // Protect existing DNS records which might be managed in another way. // Use UPSERT only if the overwrite flag is true or if the current action is an update // Else CREATE is used and fail if the same record exists var action string From 9decc3c6cb8db7cd9b88da865415b6f6ddb44cef Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:33:48 -0400 Subject: [PATCH 0591/1208] add missing comma in R53 resource code comment Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index a9861a5ab838..6e95be2235f7 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -506,7 +506,7 @@ func waitForRoute53RecordSetToSync(conn *route53.Route53, requestId string) erro } func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) error { - // If we don't have a zone ID we're doing an import. Parse it from the ID. + // If we don't have a zone ID, we're doing an import. Parse it from the ID. if _, ok := d.GetOk("zone_id"); !ok { parts := parseRecordId(d.Id()) //we check that we have parsed the id into the correct number of segments From ec5896a9b85f6ca03f4a269eeb0e925fb0fac0d0 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:34:25 -0400 Subject: [PATCH 0592/1208] normalize code comment formatting Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 6e95be2235f7..ffcd7b16f3db 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -509,8 +509,8 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro // If we don't have a zone ID, we're doing an import. Parse it from the ID. if _, ok := d.GetOk("zone_id"); !ok { parts := parseRecordId(d.Id()) - //we check that we have parsed the id into the correct number of segments - //we need at least 3 segments! + // We check that we have parsed the id into the correct number of segments. + // We need at least 3 segments! if parts[0] == "" || parts[1] == "" || parts[2] == "" { return fmt.Errorf("Error Importing aws_route_53 record. Please make sure the record ID is in the form ZONEID_RECORDNAME_TYPE_SET-IDENTIFIER (e.g. Z4KAPRWWNC7JR_dev.example.com_NS_dev), where SET-IDENTIFIER is optional") } From 5f5f349476fd86eca66f78f3dc4ed17c1fbdd535 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:35:17 -0400 Subject: [PATCH 0593/1208] use possessive 'its' in R53 resource comment Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index ffcd7b16f3db..0e3778be37f3 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -604,7 +604,7 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro } // findRecord takes a ResourceData struct for aws_resource_route53_record. It -// uses the referenced zone_id to query Route53 and find information on it's +// uses the referenced zone_id to query Route53 and find information on its // records. // // If records are found, it returns the matching From 5e1f911dc104ceb88572fb874902cf4fca571e12 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:36:44 -0400 Subject: [PATCH 0594/1208] add missing period in R53 resource comment Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 0e3778be37f3..eec9f9b14b19 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -614,7 +614,7 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro // error. // // If no matching recordset is found, it returns nil and a r53NoRecordsFound -// error +// error. // // If there are other errors, it returns nil a nil recordset and passes on the // error. From 34af178d086d4d9ccb29fac0f471f6740c09621f Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:37:43 -0400 Subject: [PATCH 0595/1208] correct typo in R53 resource comment Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index eec9f9b14b19..305d49b5ee99 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -616,7 +616,7 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro // If no matching recordset is found, it returns nil and a r53NoRecordsFound // error. // -// If there are other errors, it returns nil a nil recordset and passes on the +// If there are other errors, it returns a nil recordset and passes on the // error. func findRecord(d *schema.ResourceData, meta interface{}) (*route53.ResourceRecordSet, error) { conn := meta.(*AWSClient).r53conn From 39d4aba4c4fba07ccd4d073ad7cee061860593c2 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:38:42 -0400 Subject: [PATCH 0596/1208] add missing commas in R53 resource comment Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 305d49b5ee99..919aea3fe76b 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -674,9 +674,9 @@ func findRecord(d *schema.ResourceData, meta interface{}) (*route53.ResourceReco // We need to loop over all records starting from the record we are looking for because // Weighted, Latency, Geo, and Failover resource record sets have a special option // called SetIdentifier which allows multiple entries with the same name and type but - // a different SetIdentifier + // a different SetIdentifier. // For all other records we are setting the maxItems to 1 so that we don't return extra - // unneeded records + // unneeded records. err = conn.ListResourceRecordSetsPages(lopts, func(resp *route53.ListResourceRecordSetsOutput, lastPage bool) bool { for _, recordSet := range resp.ResourceRecordSets { From d216c42d68f29fbbbe74d3f89fa44eccfcf7e6e6 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:40:52 -0400 Subject: [PATCH 0597/1208] correct run-on sentence in R53 resource comment Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 919aea3fe76b..c91c1a375d78 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -908,7 +908,6 @@ func FQDN(name string) string { // Route 53 stores certain characters with the octal equivalent in ASCII format. // This function converts all of these characters back into the original character // E.g. "*" is stored as "\\052" and "@" as "\\100" - func cleanRecordName(name string) string { str := name s, err := strconv.Unquote(`"` + str + `"`) @@ -946,7 +945,7 @@ func resourceAwsRoute53AliasRecordHash(v interface{}) int { // nilString takes a string as an argument and returns a string // pointer. The returned pointer is nil if the string argument is -// empty, otherwise it is a pointer to a copy of the string. +// empty. Otherwise, it is a pointer to a copy of the string. func nilString(s string) *string { if s == "" { return nil From ca3e218774f58c6066ff861d2b1d25eb338812ee Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 18 Jun 2021 06:44:06 -0400 Subject: [PATCH 0598/1208] add missing period in R53 record resource comment Signed-off-by: Mike Ball --- aws/resource_aws_route53_record.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index c91c1a375d78..37d1391cf832 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -906,7 +906,7 @@ func FQDN(name string) string { } // Route 53 stores certain characters with the octal equivalent in ASCII format. -// This function converts all of these characters back into the original character +// This function converts all of these characters back into the original character. // E.g. "*" is stored as "\\052" and "@" as "\\100" func cleanRecordName(name string) string { str := name From 194ab9b6c28a0624639af9e6f135674949e167d8 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Fri, 18 Jun 2021 09:10:57 -0400 Subject: [PATCH 0599/1208] add backup vault sweeper --- aws/resource_aws_backup_vault_test.go | 75 +++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/aws/resource_aws_backup_vault_test.go b/aws/resource_aws_backup_vault_test.go index f1c41103dfb0..7bc61b810433 100644 --- a/aws/resource_aws_backup_vault_test.go +++ b/aws/resource_aws_backup_vault_test.go @@ -2,15 +2,90 @@ package aws import ( "fmt" + "log" "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/backup" + "github.com/hashicorp/go-multierror" "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 init() { + resource.AddTestSweepers("aws_backup_vault", &resource.Sweeper{ + Name: "aws_backup_vault", + F: testSweepBackupVaults, + Dependencies: []string{ + "aws_backup_vault_notifications", + "aws_backup_vault_policy", + }, + }) +} + +func testSweepBackupVaults(region string) error { + client, err := sharedClientForRegion(region) + + if err != nil { + return fmt.Errorf("Error getting client: %w", err) + } + + conn := client.(*AWSClient).backupconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + + input := &backup.ListBackupVaultsInput{} + + err = conn.ListBackupVaultsPages(input, func(page *backup.ListBackupVaultsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, vault := range page.BackupVaultList { + if vault == nil { + continue + } + + // Ignore Default Backup Vault in region (cannot be deleted) + if aws.StringValue(vault.BackupVaultName) == "Default" { + log.Printf("[INFO] Skipping Backup Vault: Default") + continue + } + + // Backup Vault deletion only supported when empty + // Reference: https://docs.aws.amazon.com/aws-backup/latest/devguide/API_DeleteBackupVault.html + if aws.Int64Value(vault.NumberOfRecoveryPoints) != 0 { + log.Printf("[INFO] Skipping Backup Vault (%s): not empty", aws.StringValue(vault.BackupVaultName)) + continue + } + + r := resourceAwsBackupVault() + d := r.Data(nil) + d.SetId(aws.StringValue(vault.BackupVaultName)) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing Backup Vaults for %s: %w", region, err)) + } + + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Backup Vaults for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping Backup Vaults sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} + func TestAccAwsBackupVault_basic(t *testing.T) { var vault backup.DescribeBackupVaultOutput From 3753521fb6ba3db907958ce2b7d31a773ead765d Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Fri, 18 Jun 2021 09:29:40 -0400 Subject: [PATCH 0600/1208] use paginated func and add concurrency --- ...rce_aws_backup_vault_notifications_test.go | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/aws/resource_aws_backup_vault_notifications_test.go b/aws/resource_aws_backup_vault_notifications_test.go index 45c983015f91..8ccc610791cb 100644 --- a/aws/resource_aws_backup_vault_notifications_test.go +++ b/aws/resource_aws_backup_vault_notifications_test.go @@ -22,52 +22,51 @@ func init() { func testSweepBackupVaultNotifications(region string) error { client, err := sharedClientForRegion(region) + if err != nil { return fmt.Errorf("Error getting client: %w", err) } + conn := client.(*AWSClient).backupconn - var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error input := &backup.ListBackupVaultsInput{} - for { - output, err := conn.ListBackupVaults(input) - if err != nil { - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping Backup Vault Notifications sweep for %s: %s", region, err) - return nil - } - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving Backup Vault Notifications: %w", err)) - return sweeperErrs.ErrorOrNil() + err = conn.ListBackupVaultsPages(input, func(page *backup.ListBackupVaultsOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - if len(output.BackupVaultList) == 0 { - log.Print("[DEBUG] No Backup Vault Notifications to sweep") - return nil - } - - for _, rule := range output.BackupVaultList { - name := aws.StringValue(rule.BackupVaultName) - - log.Printf("[INFO] Deleting Backup Vault Notifications %s", name) - _, err := conn.DeleteBackupVaultNotifications(&backup.DeleteBackupVaultNotificationsInput{ - BackupVaultName: aws.String(name), - }) - if err != nil { - sweeperErr := fmt.Errorf("error deleting Backup Vault Notifications %s: %w", name, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + for _, vault := range page.BackupVaultList { + if vault == nil { continue } - } - if output.NextToken == nil { - break + r := resourceAwsBackupVaultNotifications() + d := r.Data(nil) + d.SetId(aws.StringValue(vault.BackupVaultName)) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - input.NextToken = output.NextToken + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error listing Backup Vaults for %s: %w", region, err)) + } + + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Backup Vault Notifications for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping Backup Vault Notifications sweep for %s: %s", region, errs) + return nil } - return sweeperErrs.ErrorOrNil() + return errs.ErrorOrNil() } func TestAccAwsBackupVaultNotification_basic(t *testing.T) { From f86ed8217615821bcb2019ea484c27dc07740783 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Fri, 18 Jun 2021 09:34:18 -0400 Subject: [PATCH 0601/1208] skip default configs --- ...ws_apprunner_auto_scaling_configuration_version_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/aws/resource_aws_apprunner_auto_scaling_configuration_version_test.go b/aws/resource_aws_apprunner_auto_scaling_configuration_version_test.go index 696f49895a0d..de7209c65f33 100644 --- a/aws/resource_aws_apprunner_auto_scaling_configuration_version_test.go +++ b/aws/resource_aws_apprunner_auto_scaling_configuration_version_test.go @@ -49,6 +49,13 @@ func testSweepAppRunnerAutoScalingConfigurationVersions(region string) error { continue } + // Skip DefaultConfigurations as deletion not supported by the AppRunner service + // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/19840 + if aws.StringValue(summaryConfig.AutoScalingConfigurationName) == "DefaultConfiguration" { + log.Printf("[INFO] Skipping App Runner AutoScaling Configuration: DefaultConfiguration") + continue + } + arn := aws.StringValue(summaryConfig.AutoScalingConfigurationArn) log.Printf("[INFO] Deleting App Runner AutoScaling Configuration Version (%s)", arn) From 4312ce6c6351761588b72b813bfb5497c54cf18d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 18 Jun 2021 10:15:36 -0400 Subject: [PATCH 0602/1208] r/aws_vpc_endpoint: Fix semgrep error. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSVpcEndpoint_interfaceNonAWSServiceAccept' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSVpcEndpoint_interfaceNonAWSServiceAccept -timeout 180m === RUN TestAccAWSVpcEndpoint_interfaceNonAWSServiceAcceptOnCreate === PAUSE TestAccAWSVpcEndpoint_interfaceNonAWSServiceAcceptOnCreate === RUN TestAccAWSVpcEndpoint_interfaceNonAWSServiceAcceptOnUpdate === PAUSE TestAccAWSVpcEndpoint_interfaceNonAWSServiceAcceptOnUpdate === CONT TestAccAWSVpcEndpoint_interfaceNonAWSServiceAcceptOnCreate === CONT TestAccAWSVpcEndpoint_interfaceNonAWSServiceAcceptOnUpdate --- PASS: TestAccAWSVpcEndpoint_interfaceNonAWSServiceAcceptOnCreate (302.26s) --- PASS: TestAccAWSVpcEndpoint_interfaceNonAWSServiceAcceptOnUpdate (334.13s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 337.385s --- aws/resource_aws_vpc_endpoint.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_vpc_endpoint.go b/aws/resource_aws_vpc_endpoint.go index 2a2c17deb0f8..0f372c3acf0f 100644 --- a/aws/resource_aws_vpc_endpoint.go +++ b/aws/resource_aws_vpc_endpoint.go @@ -194,7 +194,7 @@ func resourceAwsVpcEndpointCreate(d *schema.ResourceData, meta interface{}) erro vpce := resp.VpcEndpoint d.SetId(aws.StringValue(vpce.VpcEndpointId)) - if v, ok := d.GetOk("auto_accept"); ok && v.(bool) && aws.StringValue(vpce.State) == "pendingAcceptance" { + if d.Get("auto_accept").(bool) && aws.StringValue(vpce.State) == tfec2.VpcEndpointStatePendingAcceptance { if err := vpcEndpointAccept(conn, d.Id(), aws.StringValue(vpce.ServiceName), d.Timeout(schema.TimeoutCreate)); err != nil { return err } @@ -314,7 +314,7 @@ func resourceAwsVpcEndpointRead(d *schema.ResourceData, meta interface{}) error func resourceAwsVpcEndpointUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - if d.HasChange("auto_accept") && d.Get("auto_accept").(bool) && d.Get("state").(string) == "pendingAcceptance" { + if d.HasChange("auto_accept") && d.Get("auto_accept").(bool) && d.Get("state").(string) == tfec2.VpcEndpointStatePendingAcceptance { if err := vpcEndpointAccept(conn, d.Id(), d.Get("service_name").(string), d.Timeout(schema.TimeoutUpdate)); err != nil { return err } From cdeb9cb010d198995d98151ce3b708fa54a0f4c6 Mon Sep 17 00:00:00 2001 From: Lily Date: Wed, 28 Apr 2021 12:32:36 -0700 Subject: [PATCH 0603/1208] EKS supports adding KMS envelope encryption to existing clusters https://aws.amazon.com/about-aws/whats-new/2021/03/amazon-eks-supports-adding-kms-envelope-encryption-to-existing-clusters/ Fixes #17952 --- aws/resource_aws_eks_cluster.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index 683d67b04a1c..fb930a6ab3ce 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -60,20 +60,17 @@ func resourceAwsEksCluster() *schema.Resource { Type: schema.TypeList, MaxItems: 1, Optional: true, - ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "provider": { Type: schema.TypeList, MaxItems: 1, Required: true, - ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "key_arn": { Type: schema.TypeString, Required: true, - ForceNew: true, }, }, }, @@ -82,7 +79,6 @@ func resourceAwsEksCluster() *schema.Resource { Type: schema.TypeSet, MinItems: 1, Required: true, - ForceNew: true, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.StringInSlice([]string{ From 8ac9ea3eb925647e06799ed6f464d9ccdf6245e3 Mon Sep 17 00:00:00 2001 From: Lily Date: Mon, 3 May 2021 10:00:35 -0700 Subject: [PATCH 0604/1208] Add api calls to update encryption config --- aws/resource_aws_eks_cluster.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index fb930a6ab3ce..09492a97ee35 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -388,6 +388,31 @@ func resourceAwsEksClusterUpdate(d *schema.ResourceData, meta interface{}) error } } + if d.HasChange("encryption_config") { + input := &eks.AssociateEncryptionConfigInput{ + ClusterName: aws.String(d.Id()), + EncryptionConfig: expandEksEncryptionConfig(d.Get("encryption_config").([]interface{})), + } + + log.Printf("[DEBUG] Updating EKS Cluster (%s) version: %s", d.Id(), input) + output, err := conn.AssociateEncryptionConfig(input) + + if err != nil { + return fmt.Errorf("error updating EKS Cluster (%s) version: %s", d.Id(), err) + } + + if output == nil || output.Update == nil || output.Update.Id == nil { + return fmt.Errorf("error determining EKS Cluster (%s) version update ID: empty response", d.Id()) + } + + updateID := aws.StringValue(output.Update.Id) + + err = waitForUpdateEksCluster(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return fmt.Errorf("error waiting for EKS Cluster (%s) version update (%s): %s", d.Id(), updateID, err) + } + } + if d.HasChange("version") { input := &eks.UpdateClusterVersionInput{ Name: aws.String(d.Id()), From 8ee979ac5da8021a5c4b7162d2c22294bba39167 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 15:49:44 -0400 Subject: [PATCH 0605/1208] Add CHANGELOG entry. --- .changelog/19144.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19144.txt diff --git a/.changelog/19144.txt b/.changelog/19144.txt new file mode 100644 index 000000000000..2356f160f698 --- /dev/null +++ b/.changelog/19144.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_eks_cluster: Allow updates to `encryption_config` +``` \ No newline at end of file From f318deca584179a148924d60b1c28bb325c4d706 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 16:41:31 -0400 Subject: [PATCH 0606/1208] Add 'tfeks.Resources_Values()'. --- aws/internal/service/eks/enum.go | 11 ++++++++ aws/resource_aws_eks_cluster.go | 45 ++++++++++++++------------------ 2 files changed, 31 insertions(+), 25 deletions(-) create mode 100644 aws/internal/service/eks/enum.go diff --git a/aws/internal/service/eks/enum.go b/aws/internal/service/eks/enum.go new file mode 100644 index 000000000000..8e0f2c21f43b --- /dev/null +++ b/aws/internal/service/eks/enum.go @@ -0,0 +1,11 @@ +package eks + +const ( + ResourcesSecrets = "secrets" +) + +func Resources_Values() []string { + return []string{ + ResourcesSecrets, + } +} diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index 09492a97ee35..42147bcb1489 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -13,6 +13,7 @@ import ( "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" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" ) @@ -22,7 +23,6 @@ func resourceAwsEksCluster() *schema.Resource { Read: resourceAwsEksClusterRead, Update: resourceAwsEksClusterUpdate, Delete: resourceAwsEksClusterDelete, - Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, @@ -56,6 +56,14 @@ func resourceAwsEksCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "enabled_cluster_log_types": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(eks.LogType_Values(), true), + }, + }, "encryption_config": { Type: schema.TypeList, MaxItems: 1, @@ -80,10 +88,8 @@ func resourceAwsEksCluster() *schema.Resource { MinItems: 1, Required: true, Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - "secrets", - }, false), + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(tfeks.Resources_Values(), false), }, }, }, @@ -113,7 +119,6 @@ func resourceAwsEksCluster() *schema.Resource { }, }, }, - "kubernetes_network_config": { Type: schema.TypeList, Optional: true, @@ -134,7 +139,6 @@ func resourceAwsEksCluster() *schema.Resource { }, }, }, - "name": { Type: schema.TypeString, Required: true, @@ -183,6 +187,15 @@ func resourceAwsEksCluster() *schema.Resource { Optional: true, Default: true, }, + "public_access_cidrs": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateCIDRNetworkAddress, + }, + }, "security_group_ids": { Type: schema.TypeSet, Optional: true, @@ -196,15 +209,6 @@ func resourceAwsEksCluster() *schema.Resource { MinItems: 1, Elem: &schema.Schema{Type: schema.TypeString}, }, - "public_access_cidrs": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateCIDRNetworkAddress, - }, - }, "vpc_id": { Type: schema.TypeString, Computed: true, @@ -212,15 +216,6 @@ func resourceAwsEksCluster() *schema.Resource { }, }, }, - "enabled_cluster_log_types": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice(eks.LogType_Values(), true), - }, - Set: schema.HashString, - }, }, } } From 18655a1579c109c163c41abdb28b051af91f0724 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 17:17:33 -0400 Subject: [PATCH 0607/1208] r/aws_eks_cluster: Call resource Delete method in acceptance test sweeper. --- aws/resource_aws_eks_cluster_test.go | 35 ++++++++++++++++------------ 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/aws/resource_aws_eks_cluster_test.go b/aws/resource_aws_eks_cluster_test.go index 74dcbaf9d631..667182ca2ac8 100644 --- a/aws/resource_aws_eks_cluster_test.go +++ b/aws/resource_aws_eks_cluster_test.go @@ -35,36 +35,41 @@ func testSweepEksClusters(region string) error { return fmt.Errorf("error getting client: %s", err) } conn := client.(*AWSClient).eksconn - - var errors error input := &eks.ListClustersInput{} + var sweeperErrs *multierror.Error + err = conn.ListClustersPages(input, func(page *eks.ListClustersOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + for _, cluster := range page.Clusters { - name := aws.StringValue(cluster) + r := resourceAwsEksCluster() + d := r.Data(nil) + d.SetId(aws.StringValue(cluster)) + + err = r.Delete(d, client) - log.Printf("[INFO] Deleting EKS Cluster: %s", name) - err := deleteEksCluster(conn, name) - if err != nil { - errors = multierror.Append(errors, fmt.Errorf("error deleting EKS Cluster %q: %w", name, err)) - continue - } - err = waitForDeleteEksCluster(conn, name, 15*time.Minute) if err != nil { - errors = multierror.Append(errors, fmt.Errorf("error waiting for EKS Cluster %q deletion: %w", name, err)) + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) continue } } - return true + + return !lastPage }) + if testSweepSkipSweepError(err) { log.Printf("[WARN] Skipping EKS Clusters sweep for %s: %s", region, err) - return errors // In case we have completed some pages, but had errors + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors } + if err != nil { - errors = multierror.Append(errors, fmt.Errorf("error retrieving EKS Clusters: %w", err)) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Clusters: %w", err)) } - return errors + return sweeperErrs.ErrorOrNil() } func TestAccAWSEksCluster_basic(t *testing.T) { From 2687259ea812f150a5c26b2c54e5484e48bdc195 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 17:34:32 -0400 Subject: [PATCH 0608/1208] r/aws_eks_cluster: Parallelize acceptance test sweeper. --- aws/resource_aws_eks_cluster_test.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_eks_cluster_test.go b/aws/resource_aws_eks_cluster_test.go index 667182ca2ac8..a21177bab862 100644 --- a/aws/resource_aws_eks_cluster_test.go +++ b/aws/resource_aws_eks_cluster_test.go @@ -11,7 +11,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" - multierror "github.com/hashicorp/go-multierror" "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" @@ -36,7 +35,7 @@ func testSweepEksClusters(region string) error { } conn := client.(*AWSClient).eksconn input := &eks.ListClustersInput{} - var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) err = conn.ListClustersPages(input, func(page *eks.ListClustersOutput, lastPage bool) bool { if page == nil { @@ -48,13 +47,7 @@ func testSweepEksClusters(region string) error { d := r.Data(nil) d.SetId(aws.StringValue(cluster)) - err = r.Delete(d, client) - - if err != nil { - log.Printf("[ERROR] %s", err) - sweeperErrs = multierror.Append(sweeperErrs, err) - continue - } + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } return !lastPage @@ -62,14 +55,20 @@ func testSweepEksClusters(region string) error { if testSweepSkipSweepError(err) { log.Printf("[WARN] Skipping EKS Clusters sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + return nil } if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Clusters: %w", err)) + return fmt.Errorf("error listing EKS Clusters (%s): %w", region, err) } - return sweeperErrs.ErrorOrNil() + err = testSweepResourceOrchestrator(sweepResources) + + if err != nil { + return fmt.Errorf("error sweeping EKS Clusters (%s): %w", region, err) + } + + return nil } func TestAccAWSEksCluster_basic(t *testing.T) { From 2ac70f78df280fe03c2b57b84c2cbb1429a81933 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 18 Jun 2021 08:56:31 -0400 Subject: [PATCH 0609/1208] r/aws_eks_cluster: Add and use internal finder package. Add '_disappears' test (#13826). Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSEksCluster_basic\|TestAccAWSEksCluster_disappears' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSEksCluster_basic\|TestAccAWSEksCluster_disappears -timeout 180m === RUN TestAccAWSEksCluster_basic === PAUSE TestAccAWSEksCluster_basic === RUN TestAccAWSEksCluster_disappears === PAUSE TestAccAWSEksCluster_disappears === CONT TestAccAWSEksCluster_basic === CONT TestAccAWSEksCluster_disappears --- PASS: TestAccAWSEksCluster_basic (673.27s) --- PASS: TestAccAWSEksCluster_disappears (681.94s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 685.380s --- aws/internal/service/eks/finder/finder.go | 38 +++++++ aws/resource_aws_eks_cluster.go | 130 ++++++++++++---------- aws/resource_aws_eks_cluster_test.go | 69 ++++++------ 3 files changed, 144 insertions(+), 93 deletions(-) create mode 100644 aws/internal/service/eks/finder/finder.go diff --git a/aws/internal/service/eks/finder/finder.go b/aws/internal/service/eks/finder/finder.go new file mode 100644 index 000000000000..c6a5565bda9a --- /dev/null +++ b/aws/internal/service/eks/finder/finder.go @@ -0,0 +1,38 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/eks" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func ClusterByName(conn *eks.EKS, name string) (*eks.Cluster, error) { + input := &eks.DescribeClusterInput{ + Name: aws.String(name), + } + + output, err := conn.DescribeCluster(input) + + // Sometimes the EKS API returns the ResourceNotFound error in this form: + // ClientException: No cluster found for name: tf-acc-test-0o1f8 + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) || tfawserr.ErrMessageContains(err, eks.ErrCodeClientException, "No cluster found for name:") { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Cluster == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.Cluster, nil +} diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index 42147bcb1489..620b754e09e1 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -9,12 +9,15 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsEksCluster() *schema.Resource { @@ -301,50 +304,53 @@ func resourceAwsEksClusterRead(d *schema.ResourceData, meta interface{}) error { defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - input := &eks.DescribeClusterInput{ - Name: aws.String(d.Id()), - } + cluster, err := finder.ClusterByName(conn, d.Id()) - log.Printf("[DEBUG] Reading EKS Cluster: %s", input) - output, err := conn.DescribeCluster(input) - if err != nil { - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] EKS Cluster (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - return fmt.Errorf("error reading EKS Cluster (%s): %s", d.Id(), err) - } - - cluster := output.Cluster - if cluster == nil { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] EKS Cluster (%s) not found, removing from state", d.Id()) d.SetId("") return nil } + if err != nil { + return fmt.Errorf("error reading EKS Cluster (%s): %w", d.Id(), err) + } + d.Set("arn", cluster.Arn) if err := d.Set("certificate_authority", flattenEksCertificate(cluster.CertificateAuthority)); err != nil { - return fmt.Errorf("error setting certificate_authority: %s", err) + return fmt.Errorf("error setting certificate_authority: %w", err) } d.Set("created_at", aws.TimeValue(cluster.CreatedAt).String()) + if err := d.Set("enabled_cluster_log_types", flattenEksEnabledLogTypes(cluster.Logging)); err != nil { + return fmt.Errorf("error setting enabled_cluster_log_types: %w", err) + } + if err := d.Set("encryption_config", flattenEksEncryptionConfig(cluster.EncryptionConfig)); err != nil { - return fmt.Errorf("error setting encryption_config: %s", err) + return fmt.Errorf("error setting encryption_config: %w", err) } d.Set("endpoint", cluster.Endpoint) if err := d.Set("identity", flattenEksIdentity(cluster.Identity)); err != nil { - return fmt.Errorf("error setting identity: %s", err) + return fmt.Errorf("error setting identity: %w", err) + } + + if err := d.Set("kubernetes_network_config", flattenEksNetworkConfig(cluster.KubernetesNetworkConfig)); err != nil { + return fmt.Errorf("error setting kubernetes_network_config: %w", err) } d.Set("name", cluster.Name) d.Set("platform_version", cluster.PlatformVersion) d.Set("role_arn", cluster.RoleArn) d.Set("status", cluster.Status) + d.Set("version", cluster.Version) + + if err := d.Set("vpc_config", flattenEksVpcConfigResponse(cluster.ResourcesVpcConfig)); err != nil { + return fmt.Errorf("error setting vpc_config: %w", err) + } tags := keyvaluetags.EksKeyValueTags(cluster.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -357,32 +363,12 @@ func resourceAwsEksClusterRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting tags_all: %w", err) } - d.Set("version", cluster.Version) - if err := d.Set("enabled_cluster_log_types", flattenEksEnabledLogTypes(cluster.Logging)); err != nil { - return fmt.Errorf("error setting enabled_cluster_log_types: %s", err) - } - - if err := d.Set("vpc_config", flattenEksVpcConfigResponse(cluster.ResourcesVpcConfig)); err != nil { - return fmt.Errorf("error setting vpc_config: %s", err) - } - - if err := d.Set("kubernetes_network_config", flattenEksNetworkConfig(cluster.KubernetesNetworkConfig)); err != nil { - return fmt.Errorf("error setting kubernetes_network_config: %w", err) - } - return nil } func resourceAwsEksClusterUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).eksconn - if d.HasChange("tags_all") { - o, n := d.GetChange("tags_all") - if err := keyvaluetags.EksUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating tags: %s", err) - } - } - if d.HasChange("encryption_config") { input := &eks.AssociateEncryptionConfigInput{ ClusterName: aws.String(d.Id()), @@ -484,6 +470,13 @@ func resourceAwsEksClusterUpdate(d *schema.ResourceData, meta interface{}) error } } + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + if err := keyvaluetags.EksUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %w", err) + } + } + return resourceAwsEksClusterRead(d, meta) } @@ -491,35 +484,27 @@ func resourceAwsEksClusterDelete(d *schema.ResourceData, meta interface{}) error conn := meta.(*AWSClient).eksconn log.Printf("[DEBUG] Deleting EKS Cluster: %s", d.Id()) - err := deleteEksCluster(conn, d.Id()) - if err != nil { - return fmt.Errorf("error deleting EKS Cluster (%s): %s", d.Id(), err) - } + _, err := conn.DeleteCluster(&eks.DeleteClusterInput{ + Name: aws.String(d.Id()), + }) - err = waitForDeleteEksCluster(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) - if err != nil { - return fmt.Errorf("error waiting for EKS Cluster (%s) deletion: %s", d.Id(), err) + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { + return nil } - return nil -} + // Sometimes the EKS API returns the ResourceNotFound error in this form: + // ClientException: No cluster found for name: tf-acc-test-0o1f8 + if tfawserr.ErrMessageContains(err, eks.ErrCodeClientException, "No cluster found for name:") { + return nil + } -func deleteEksCluster(conn *eks.EKS, clusterName string) error { - input := &eks.DeleteClusterInput{ - Name: aws.String(clusterName), + if err != nil { + return fmt.Errorf("error deleting EKS Cluster (%s): %s", d.Id(), err) } - _, err := conn.DeleteCluster(input) + err = waitForDeleteEksCluster(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) if err != nil { - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - return nil - } - // Sometimes the EKS API returns the ResourceNotFound error in this form: - // ClientException: No cluster found for name: tf-acc-test-0o1f8 - if isAWSErr(err, eks.ErrCodeClientException, "No cluster found for name:") { - return nil - } - return err + return fmt.Errorf("error waiting for EKS Cluster (%s) deletion: %s", d.Id(), err) } return nil @@ -798,6 +783,29 @@ func refreshEksUpdateStatus(conn *eks.EKS, clusterName, updateID string) resourc } func waitForDeleteEksCluster(conn *eks.EKS, clusterName string, timeout time.Duration) error { + /* + TODO + + // Handle eventual consistency + err := resource.Retry(1*time.Minute, func() *resource.RetryError { + output, err := conn.DescribeCluster(&eks.DescribeClusterInput{ + Name: aws.String(rs.Primary.ID), + }) + + if err != nil { + if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + return nil + } + return resource.NonRetryableError(err) + } + + if output != nil && output.Cluster != nil && aws.StringValue(output.Cluster.Name) == rs.Primary.ID { + return resource.RetryableError(fmt.Errorf("EKS Cluster %s still exists", rs.Primary.ID)) + } + + return nil + }) + */ stateConf := resource.StateChangeConf{ Pending: []string{ eks.ClusterStatusActive, diff --git a/aws/resource_aws_eks_cluster_test.go b/aws/resource_aws_eks_cluster_test.go index a21177bab862..d255f5e1a941 100644 --- a/aws/resource_aws_eks_cluster_test.go +++ b/aws/resource_aws_eks_cluster_test.go @@ -7,13 +7,14 @@ import ( "regexp" "strings" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -73,7 +74,6 @@ func testSweepEksClusters(region string) error { func TestAccAWSEksCluster_basic(t *testing.T) { var cluster eks.Cluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) resourceName := "aws_eks_cluster.test" @@ -119,6 +119,29 @@ func TestAccAWSEksCluster_basic(t *testing.T) { }) } +func TestAccAWSEksCluster_disappears(t *testing.T) { + var cluster eks.Cluster + rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "aws_eks_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEksClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksClusterConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksClusterExists(resourceName, &cluster), + testAccCheckResourceDisappears(testAccProvider, resourceAwsEksCluster(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func TestAccAWSEksCluster_EncryptionConfig(t *testing.T) { var cluster eks.Cluster kmsKeyResourceName := "aws_kms_key.test" @@ -514,22 +537,14 @@ func testAccCheckAWSEksClusterExists(resourceName string, cluster *eks.Cluster) } conn := testAccProvider.Meta().(*AWSClient).eksconn - output, err := conn.DescribeCluster(&eks.DescribeClusterInput{ - Name: aws.String(rs.Primary.ID), - }) - if err != nil { - return err - } - if output == nil || output.Cluster == nil { - return fmt.Errorf("EKS Cluster (%s) not found", rs.Primary.ID) - } + output, err := finder.ClusterByName(conn, rs.Primary.ID) - if aws.StringValue(output.Cluster.Name) != rs.Primary.ID { - return fmt.Errorf("EKS Cluster (%s) not found", rs.Primary.ID) + if err != nil { + return err } - *cluster = *output.Cluster + *cluster = *output return nil } @@ -543,27 +558,17 @@ func testAccCheckAWSEksClusterDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).eksconn - // Handle eventual consistency - err := resource.Retry(1*time.Minute, func() *resource.RetryError { - output, err := conn.DescribeCluster(&eks.DescribeClusterInput{ - Name: aws.String(rs.Primary.ID), - }) + _, err := finder.ClusterByName(conn, rs.Primary.ID) - if err != nil { - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - return nil - } - return resource.NonRetryableError(err) - } - - if output != nil && output.Cluster != nil && aws.StringValue(output.Cluster.Name) == rs.Primary.ID { - return resource.RetryableError(fmt.Errorf("EKS Cluster %s still exists", rs.Primary.ID)) - } + if tfresource.NotFound(err) { + continue + } - return nil - }) + if err != nil { + return err + } - return err + return fmt.Errorf("EKS Cluster %s still exists", rs.Primary.ID) } return nil From f4ac852ac0d0cc219783290df3a87f4c7516a0ae Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 18 Jun 2021 09:56:30 -0400 Subject: [PATCH 0610/1208] Additional waiters. --- aws/internal/service/eks/finder/finder.go | 29 +++++++++++++++++++ aws/internal/service/eks/waiter/status.go | 34 +++++++++++++++++++++++ aws/internal/service/eks/waiter/waiter.go | 17 ++++++++++++ 3 files changed, 80 insertions(+) diff --git a/aws/internal/service/eks/finder/finder.go b/aws/internal/service/eks/finder/finder.go index c6a5565bda9a..a1b8fc712d7d 100644 --- a/aws/internal/service/eks/finder/finder.go +++ b/aws/internal/service/eks/finder/finder.go @@ -36,3 +36,32 @@ func ClusterByName(conn *eks.EKS, name string) (*eks.Cluster, error) { return output.Cluster, nil } + +func UpdateByNameAndID(conn *eks.EKS, name, id string) (*eks.Update, error) { + input := &eks.DescribeUpdateInput{ + Name: aws.String(name), + UpdateId: aws.String(id), + } + + output, err := conn.DescribeUpdate(input) + + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Update == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.Update, nil +} diff --git a/aws/internal/service/eks/waiter/status.go b/aws/internal/service/eks/waiter/status.go index f5013e37097d..97b22250a2fa 100644 --- a/aws/internal/service/eks/waiter/status.go +++ b/aws/internal/service/eks/waiter/status.go @@ -8,8 +8,42 @@ import ( "github.com/aws/aws-sdk-go/service/eks" "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) +func ClusterStatus(conn *eks.EKS, name string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.ClusterByName(conn, name) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} + +func UodateStatus(conn *eks.EKS, name, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.UpdateByNameAndID(conn, name, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} + func EksAddonStatus(ctx context.Context, conn *eks.EKS, addonName, clusterName string) resource.StateRefreshFunc { return func() (interface{}, string, error) { output, err := conn.DescribeAddonWithContext(ctx, &eks.DescribeAddonInput{ diff --git a/aws/internal/service/eks/waiter/waiter.go b/aws/internal/service/eks/waiter/waiter.go index badfeb90cd5c..41d1446328fc 100644 --- a/aws/internal/service/eks/waiter/waiter.go +++ b/aws/internal/service/eks/waiter/waiter.go @@ -18,6 +18,23 @@ const ( EksAddonDeletedTimeout = 40 * time.Minute ) +func ClusterDeleted(conn *eks.EKS, name string, timeout time.Duration) (*eks.Cluster, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{eks.ClusterStatusActive, eks.ClusterStatusDeleting}, + Target: []string{}, + Refresh: ClusterStatus(conn, name), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*eks.Cluster); ok { + return output, err + } + + return nil, err +} + // EksAddonCreated waits for a EKS add-on to return status "ACTIVE" or "CREATE_FAILED" func EksAddonCreated(ctx context.Context, conn *eks.EKS, clusterName, addonName string) (*eks.Addon, error) { stateConf := resource.StateChangeConf{ From 97308e6bc5f797a572ffd0759bbaa924d1ecef27 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Fri, 18 Jun 2021 15:12:21 +0000 Subject: [PATCH 0611/1208] Update CHANGELOG.md for #19867 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 616208a02cc9..5e135a58b215 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,14 @@ ## 3.47.0 (Unreleased) + +ENHANCEMENTS: + +* resource/aws_default_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) +* resource/aws_default_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) +* resource/aws_main_route_table_association: Wait for association to reach the required state ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) +* resource/aws_route: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) +* resource/aws_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) +* resource/aws_route_table_association: Wait for association to reach the required state ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) + ## 3.46.0 (June 17, 2021) FEATURES: From 9a7d46ef424ceddb995823fb3e3d8ad27e9b81a0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 18:28:42 -0400 Subject: [PATCH 0612/1208] r/route53_zone: Use aws.StringValue() instead --- aws/resource_aws_route53_zone.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index 5ff097e9a156..1e49ef6c59d7 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -348,7 +348,7 @@ func deleteAllRecordsInHostedZoneId(hostedZoneId, hostedZoneName string, conn *r changes := make([]*route53.Change, 0) // 100 items per page returned by default for _, set := range sets { - if strings.TrimSuffix(*set.Name, ".") == strings.TrimSuffix(hostedZoneName, ".") && (*set.Type == "NS" || *set.Type == "SOA") { + if strings.TrimSuffix(aws.StringValue(set.Name), ".") == strings.TrimSuffix(hostedZoneName, ".") && (aws.StringValue(set.Type) == "NS" || aws.StringValue(set.Type) == "SOA") { // Zone NS & SOA records cannot be deleted continue } @@ -357,8 +357,7 @@ func deleteAllRecordsInHostedZoneId(hostedZoneId, hostedZoneName string, conn *r ResourceRecordSet: set, }) } - log.Printf("[DEBUG] Deleting %d records (page %d) from %s", - len(changes), pageNum, hostedZoneId) + log.Printf("[DEBUG] Deleting %d records (page %d) from %s", len(changes), pageNum, hostedZoneId) req := &route53.ChangeResourceRecordSetsInput{ HostedZoneId: aws.String(hostedZoneId), @@ -373,7 +372,7 @@ func deleteAllRecordsInHostedZoneId(hostedZoneId, hostedZoneName string, conn *r if out, ok := resp.(*route53.ChangeResourceRecordSetsOutput); ok { log.Printf("[DEBUG] Waiting for change batch to become INSYNC: %#v", out) if out.ChangeInfo != nil && out.ChangeInfo.Id != nil { - lastErrorFromWaiter = waitForRoute53RecordSetToSync(conn, cleanChangeID(*out.ChangeInfo.Id)) + lastErrorFromWaiter = waitForRoute53RecordSetToSync(conn, cleanChangeID(aws.StringValue(out.ChangeInfo.Id))) } else { log.Printf("[DEBUG] Change info was empty") } @@ -397,7 +396,7 @@ func resourceAwsGoRoute53Wait(r53 *route53.Route53, ref *route53.GetChangeInput) if err != nil { return nil, "UNKNOWN", err } - return true, *status.ChangeInfo.Status, nil + return true, aws.StringValue(status.ChangeInfo.Status), nil } // cleanChangeID is used to remove the leading /change/ @@ -446,7 +445,7 @@ func getNameServers(zoneId string, zoneName string, r53 *route53.Route53) ([]str } ns := make([]string, len(resp.ResourceRecordSets[0].ResourceRecords)) for i := range resp.ResourceRecordSets[0].ResourceRecords { - ns[i] = *resp.ResourceRecordSets[0].ResourceRecords[i].Value + ns[i] = aws.StringValue(resp.ResourceRecordSets[0].ResourceRecords[i].Value) } sort.Strings(ns) return ns, nil From 71d7857ffd5bfebb2ada9e16d6be448c2611b6e4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 17 Jun 2021 18:29:07 -0400 Subject: [PATCH 0613/1208] tests/r/route53_zone: Add sweeper --- aws/resource_aws_route53_zone_test.go | 82 +++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index 406c477de564..9fe280f8d358 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -4,10 +4,12 @@ import ( "fmt" "log" "sort" + "strings" "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/route53" + multierror "github.com/hashicorp/go-multierror" "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/helper/schema" @@ -73,6 +75,86 @@ func TestTrimTrailingPeriod(t *testing.T) { } } +// add sweeper to delete resources +func init() { + resource.AddTestSweepers("aws_route53_zone", &resource.Sweeper{ + Name: "aws_route53_zone", + Dependencies: []string{ + "aws_service_discovery_http_namespace", + "aws_service_discovery_public_dns_namespace", + "aws_service_discovery_private_dns_namespace", + "aws_elb", + }, + F: testSweepRoute53Zones, + }) +} + +func testSweepRoute53Zones(region string) error { + client, err := sharedClientForRegion(region) + + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + + conn := client.(*AWSClient).r53conn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + + input := &route53.ListHostedZonesInput{} + + hostedZonesToPreserve := []string{ + "acmetest.hashicorp.engineering", + "tfacc.hashicorptest.com", + "aws.tfacc.hashicorptest.com", + } + + err = conn.ListHostedZonesPages(input, func(page *route53.ListHostedZonesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, detail := range page.HostedZones { + if detail == nil { + continue + } + + id := aws.StringValue(detail.Id) + + for _, domain := range hostedZonesToPreserve { + if strings.Contains(aws.StringValue(detail.Name), domain) { + log.Printf("[DEBUG] Skipping Route53 Hosted Zone (%s): %s", domain, id) + continue + } + } + + r := resourceAwsRoute53Zone() + d := r.Data(nil) + d.SetId(id) + d.Set("force_destroy", true) + d.Set("name", detail.Name) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing Route53 Hosted Zones for %s: %w", region, err)) + } + + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Route53 Hosted Zones for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping Route53 Hosted Zones sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} + func TestAccAWSRoute53Zone_basic(t *testing.T) { var zone route53.GetHostedZoneOutput From 8306f7a11cbee46ce4bfa3eac4d824faa2ff2698 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 18 Jun 2021 11:23:35 -0400 Subject: [PATCH 0614/1208] r/route53_zone: Add protected domain --- aws/resource_aws_route53_zone_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index 9fe280f8d358..b0c61a531037 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -106,6 +106,7 @@ func testSweepRoute53Zones(region string) error { "acmetest.hashicorp.engineering", "tfacc.hashicorptest.com", "aws.tfacc.hashicorptest.com", + "hashicorp.com", } err = conn.ListHostedZonesPages(input, func(page *route53.ListHostedZonesOutput, lastPage bool) bool { From 15a8b4ea63a64d978712a2386031d3ce370b801d Mon Sep 17 00:00:00 2001 From: Simon Davis Date: Fri, 18 Jun 2021 08:26:52 -0700 Subject: [PATCH 0615/1208] use values array instead of seperate values (#19876) --- aws/resource_aws_lb_target_group.go | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index 57e4cf218b89..2d01e6688fa2 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -256,15 +256,11 @@ func resourceAwsLbTargetGroup() *schema.Resource { }, }, "target_type": { - Type: schema.TypeString, - Optional: true, - Default: elbv2.TargetTypeEnumInstance, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - elbv2.TargetTypeEnumInstance, - elbv2.TargetTypeEnumIp, - elbv2.TargetTypeEnumLambda, - }, false), + Type: schema.TypeString, + Optional: true, + Default: elbv2.TargetTypeEnumInstance, + ForceNew: true, + ValidateFunc: validation.StringInSlice(elbv2.TargetTypeEnum_Values(), false), }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), From cd8b43fd3b1ec8b363c843960f40a8a8ab4e0c7e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 18 Jun 2021 12:37:30 -0400 Subject: [PATCH 0616/1208] tests/sweeper: Increase throttling timeout --- aws/aws_sweeper_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/aws/aws_sweeper_test.go b/aws/aws_sweeper_test.go index 5ce03b6a4ad3..41c726557ae7 100644 --- a/aws/aws_sweeper_test.go +++ b/aws/aws_sweeper_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "log" "os" "testing" "time" @@ -15,7 +16,7 @@ import ( ) const ( - SweepThrottlingRetryTimeout = 5 * time.Minute + SweepThrottlingRetryTimeout = 10 * time.Minute ) // sweeperAwsClients is a shared cache of regional AWSClient @@ -87,7 +88,8 @@ func testSweepResourceOrchestrator(sweepResources []*testSweepResource) error { err := testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) if err != nil { - if tfawserr.ErrCodeContains(err, "ThrottlingException: Rate exceeded") { + if tfawserr.ErrCodeContains(err, "Throttling") { + log.Printf("[INFO] While sweeping resource (%s), encountered throttling error (%s). Retrying...", sweepResource.d.Id(), err) return resource.RetryableError(err) } From ba7ec6afc426788986f61ef170cab8200fe04cbf Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 18 Jun 2021 12:38:31 -0400 Subject: [PATCH 0617/1208] r/route53_zone: Make force_destroy more robust --- aws/resource_aws_route53_zone.go | 61 +++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index 1e49ef6c59d7..dce016fb0257 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -10,11 +10,14 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/route53" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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/hashcode" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsRoute53Zone() *schema.Resource { @@ -312,7 +315,11 @@ func resourceAwsRoute53ZoneDelete(d *schema.ResourceData, meta interface{}) erro if d.Get("force_destroy").(bool) { if err := deleteAllRecordsInHostedZoneId(d.Id(), d.Get("name").(string), conn); err != nil { - return fmt.Errorf("error deleting records in Route53 Hosted Zone (%s): %s", d.Id(), err) + return fmt.Errorf("error while force deleting Route53 Hosted Zone (%s), deleting records: %w", d.Id(), err) + } + + if err := deleteDNSSECForZone(conn, d.Id()); err != nil { + return fmt.Errorf("error while force deleting Route53 Hosted Zone (%s), disabling DNSSEC: %w", d.Id(), err) } } @@ -390,6 +397,58 @@ func deleteAllRecordsInHostedZoneId(hostedZoneId, hostedZoneName string, conn *r return nil } +func deleteDNSSECForZone(conn *route53.Route53, hostedZoneId string) error { + // hosted zones cannot be deleted if DNSSEC Key Signing Keys exist + input := &route53.DisableHostedZoneDNSSECInput{ + HostedZoneId: aws.String(hostedZoneId), + } + + var output *route53.DisableHostedZoneDNSSECOutput + err := resource.Retry(10*time.Minute, func() *resource.RetryError { + var err error + + output, err = conn.DisableHostedZoneDNSSEC(input) + + if err != nil { + if tfawserr.ErrCodeEquals(err, route53.ErrCodeKeySigningKeyInParentDSRecord) { + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + output, err = conn.DisableHostedZoneDNSSEC(input) + } + + if tfawserr.ErrCodeEquals(err, route53.ErrCodeDNSSECNotFound) { + return nil + } + + if tfawserr.ErrCodeEquals(err, route53.ErrCodeNoSuchHostedZone) { + return nil + } + + if tfawserr.ErrCodeContains(err, "InvalidArgument: Operation is unsupported for private") { + return nil + } + + if err != nil { + return fmt.Errorf("disabling Route 53 Hosted Zone DNSSEC (%s): %w", hostedZoneId, err) + } + + if output != nil && output.ChangeInfo != nil { + if _, err := waiter.ChangeInfoStatusInsync(conn, aws.StringValue(output.ChangeInfo.Id)); err != nil { + return fmt.Errorf("waiting for Route 53 Hosted Zone DNSSEC (%s) disable: %w", hostedZoneId, err) + } + } + + return nil +} + func resourceAwsGoRoute53Wait(r53 *route53.Route53, ref *route53.GetChangeInput) (result interface{}, state string, err error) { status, err := r53.GetChange(ref) From a16b261f61195bcc73ef826fa31659a51a5d8d83 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 18 Jun 2021 12:55:51 -0400 Subject: [PATCH 0618/1208] tests/sweeper: Update throttling check --- aws/aws_sweeper_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/aws_sweeper_test.go b/aws/aws_sweeper_test.go index 41c726557ae7..e064db16de30 100644 --- a/aws/aws_sweeper_test.go +++ b/aws/aws_sweeper_test.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "os" + "strings" "testing" "time" @@ -88,7 +89,7 @@ func testSweepResourceOrchestrator(sweepResources []*testSweepResource) error { err := testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) if err != nil { - if tfawserr.ErrCodeContains(err, "Throttling") { + if strings.Contains(err.Error(), "Throttling") { log.Printf("[INFO] While sweeping resource (%s), encountered throttling error (%s). Retrying...", sweepResource.d.Id(), err) return resource.RetryableError(err) } From 550694abc5a4922424eeec7b56f86cb12d0d4165 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 18 Jun 2021 12:56:27 -0400 Subject: [PATCH 0619/1208] r/route53_zone: Fix force_destroy DNSSEC disable --- aws/resource_aws_route53_zone.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index dce016fb0257..15b071c43c1e 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -432,7 +432,7 @@ func deleteDNSSECForZone(conn *route53.Route53, hostedZoneId string) error { return nil } - if tfawserr.ErrCodeContains(err, "InvalidArgument: Operation is unsupported for private") { + if tfawserr.ErrMessageContains(err, "InvalidArgument", "Operation is unsupported for private") { return nil } From 00c665ddb600941ad8a22bb40d1cae785c0be6ae Mon Sep 17 00:00:00 2001 From: Robert Sheehy Date: Fri, 18 Jun 2021 11:59:26 -0500 Subject: [PATCH 0620/1208] Update DNSSEC docs to a working example (#19746) * Update DNSSEC docs to a working example * fix kms key and zone naming Co-authored-by: Simon Davis --- .../route53_hosted_zone_dnssec.html.markdown | 26 ++++++++++++++++--- .../r/route53_key_signing_key.html.markdown | 22 ++++++++++++++-- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/website/docs/r/route53_hosted_zone_dnssec.html.markdown b/website/docs/r/route53_hosted_zone_dnssec.html.markdown index 17a6bc4eaf71..7e2d832b23ed 100644 --- a/website/docs/r/route53_hosted_zone_dnssec.html.markdown +++ b/website/docs/r/route53_hosted_zone_dnssec.html.markdown @@ -31,9 +31,24 @@ resource "aws_kms_key" "example" { ], Effect = "Allow" Principal = { - Service = "api-service.dnssec.route53.aws.internal" + Service = "dnssec-route53.amazonaws.com" + } + Sid = "Allow Route 53 DNSSEC Service", + Resource = "*" + }, + { + Action = "kms:CreateGrant", + Effect = "Allow" + Principal = { + Service = "dnssec-route53.amazonaws.com" + } + Sid = "Allow Route 53 DNSSEC Service to CreateGrant", + Resource = "*" + Condition = { + Bool = { + "kms:GrantIsForAWSResource" = "true" + } } - Sid = "Route 53 DNSSEC Permissions" }, { Action = "kms:*" @@ -54,12 +69,15 @@ resource "aws_route53_zone" "example" { } resource "aws_route53_key_signing_key" "example" { - hosted_zone_id = aws_route53_zone.test.id - key_management_service_arn = aws_kms_key.test.arn + hosted_zone_id = aws_route53_zone.example.id + key_management_service_arn = aws_kms_key.example.arn name = "example" } resource "aws_route53_hosted_zone_dnssec" "example" { + depends_on = [ + aws_route53_key_signing_key.example + ] hosted_zone_id = aws_route53_key_signing_key.example.hosted_zone_id } ``` diff --git a/website/docs/r/route53_key_signing_key.html.markdown b/website/docs/r/route53_key_signing_key.html.markdown index 2f16effa4922..770dcf44e3e0 100644 --- a/website/docs/r/route53_key_signing_key.html.markdown +++ b/website/docs/r/route53_key_signing_key.html.markdown @@ -31,9 +31,24 @@ resource "aws_kms_key" "example" { ], Effect = "Allow" Principal = { - Service = "api-service.dnssec.route53.aws.internal" + Service = "dnssec-route53.amazonaws.com" + } + Sid = "Allow Route 53 DNSSEC Service", + Resource = "*" + }, + { + Action = "kms:CreateGrant", + Effect = "Allow" + Principal = { + Service = "dnssec-route53.amazonaws.com" + } + Sid = "Allow Route 53 DNSSEC Service to CreateGrant", + Resource = "*" + Condition = { + Bool = { + "kms:GrantIsForAWSResource" = "true" + } } - Sid = "Route 53 DNSSEC Permissions" }, { Action = "kms:*" @@ -60,6 +75,9 @@ resource "aws_route53_key_signing_key" "example" { } resource "aws_route53_hosted_zone_dnssec" "example" { + depends_on = [ + aws_route53_key_signing_key.example + ] hosted_zone_id = aws_route53_key_signing_key.example.hosted_zone_id } ``` From f685bcd0c0d4b0778c051e7039090bb5bf10c691 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 18 Jun 2021 12:26:20 -0400 Subject: [PATCH 0621/1208] Add unit tests. --- aws/internal/tfresource/errors.go | 1 + aws/internal/tfresource/errors_test.go | 72 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/aws/internal/tfresource/errors.go b/aws/internal/tfresource/errors.go index 703eb55aa7d1..032ea8f42e97 100644 --- a/aws/internal/tfresource/errors.go +++ b/aws/internal/tfresource/errors.go @@ -25,6 +25,7 @@ func TimedOut(err error) bool { } // SetLastError sets the LastError field on the error if supported. +// If lastErr is nil it is ignored. func SetLastError(err, lastErr error) { var te *resource.TimeoutError var use *resource.UnexpectedStateError diff --git a/aws/internal/tfresource/errors_test.go b/aws/internal/tfresource/errors_test.go index da75f2cec9e2..36883294882a 100644 --- a/aws/internal/tfresource/errors_test.go +++ b/aws/internal/tfresource/errors_test.go @@ -3,6 +3,7 @@ package tfresource_test import ( "errors" "fmt" + "strings" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -97,3 +98,74 @@ func TestTimedOut(t *testing.T) { }) } } + +func TestSetLastError(t *testing.T) { + testCases := []struct { + Name string + Err error + LastErr error + Expected bool + }{ + { + Name: "nil error", + }, + { + Name: "other error", + Err: errors.New("test"), + LastErr: errors.New("last"), + }, + { + Name: "timeout error lastErr is nil", + Err: &resource.TimeoutError{}, + }, + { + Name: "timeout error", + Err: &resource.TimeoutError{}, + LastErr: errors.New("lasttest"), + Expected: true, + }, + { + Name: "timeout error non-nil last error lastErr is nil", + Err: &resource.TimeoutError{LastError: errors.New("test")}, + }, + { + Name: "timeout error non-nil last error no overwrite", + Err: &resource.TimeoutError{LastError: errors.New("test")}, + LastErr: errors.New("lasttest"), + }, + { + Name: "unexpected state error lastErr is nil", + Err: &resource.UnexpectedStateError{}, + }, + { + Name: "unexpected state error", + Err: &resource.UnexpectedStateError{}, + LastErr: errors.New("lasttest"), + Expected: true, + }, + { + Name: "unexpected state error non-nil last error lastErr is nil", + Err: &resource.UnexpectedStateError{LastError: errors.New("test")}, + }, + { + Name: "unexpected state error non-nil last error no overwrite", + Err: &resource.UnexpectedStateError{LastError: errors.New("test")}, + LastErr: errors.New("lasttest"), + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + tfresource.SetLastError(testCase.Err, testCase.LastErr) + + if testCase.Err != nil { + got := testCase.Err.Error() + contains := strings.Contains(got, "lasttest") + + if (testCase.Expected && !contains) || (!testCase.Expected && contains) { + t.Errorf("got %s", got) + } + } + }) + } +} From 2040dd2d2152c7f157840b2cd986e21b151c763f Mon Sep 17 00:00:00 2001 From: Simon Davis Date: Fri, 18 Jun 2021 10:12:34 -0700 Subject: [PATCH 0622/1208] fix bullet formatting for config/items (#19833) --- .../docs/r/cloudfront_cache_policy.html.markdown | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/website/docs/r/cloudfront_cache_policy.html.markdown b/website/docs/r/cloudfront_cache_policy.html.markdown index 4fe89393a1f5..5f8de3c97449 100644 --- a/website/docs/r/cloudfront_cache_policy.html.markdown +++ b/website/docs/r/cloudfront_cache_policy.html.markdown @@ -68,22 +68,22 @@ The following arguments are supported: ### Cookies Config -`cookie_behavior` - (Required) Determines whether any cookies in viewer requests are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `allExcept`, `all`. -`cookies` - (Optional) Object that contains a list of cookie names. See [Items](#items) for more information. +* `cookie_behavior` - (Required) Determines whether any cookies in viewer requests are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `allExcept`, `all`. +* `cookies` - (Optional) Object that contains a list of cookie names. See [Items](#items) for more information. ### Headers Config -`header_behavior` - (Required) Determines whether any HTTP headers are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`. -`headers` - (Optional) Object that contains a list of header names. See [Items](#items) for more information. +* `header_behavior` - (Required) Determines whether any HTTP headers are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`. +* `headers` - (Optional) Object that contains a list of header names. See [Items](#items) for more information. ### Query String Config -`query_string_behavior` - (Required) Determines whether any URL query strings in viewer requests are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `allExcept`, `all`. -`query_strings` - (Optional) Object that contains a list of query string names. See [Items](#items) for more information. +* `query_string_behavior` - (Required) Determines whether any URL query strings in viewer requests are included in the cache key and automatically included in requests that CloudFront sends to the origin. Valid values are `none`, `whitelist`, `allExcept`, `all`. +* `query_strings` - (Optional) Object that contains a list of query string names. See [Items](#items) for more information. ### Items -`items` - (Required) A list of item names (cookies, headers, or query strings). +* `items` - (Required) A list of item names (cookies, headers, or query strings). ## Attributes Reference From 46eea7a6e7e3c268fca9fc22e7cd2b007c27748f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 18 Jun 2021 13:58:20 -0400 Subject: [PATCH 0623/1208] Tweak use of 'tfresource.SetLastError'. --- aws/internal/service/amplify/waiter/waiter.go | 2 +- aws/internal/service/ec2/waiter/waiter.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/internal/service/amplify/waiter/waiter.go b/aws/internal/service/amplify/waiter/waiter.go index 08abc2675acb..02105061a37d 100644 --- a/aws/internal/service/amplify/waiter/waiter.go +++ b/aws/internal/service/amplify/waiter/waiter.go @@ -26,7 +26,7 @@ func DomainAssociationCreated(conn *amplify.Amplify, appID, domainName string) ( outputRaw, err := stateConf.WaitForState() if v, ok := outputRaw.(*amplify.DomainAssociation); ok { - if v != nil && aws.StringValue(v.DomainStatus) == amplify.DomainStatusFailed { + if status := aws.StringValue(v.DomainStatus); status == amplify.DomainStatusFailed { tfresource.SetLastError(err, errors.New(aws.StringValue(v.StatusReason))) } diff --git a/aws/internal/service/ec2/waiter/waiter.go b/aws/internal/service/ec2/waiter/waiter.go index 73ff47bfbd78..1daf05b25f9b 100644 --- a/aws/internal/service/ec2/waiter/waiter.go +++ b/aws/internal/service/ec2/waiter/waiter.go @@ -358,7 +358,7 @@ func RouteTableAssociationCreated(conn *ec2.EC2, id string) (*ec2.RouteTableAsso outputRaw, err := stateConf.WaitForState() if output, ok := outputRaw.(*ec2.RouteTableAssociationState); ok { - if output != nil && aws.StringValue(output.State) == ec2.RouteTableAssociationStateCodeFailed { + if state := aws.StringValue(output.State); state == ec2.RouteTableAssociationStateCodeFailed { tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusMessage))) } @@ -379,7 +379,7 @@ func RouteTableAssociationDeleted(conn *ec2.EC2, id string) (*ec2.RouteTableAsso outputRaw, err := stateConf.WaitForState() if output, ok := outputRaw.(*ec2.RouteTableAssociationState); ok { - if output != nil && aws.StringValue(output.State) == ec2.RouteTableAssociationStateCodeFailed { + if state := aws.StringValue(output.State); state == ec2.RouteTableAssociationStateCodeFailed { tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusMessage))) } @@ -400,7 +400,7 @@ func RouteTableAssociationUpdated(conn *ec2.EC2, id string) (*ec2.RouteTableAsso outputRaw, err := stateConf.WaitForState() if output, ok := outputRaw.(*ec2.RouteTableAssociationState); ok { - if output != nil && aws.StringValue(output.State) == ec2.RouteTableAssociationStateCodeFailed { + if state := aws.StringValue(output.State); state == ec2.RouteTableAssociationStateCodeFailed { tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusMessage))) } @@ -704,8 +704,8 @@ func VpcEndpointAccepted(conn *ec2.EC2, vpcEndpointID string, timeout time.Durat outputRaw, err := stateConf.WaitForState() if output, ok := outputRaw.(*ec2.VpcEndpoint); ok { - if output != nil && aws.StringValue(output.State) == tfec2.VpcEndpointStateFailed && output.LastError != nil { - tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.StringValue(output.LastError.Code), aws.StringValue(output.LastError.Message))) + if state, lastError := aws.StringValue(output.State), output.LastError; state == tfec2.VpcEndpointStateFailed && lastError != nil { + tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.StringValue(lastError.Code), aws.StringValue(lastError.Message))) } return output, err From 716e26755f8c4c3f8b249ec9985dc0bfad0e566f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 18 Jun 2021 13:59:23 -0400 Subject: [PATCH 0624/1208] Add and use waiters in 'internal/service/eks'. --- aws/internal/service/eks/waiter/status.go | 2 +- aws/internal/service/eks/waiter/waiter.go | 45 ++++ aws/resource_aws_eks_addon_test.go | 25 +- aws/resource_aws_eks_cluster.go | 285 +++++++--------------- 4 files changed, 131 insertions(+), 226 deletions(-) diff --git a/aws/internal/service/eks/waiter/status.go b/aws/internal/service/eks/waiter/status.go index 97b22250a2fa..a2e730460490 100644 --- a/aws/internal/service/eks/waiter/status.go +++ b/aws/internal/service/eks/waiter/status.go @@ -28,7 +28,7 @@ func ClusterStatus(conn *eks.EKS, name string) resource.StateRefreshFunc { } } -func UodateStatus(conn *eks.EKS, name, id string) resource.StateRefreshFunc { +func UpdateStatus(conn *eks.EKS, name, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { output, err := finder.UpdateByNameAndID(conn, name, id) diff --git a/aws/internal/service/eks/waiter/waiter.go b/aws/internal/service/eks/waiter/waiter.go index 41d1446328fc..c05ef448c64b 100644 --- a/aws/internal/service/eks/waiter/waiter.go +++ b/aws/internal/service/eks/waiter/waiter.go @@ -9,7 +9,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" "github.com/hashicorp/aws-sdk-go-base/tfawserr" + multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -18,6 +20,23 @@ const ( EksAddonDeletedTimeout = 40 * time.Minute ) +func ClusterCreated(conn *eks.EKS, name string, timeout time.Duration) (*eks.Cluster, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{eks.ClusterStatusCreating}, + Target: []string{eks.ClusterStatusActive}, + Refresh: ClusterStatus(conn, name), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*eks.Cluster); ok { + return output, err + } + + return nil, err +} + func ClusterDeleted(conn *eks.EKS, name string, timeout time.Duration) (*eks.Cluster, error) { stateConf := &resource.StateChangeConf{ Pending: []string{eks.ClusterStatusActive, eks.ClusterStatusDeleting}, @@ -35,6 +54,32 @@ func ClusterDeleted(conn *eks.EKS, name string, timeout time.Duration) (*eks.Clu return nil, err } +func UpdateSuccessful(conn *eks.EKS, name, id string, timeout time.Duration) (*eks.Update, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{eks.UpdateStatusInProgress}, + Target: []string{eks.UpdateStatusSuccessful}, + Refresh: UpdateStatus(conn, name, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*eks.Update); ok { + if status := aws.StringValue(output.Status); status == eks.UpdateStatusCancelled || status == eks.UpdateStatusFailed { + var errs *multierror.Error + + for _, e := range output.Errors { + errs = multierror.Append(errs, fmt.Errorf("%s: %s", aws.StringValue(e.ErrorCode), aws.StringValue(e.ErrorMessage))) + } + tfresource.SetLastError(err, errs.ErrorOrNil()) + } + + return output, err + } + + return nil, err +} + // EksAddonCreated waits for a EKS add-on to return status "ACTIVE" or "CREATE_FAILED" func EksAddonCreated(ctx context.Context, conn *eks.EKS, clusterName, addonName string) (*eks.Addon, error) { stateConf := resource.StateChangeConf{ diff --git a/aws/resource_aws_eks_addon_test.go b/aws/resource_aws_eks_addon_test.go index ce403ac430b9..f79c68c52c7a 100644 --- a/aws/resource_aws_eks_addon_test.go +++ b/aws/resource_aws_eks_addon_test.go @@ -147,6 +147,7 @@ func TestAccAWSEksAddon_disappears_Cluster(t *testing.T) { var addon eks.Addon rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_addon.test" + clusterResourceName := "aws_eks_cluster" addonName := "vpc-cni" ctx := context.TODO() @@ -160,7 +161,7 @@ func TestAccAWSEksAddon_disappears_Cluster(t *testing.T) { Config: testAccAWSEksAddon_Basic(rName, addonName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksAddonExists(ctx, resourceName, &addon), - testAccCheckAWSEksClusterDisappears(ctx, &addon), + testAccCheckResourceDisappears(testAccProvider, resourceAwsEksCluster(), clusterResourceName), ), ExpectNonEmptyPlan: true, }, @@ -796,28 +797,6 @@ func testAccCheckAWSEksAddonDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSEksClusterDisappears(ctx context.Context, addon *eks.Addon) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).eksconn - - input := &eks.DeleteClusterInput{ - Name: addon.ClusterName, - } - - _, err := conn.DeleteClusterWithContext(ctx, input) - - if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { - return nil - } - - if err != nil { - return err - } - - return waitForDeleteEksCluster(conn, aws.StringValue(addon.ClusterName), 30*time.Minute) - } -} - func testAccPreCheckAWSEksAddon(t *testing.T) { conn := testAccProvider.Meta().(*AWSClient).eksconn diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index 620b754e09e1..1d1251abb924 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "regexp" - "strings" "time" "github.com/aws/aws-sdk-go/aws" @@ -16,6 +15,7 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/waiter" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -67,6 +67,9 @@ func resourceAwsEksCluster() *schema.Resource { ValidateFunc: validation.StringInSlice(eks.LogType_Values(), true), }, }, + // TODO + // TODO You cannot disable envelope encryption after enabling it. This action is irreversible. + // TODO "encryption_config": { Type: schema.TypeList, MaxItems: 1, @@ -231,14 +234,10 @@ func resourceAwsEksClusterCreate(d *schema.ResourceData, meta interface{}) error input := &eks.CreateClusterInput{ EncryptionConfig: expandEksEncryptionConfig(d.Get("encryption_config").([]interface{})), + Logging: expandEksLoggingTypes(d.Get("enabled_cluster_log_types").(*schema.Set)), Name: aws.String(name), - RoleArn: aws.String(d.Get("role_arn").(string)), ResourcesVpcConfig: expandEksVpcConfigRequest(d.Get("vpc_config").([]interface{})), - Logging: expandEksLoggingTypes(d.Get("enabled_cluster_log_types").(*schema.Set)), - } - - if len(tags) > 0 { - input.Tags = tags.IgnoreAws().EksTags() + RoleArn: aws.String(d.Get("role_arn").(string)), } if _, ok := d.GetOk("kubernetes_network_config"); ok { @@ -249,51 +248,62 @@ func resourceAwsEksClusterCreate(d *schema.ResourceData, meta interface{}) error input.Version = aws.String(v.(string)) } + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().EksTags() + } + log.Printf("[DEBUG] Creating EKS Cluster: %s", input) + var output *eks.CreateClusterOutput err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { - _, err := conn.CreateCluster(input) + var err error + + output, err = conn.CreateCluster(input) + + // InvalidParameterException: roleArn, arn:aws:iam::123456789012:role/XXX, does not exist + if isAWSErr(err, eks.ErrCodeInvalidParameterException, "does not exist") { + return resource.RetryableError(err) + } + + // InvalidParameterException: Error in role params + if isAWSErr(err, eks.ErrCodeInvalidParameterException, "Error in role params") { + return resource.RetryableError(err) + } + + if isAWSErr(err, eks.ErrCodeInvalidParameterException, "Role could not be assumed because the trusted entity is not correct") { + return resource.RetryableError(err) + } + + // InvalidParameterException: The provided role doesn't have the Amazon EKS Managed Policies associated with it. Please ensure the following policy is attached: arn:aws:iam::aws:policy/AmazonEKSClusterPolicy + if isAWSErr(err, eks.ErrCodeInvalidParameterException, "The provided role doesn't have the Amazon EKS Managed Policies associated with it") { + return resource.RetryableError(err) + } + + // InvalidParameterException: IAM role's policy must include the `ec2:DescribeSubnets` action + if isAWSErr(err, eks.ErrCodeInvalidParameterException, "IAM role's policy must include") { + return resource.RetryableError(err) + } + if err != nil { - // InvalidParameterException: roleArn, arn:aws:iam::123456789012:role/XXX, does not exist - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "does not exist") { - return resource.RetryableError(err) - } - // InvalidParameterException: Error in role params - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "Error in role params") { - return resource.RetryableError(err) - } - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "Role could not be assumed because the trusted entity is not correct") { - return resource.RetryableError(err) - } - // InvalidParameterException: The provided role doesn't have the Amazon EKS Managed Policies associated with it. Please ensure the following policy is attached: arn:aws:iam::aws:policy/AmazonEKSClusterPolicy - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "The provided role doesn't have the Amazon EKS Managed Policies associated with it") { - return resource.RetryableError(err) - } - // InvalidParameterException: IAM role's policy must include the `ec2:DescribeSubnets` action - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "IAM role's policy must include") { - return resource.RetryableError(err) - } return resource.NonRetryableError(err) } + return nil }) - if isResourceTimeoutError(err) { - _, err = conn.CreateCluster(input) + + if tfresource.TimedOut(err) { + output, err = conn.CreateCluster(input) } + if err != nil { - return fmt.Errorf("error creating EKS Cluster (%s): %s", name, err) + return fmt.Errorf("error creating EKS Cluster (%s): %w", name, err) } - d.SetId(name) + d.SetId(aws.StringValue(output.Cluster.Name)) + + _, err = waiter.ClusterCreated(conn, d.Id(), d.Timeout(schema.TimeoutCreate)) - stateConf := resource.StateChangeConf{ - Pending: []string{eks.ClusterStatusCreating}, - Target: []string{eks.ClusterStatusActive}, - Timeout: d.Timeout(schema.TimeoutCreate), - Refresh: refreshEksClusterStatus(conn, name), - } - _, err = stateConf.WaitForState() if err != nil { - return err + return fmt.Errorf("error waiting for EKS Cluster (%s) to create: %w", d.Id(), err) } return resourceAwsEksClusterRead(d, meta) @@ -369,79 +379,70 @@ func resourceAwsEksClusterRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsEksClusterUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).eksconn - if d.HasChange("encryption_config") { - input := &eks.AssociateEncryptionConfigInput{ - ClusterName: aws.String(d.Id()), - EncryptionConfig: expandEksEncryptionConfig(d.Get("encryption_config").([]interface{})), + // Do any version update first. + if d.HasChange("version") { + input := &eks.UpdateClusterVersionInput{ + Name: aws.String(d.Id()), + Version: aws.String(d.Get("version").(string)), } log.Printf("[DEBUG] Updating EKS Cluster (%s) version: %s", d.Id(), input) - output, err := conn.AssociateEncryptionConfig(input) + output, err := conn.UpdateClusterVersion(input) if err != nil { - return fmt.Errorf("error updating EKS Cluster (%s) version: %s", d.Id(), err) - } - - if output == nil || output.Update == nil || output.Update.Id == nil { - return fmt.Errorf("error determining EKS Cluster (%s) version update ID: empty response", d.Id()) + return fmt.Errorf("error updating EKS Cluster (%s) version: %w", d.Id(), err) } updateID := aws.StringValue(output.Update.Id) - err = waitForUpdateEksCluster(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + _, err = waiter.UpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { - return fmt.Errorf("error waiting for EKS Cluster (%s) version update (%s): %s", d.Id(), updateID, err) + return fmt.Errorf("error waiting for EKS Cluster (%s) version update (%s): %w", d.Id(), updateID, err) } } - if d.HasChange("version") { - input := &eks.UpdateClusterVersionInput{ - Name: aws.String(d.Id()), - Version: aws.String(d.Get("version").(string)), + if d.HasChange("encryption_config") { + input := &eks.AssociateEncryptionConfigInput{ + ClusterName: aws.String(d.Id()), + EncryptionConfig: expandEksEncryptionConfig(d.Get("encryption_config").([]interface{})), } - log.Printf("[DEBUG] Updating EKS Cluster (%s) version: %s", d.Id(), input) - output, err := conn.UpdateClusterVersion(input) + log.Printf("[DEBUG] Associating EKS Cluster (%s) encryption config: %s", d.Id(), input) + output, err := conn.AssociateEncryptionConfig(input) if err != nil { - return fmt.Errorf("error updating EKS Cluster (%s) version: %s", d.Id(), err) - } - - if output == nil || output.Update == nil || output.Update.Id == nil { - return fmt.Errorf("error determining EKS Cluster (%s) version update ID: empty response", d.Id()) + return fmt.Errorf("error associating EKS Cluster (%s) encryption config: %w", d.Id(), err) } updateID := aws.StringValue(output.Update.Id) - err = waitForUpdateEksCluster(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + _, err = waiter.UpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { - return fmt.Errorf("error waiting for EKS Cluster (%s) version update (%s): %s", d.Id(), updateID, err) + return fmt.Errorf("error waiting for EKS Cluster (%s) encryption config association (%s): %w", d.Id(), updateID, err) } } if d.HasChange("enabled_cluster_log_types") { - _, v := d.GetChange("enabled_cluster_log_types") input := &eks.UpdateClusterConfigInput{ + Logging: expandEksLoggingTypes(d.Get("enabled_cluster_log_types").(*schema.Set)), Name: aws.String(d.Id()), - Logging: expandEksLoggingTypes(v.(*schema.Set)), } log.Printf("[DEBUG] Updating EKS Cluster (%s) logging: %s", d.Id(), input) output, err := conn.UpdateClusterConfig(input) if err != nil { - return fmt.Errorf("error updating EKS Cluster (%s) logging: %s", d.Id(), err) - } - - if output == nil || output.Update == nil || output.Update.Id == nil { - return fmt.Errorf("error determining EKS Cluster (%s) logging update ID: empty response", d.Id()) + return fmt.Errorf("error updating EKS Cluster (%s) logging: %w", d.Id(), err) } updateID := aws.StringValue(output.Update.Id) - err = waitForUpdateEksCluster(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + _, err = waiter.UpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { - return fmt.Errorf("error waiting for EKS Cluster (%s) logging update (%s): %s", d.Id(), updateID, err) + return fmt.Errorf("error waiting for EKS Cluster (%s) logging update (%s): %w", d.Id(), updateID, err) } } @@ -451,22 +452,19 @@ func resourceAwsEksClusterUpdate(d *schema.ResourceData, meta interface{}) error ResourcesVpcConfig: expandEksVpcConfigUpdateRequest(d.Get("vpc_config").([]interface{})), } - log.Printf("[DEBUG] Updating EKS Cluster (%s) config: %s", d.Id(), input) + log.Printf("[DEBUG] Updating EKS Cluster (%s) VPC config: %s", d.Id(), input) output, err := conn.UpdateClusterConfig(input) if err != nil { - return fmt.Errorf("error updating EKS Cluster (%s) config: %s", d.Id(), err) - } - - if output == nil || output.Update == nil || output.Update.Id == nil { - return fmt.Errorf("error determining EKS Cluster (%s) config update ID: empty response", d.Id()) + return fmt.Errorf("error updating EKS Cluster (%s) VPC config: %w", d.Id(), err) } updateID := aws.StringValue(output.Update.Id) - err = waitForUpdateEksCluster(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + _, err = waiter.UpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { - return fmt.Errorf("error waiting for EKS Cluster (%s) config update (%s): %s", d.Id(), updateID, err) + return fmt.Errorf("error waiting for EKS Cluster (%s) VPC config update (%s): %w", d.Id(), updateID, err) } } @@ -499,12 +497,13 @@ func resourceAwsEksClusterDelete(d *schema.ResourceData, meta interface{}) error } if err != nil { - return fmt.Errorf("error deleting EKS Cluster (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting EKS Cluster (%s): %w", d.Id(), err) } - err = waitForDeleteEksCluster(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) + _, err = waiter.ClusterDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) + if err != nil { - return fmt.Errorf("error waiting for EKS Cluster (%s) deletion: %s", d.Id(), err) + return fmt.Errorf("error waiting for EKS Cluster (%s) delete: %w", d.Id(), err) } return nil @@ -744,121 +743,3 @@ func flattenEksNetworkConfig(apiObject *eks.KubernetesNetworkConfigResponse) []i return []interface{}{tfMap} } - -func refreshEksClusterStatus(conn *eks.EKS, clusterName string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - output, err := conn.DescribeCluster(&eks.DescribeClusterInput{ - Name: aws.String(clusterName), - }) - if err != nil { - return 42, "", err - } - cluster := output.Cluster - if cluster == nil { - return cluster, "", fmt.Errorf("EKS Cluster (%s) missing", clusterName) - } - return cluster, aws.StringValue(cluster.Status), nil - } -} - -func refreshEksUpdateStatus(conn *eks.EKS, clusterName, updateID string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - input := &eks.DescribeUpdateInput{ - Name: aws.String(clusterName), - UpdateId: aws.String(updateID), - } - - output, err := conn.DescribeUpdate(input) - - if err != nil { - return nil, "", err - } - - if output == nil || output.Update == nil { - return nil, "", fmt.Errorf("EKS Cluster (%s) update (%s) missing", clusterName, updateID) - } - - return output.Update, aws.StringValue(output.Update.Status), nil - } -} - -func waitForDeleteEksCluster(conn *eks.EKS, clusterName string, timeout time.Duration) error { - /* - TODO - - // Handle eventual consistency - err := resource.Retry(1*time.Minute, func() *resource.RetryError { - output, err := conn.DescribeCluster(&eks.DescribeClusterInput{ - Name: aws.String(rs.Primary.ID), - }) - - if err != nil { - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - return nil - } - return resource.NonRetryableError(err) - } - - if output != nil && output.Cluster != nil && aws.StringValue(output.Cluster.Name) == rs.Primary.ID { - return resource.RetryableError(fmt.Errorf("EKS Cluster %s still exists", rs.Primary.ID)) - } - - return nil - }) - */ - stateConf := resource.StateChangeConf{ - Pending: []string{ - eks.ClusterStatusActive, - eks.ClusterStatusDeleting, - }, - Target: []string{""}, - Timeout: timeout, - Refresh: refreshEksClusterStatus(conn, clusterName), - } - cluster, err := stateConf.WaitForState() - if err != nil { - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - return nil - } - // Sometimes the EKS API returns the ResourceNotFound error in this form: - // ClientException: No cluster found for name: tf-acc-test-0o1f8 - if isAWSErr(err, eks.ErrCodeClientException, "No cluster found for name:") { - return nil - } - } - if cluster == nil { - return nil - } - return err -} - -func waitForUpdateEksCluster(conn *eks.EKS, clusterName, updateID string, timeout time.Duration) error { - stateConf := resource.StateChangeConf{ - Pending: []string{eks.UpdateStatusInProgress}, - Target: []string{ - eks.UpdateStatusCancelled, - eks.UpdateStatusFailed, - eks.UpdateStatusSuccessful, - }, - Timeout: timeout, - Refresh: refreshEksUpdateStatus(conn, clusterName, updateID), - } - updateRaw, err := stateConf.WaitForState() - - if err != nil { - return err - } - - update := updateRaw.(*eks.Update) - - if aws.StringValue(update.Status) == eks.UpdateStatusSuccessful { - return nil - } - - var detailedErrors []string - for i, updateError := range update.Errors { - detailedErrors = append(detailedErrors, fmt.Sprintf("Error %d: Code: %s / Message: %s", i+1, aws.StringValue(updateError.ErrorCode), aws.StringValue(updateError.ErrorMessage))) - } - - return fmt.Errorf("EKS Cluster (%s) update (%s) status (%s) not successful: Errors:\n%s", clusterName, updateID, aws.StringValue(update.Status), strings.Join(detailedErrors, "\n")) -} From f2be7d732f6d7768c9464e0b5aaa321f28fc0141 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Fri, 18 Jun 2021 14:01:50 -0400 Subject: [PATCH 0625/1208] use resource ID as input to delete operation; ignore automated backups that can't be removed --- aws/resource_aws_backup_vault.go | 2 +- aws/resource_aws_backup_vault_test.go | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_backup_vault.go b/aws/resource_aws_backup_vault.go index 381ff2df3ee4..2b15de218ad1 100644 --- a/aws/resource_aws_backup_vault.go +++ b/aws/resource_aws_backup_vault.go @@ -140,7 +140,7 @@ func resourceAwsBackupVaultDelete(d *schema.ResourceData, meta interface{}) erro conn := meta.(*AWSClient).backupconn input := &backup.DeleteBackupVaultInput{ - BackupVaultName: aws.String(d.Get("name").(string)), + BackupVaultName: aws.String(d.Id()), } _, err := conn.DeleteBackupVault(input) diff --git a/aws/resource_aws_backup_vault_test.go b/aws/resource_aws_backup_vault_test.go index 7bc61b810433..fa9e1f2726ca 100644 --- a/aws/resource_aws_backup_vault_test.go +++ b/aws/resource_aws_backup_vault_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "strings" "testing" "github.com/aws/aws-sdk-go/aws" @@ -47,22 +48,25 @@ func testSweepBackupVaults(region string) error { continue } + name := aws.StringValue(vault.BackupVaultName) + // Ignore Default Backup Vault in region (cannot be deleted) - if aws.StringValue(vault.BackupVaultName) == "Default" { - log.Printf("[INFO] Skipping Backup Vault: Default") + // and automated Backups that result in AccessDeniedException when deleted + if name == "Default" || strings.Contains(name, "automatic-backup-vault") { + log.Printf("[INFO] Skipping Backup Vault: %s", name) continue } // Backup Vault deletion only supported when empty // Reference: https://docs.aws.amazon.com/aws-backup/latest/devguide/API_DeleteBackupVault.html if aws.Int64Value(vault.NumberOfRecoveryPoints) != 0 { - log.Printf("[INFO] Skipping Backup Vault (%s): not empty", aws.StringValue(vault.BackupVaultName)) + log.Printf("[INFO] Skipping Backup Vault (%s): not empty", name) continue } r := resourceAwsBackupVault() d := r.Data(nil) - d.SetId(aws.StringValue(vault.BackupVaultName)) + d.SetId(name) sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } @@ -74,7 +78,7 @@ func testSweepBackupVaults(region string) error { errs = multierror.Append(errs, fmt.Errorf("error listing Backup Vaults for %s: %w", region, err)) } - if err = testSweepResourceOrchestrator(sweepResources); err != nil { + if err := testSweepResourceOrchestrator(sweepResources); err != nil { errs = multierror.Append(errs, fmt.Errorf("error sweeping Backup Vaults for %s: %w", region, err)) } From 80ee3b835673d08a77551a43312eb9eb7ba44575 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Jun 2021 11:13:47 -0700 Subject: [PATCH 0626/1208] Uses resource Delete operation for API Gateway VPC Link sweeper and adds concurrency --- aws/resource_aws_api_gateway_vpc_link_test.go | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/aws/resource_aws_api_gateway_vpc_link_test.go b/aws/resource_aws_api_gateway_vpc_link_test.go index 253cf6395294..27254afbbda3 100644 --- a/aws/resource_aws_api_gateway_vpc_link_test.go +++ b/aws/resource_aws_api_gateway_vpc_link_test.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/apigateway" + multierror "github.com/hashicorp/go-multierror" "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" @@ -23,40 +24,39 @@ func init() { func testSweepAPIGatewayVpcLinks(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } conn := client.(*AWSClient).apigatewayconn + sweepResources := make([]*testSweepResource, 0) + var sweeperErrs *multierror.Error + err = conn.GetVpcLinksPages(&apigateway.GetVpcLinksInput{}, func(page *apigateway.GetVpcLinksOutput, lastPage bool) bool { for _, item := range page.Items { - input := &apigateway.DeleteVpcLinkInput{ - VpcLinkId: item.Id, - } id := aws.StringValue(item.Id) - log.Printf("[INFO] Deleting API Gateway VPC Link: %s", id) - _, err := conn.DeleteVpcLink(input) + log.Printf("[INFO] Deleting API Gateway VPC Link (%s)", id) + r := resourceAwsApiGatewayVpcLink() + d := r.Data(nil) + d.SetId(id) - if err != nil { - log.Printf("[ERROR] Failed to delete API Gateway VPC Link %s: %s", id, err) - continue - } - - if err := waitForApiGatewayVpcLinkDeletion(conn, id); err != nil { - log.Printf("[ERROR] Error waiting for API Gateway VPC Link (%s) deletion: %s", id, err) - } + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } return !lastPage }) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping API Gateway VPC Link sweep for %s: %s", region, err) + return nil + } if err != nil { - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping API Gateway VPC Link sweep for %s: %s", region, err) - return nil - } - return fmt.Errorf("Error retrieving API Gateway VPC Links: %s", err) + return fmt.Errorf("error retrieving API Gateway VPC Links: %w", err) } - return nil + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping App Runner AutoScaling Configuration Version for %s: %w", region, err)) + } + + return sweeperErrs.ErrorOrNil() } func TestAccAWSAPIGatewayVpcLink_basic(t *testing.T) { From 4d4335d305d3e53e4d9cbcab5f8546443a79f2f3 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Jun 2021 11:15:30 -0700 Subject: [PATCH 0627/1208] Moves API Gateway VPC Link deletion waiter to `waiter` package --- .../service/apigateway/waiter/status.go | 31 +++++++++++++++ .../service/apigateway/waiter/waiter.go | 29 ++++++++++++++ aws/resource_aws_api_gateway_vpc_link.go | 39 ++----------------- 3 files changed, 64 insertions(+), 35 deletions(-) create mode 100644 aws/internal/service/apigateway/waiter/status.go create mode 100644 aws/internal/service/apigateway/waiter/waiter.go diff --git a/aws/internal/service/apigateway/waiter/status.go b/aws/internal/service/apigateway/waiter/status.go new file mode 100644 index 000000000000..864915761a10 --- /dev/null +++ b/aws/internal/service/apigateway/waiter/status.go @@ -0,0 +1,31 @@ +package waiter + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/apigateway" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func apiGatewayVpcLinkStatus(conn *apigateway.APIGateway, vpcLinkId string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := conn.GetVpcLink(&apigateway.GetVpcLinkInput{ + VpcLinkId: aws.String(vpcLinkId), + }) + if tfawserr.ErrCodeEquals(err, apigateway.ErrCodeNotFoundException) { + return nil, "", nil + } + if err != nil { + return nil, "", err + } + + // Error messages can also be contained in the response with FAILED status + if aws.StringValue(output.Status) == apigateway.VpcLinkStatusFailed { + return output, apigateway.VpcLinkStatusFailed, fmt.Errorf("%s: %s", apigateway.VpcLinkStatusFailed, aws.StringValue(output.StatusMessage)) + } + + return output, aws.StringValue(output.Status), nil + } +} diff --git a/aws/internal/service/apigateway/waiter/waiter.go b/aws/internal/service/apigateway/waiter/waiter.go new file mode 100644 index 000000000000..0b837c166cad --- /dev/null +++ b/aws/internal/service/apigateway/waiter/waiter.go @@ -0,0 +1,29 @@ +package waiter + +import ( + "time" + + "github.com/aws/aws-sdk-go/service/apigateway" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + // Maximum amount of time for VpcLink to delete + ApiGatewayVpcLinkDeleteTimeout = 20 * time.Minute +) + +func ApiGatewayVpcLinkDeleted(conn *apigateway.APIGateway, vpcLinkId string) error { + stateConf := resource.StateChangeConf{ + Pending: []string{apigateway.VpcLinkStatusPending, + apigateway.VpcLinkStatusAvailable, + apigateway.VpcLinkStatusDeleting}, + Target: []string{""}, + Timeout: ApiGatewayVpcLinkDeleteTimeout, + MinTimeout: 1 * time.Second, + Refresh: apiGatewayVpcLinkStatus(conn, vpcLinkId), + } + + _, err := stateConf.WaitForState() + + return err +} diff --git a/aws/resource_aws_api_gateway_vpc_link.go b/aws/resource_aws_api_gateway_vpc_link.go index 4a58946e084a..ca167fcd1b99 100644 --- a/aws/resource_aws_api_gateway_vpc_link.go +++ b/aws/resource_aws_api_gateway_vpc_link.go @@ -11,13 +11,12 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apigateway/waiter" ) const ( // Maximum amount of time for VpcLink to become available apigatewayVpcLinkAvailableTimeout = 20 * time.Minute - // Maximum amount of time for VpcLink to delete - apigatewayVpcLinkDeleteTimeout = 20 * time.Minute ) func resourceAwsApiGatewayVpcLink() *schema.Resource { @@ -213,11 +212,11 @@ func resourceAwsApiGatewayVpcLinkDelete(d *schema.ResourceData, meta interface{} } if err != nil { - return fmt.Errorf("error deleting API Gateway VPC Link (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting API Gateway VPC Link (%s): %w", d.Id(), err) } - if err := waitForApiGatewayVpcLinkDeletion(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for API Gateway VPC Link (%s) deletion: %s", d.Id(), err) + if err := waiter.ApiGatewayVpcLinkDeleted(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for API Gateway VPC Link (%s) deletion: %w", d.Id(), err) } return nil @@ -235,33 +234,3 @@ func apigatewayVpcLinkRefreshStatusFunc(conn *apigateway.APIGateway, vl string) return resp, *resp.Status, nil } } - -func waitForApiGatewayVpcLinkDeletion(conn *apigateway.APIGateway, vpcLinkID string) error { - stateConf := resource.StateChangeConf{ - Pending: []string{apigateway.VpcLinkStatusPending, - apigateway.VpcLinkStatusAvailable, - apigateway.VpcLinkStatusDeleting}, - Target: []string{""}, - Timeout: apigatewayVpcLinkDeleteTimeout, - MinTimeout: 1 * time.Second, - Refresh: func() (interface{}, string, error) { - resp, err := conn.GetVpcLink(&apigateway.GetVpcLinkInput{ - VpcLinkId: aws.String(vpcLinkID), - }) - - if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") { - return 1, "", nil - } - - if err != nil { - return nil, apigateway.VpcLinkStatusFailed, err - } - - return resp, aws.StringValue(resp.Status), nil - }, - } - - _, err := stateConf.WaitForState() - - return err -} From eeabf4740c1985e311d51314c4696dae4b75236f Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Jun 2021 12:10:59 -0700 Subject: [PATCH 0628/1208] Fixes copy-paste error --- aws/resource_aws_api_gateway_vpc_link_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_api_gateway_vpc_link_test.go b/aws/resource_aws_api_gateway_vpc_link_test.go index 27254afbbda3..60d3f1918297 100644 --- a/aws/resource_aws_api_gateway_vpc_link_test.go +++ b/aws/resource_aws_api_gateway_vpc_link_test.go @@ -53,7 +53,7 @@ func testSweepAPIGatewayVpcLinks(region string) error { } if err := testSweepResourceOrchestrator(sweepResources); err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping App Runner AutoScaling Configuration Version for %s: %w", region, err)) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping API Gateway VPC Links")) } return sweeperErrs.ErrorOrNil() From c491ce7f03ea9f1a22c7edf653b839f99f9e00e4 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Jun 2021 12:13:01 -0700 Subject: [PATCH 0629/1208] Includes nested error --- aws/resource_aws_api_gateway_vpc_link_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_api_gateway_vpc_link_test.go b/aws/resource_aws_api_gateway_vpc_link_test.go index 60d3f1918297..db5377730588 100644 --- a/aws/resource_aws_api_gateway_vpc_link_test.go +++ b/aws/resource_aws_api_gateway_vpc_link_test.go @@ -53,7 +53,7 @@ func testSweepAPIGatewayVpcLinks(region string) error { } if err := testSweepResourceOrchestrator(sweepResources); err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping API Gateway VPC Links")) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping API Gateway VPC Links: %w", err)) } return sweeperErrs.ErrorOrNil() From 7723e0e52e1fcaa80fe1057372329c27ab32b622 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 18 Jun 2021 15:51:56 -0400 Subject: [PATCH 0630/1208] r/aws_eks_cluster: Add 'TestAccAWSEksCluster_EncryptionConfig_Update'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSEksCluster_EncryptionConfig_Update' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSEksCluster_EncryptionConfig_Update -timeout 180m === RUN TestAccAWSEksCluster_EncryptionConfig_Update === PAUSE TestAccAWSEksCluster_EncryptionConfig_Update === CONT TestAccAWSEksCluster_EncryptionConfig_Update --- PASS: TestAccAWSEksCluster_EncryptionConfig_Update (3710.17s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 3713.264s --- aws/resource_aws_eks_cluster_test.go | 107 +++++++++++++++++---------- 1 file changed, 69 insertions(+), 38 deletions(-) diff --git a/aws/resource_aws_eks_cluster_test.go b/aws/resource_aws_eks_cluster_test.go index d255f5e1a941..c78780531311 100644 --- a/aws/resource_aws_eks_cluster_test.go +++ b/aws/resource_aws_eks_cluster_test.go @@ -74,7 +74,7 @@ func testSweepEksClusters(region string) error { func TestAccAWSEksCluster_basic(t *testing.T) { var cluster eks.Cluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" resource.ParallelTest(t, resource.TestCase{ @@ -121,7 +121,7 @@ func TestAccAWSEksCluster_basic(t *testing.T) { func TestAccAWSEksCluster_disappears(t *testing.T) { var cluster eks.Cluster - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" resource.ParallelTest(t, resource.TestCase{ @@ -142,11 +142,42 @@ func TestAccAWSEksCluster_disappears(t *testing.T) { }) } -func TestAccAWSEksCluster_EncryptionConfig(t *testing.T) { +func TestAccAWSEksCluster_EncryptionConfig_Create(t *testing.T) { var cluster eks.Cluster - kmsKeyResourceName := "aws_kms_key.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" + kmsKeyResourceName := "aws_kms_key.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEksClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksClusterConfig_EncryptionConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "encryption_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "encryption_config.0.provider.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "encryption_config.0.provider.0.key_arn", kmsKeyResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "encryption_config.0.resources.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSEksCluster_EncryptionConfig_Update(t *testing.T) { + var cluster eks.Cluster rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_eks_cluster.test" + kmsKeyResourceName := "aws_kms_key.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, @@ -154,6 +185,13 @@ func TestAccAWSEksCluster_EncryptionConfig(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckAWSEksClusterDestroy, Steps: []resource.TestStep{ + { + Config: testAccAWSEksClusterConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksClusterExists(resourceName, &cluster), + resource.TestCheckResourceAttr(resourceName, "encryption_config.#", "0"), + ), + }, { Config: testAccAWSEksClusterConfig_EncryptionConfig(rName), Check: resource.ComposeTestCheckFunc( @@ -175,8 +213,7 @@ func TestAccAWSEksCluster_EncryptionConfig(t *testing.T) { func TestAccAWSEksCluster_Version(t *testing.T) { var cluster1, cluster2 eks.Cluster - - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" resource.ParallelTest(t, resource.TestCase{ @@ -211,8 +248,7 @@ func TestAccAWSEksCluster_Version(t *testing.T) { func TestAccAWSEksCluster_Logging(t *testing.T) { var cluster1, cluster2 eks.Cluster - - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" resource.ParallelTest(t, resource.TestCase{ @@ -304,8 +340,7 @@ func TestAccAWSEksCluster_Tags(t *testing.T) { func TestAccAWSEksCluster_VpcConfig_SecurityGroupIds(t *testing.T) { var cluster eks.Cluster - - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" resource.ParallelTest(t, resource.TestCase{ @@ -333,8 +368,7 @@ func TestAccAWSEksCluster_VpcConfig_SecurityGroupIds(t *testing.T) { func TestAccAWSEksCluster_VpcConfig_EndpointPrivateAccess(t *testing.T) { var cluster1, cluster2, cluster3 eks.Cluster - - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" resource.ParallelTest(t, resource.TestCase{ @@ -380,8 +414,7 @@ func TestAccAWSEksCluster_VpcConfig_EndpointPrivateAccess(t *testing.T) { func TestAccAWSEksCluster_VpcConfig_EndpointPublicAccess(t *testing.T) { var cluster1, cluster2, cluster3 eks.Cluster - - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" resource.ParallelTest(t, resource.TestCase{ @@ -426,9 +459,8 @@ func TestAccAWSEksCluster_VpcConfig_EndpointPublicAccess(t *testing.T) { } func TestAccAWSEksCluster_VpcConfig_PublicAccessCidrs(t *testing.T) { - var cluster1 eks.Cluster - - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + var cluster eks.Cluster + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" resource.ParallelTest(t, resource.TestCase{ @@ -440,7 +472,7 @@ func TestAccAWSEksCluster_VpcConfig_PublicAccessCidrs(t *testing.T) { { Config: testAccAWSEksClusterConfig_VpcConfig_PublicAccessCidrs(rName, `["1.2.3.4/32", "5.6.7.8/32"]`), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksClusterExists(resourceName, &cluster1), + testAccCheckAWSEksClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "vpc_config.0.public_access_cidrs.#", "2"), ), @@ -453,7 +485,7 @@ func TestAccAWSEksCluster_VpcConfig_PublicAccessCidrs(t *testing.T) { { Config: testAccAWSEksClusterConfig_VpcConfig_PublicAccessCidrs(rName, `["4.3.2.1/32", "8.7.6.5/32"]`), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksClusterExists(resourceName, &cluster1), + testAccCheckAWSEksClusterExists(resourceName, &cluster), resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "vpc_config.0.public_access_cidrs.#", "2"), ), @@ -464,8 +496,7 @@ func TestAccAWSEksCluster_VpcConfig_PublicAccessCidrs(t *testing.T) { func TestAccAWSEksCluster_NetworkConfig_ServiceIpv4Cidr(t *testing.T) { var cluster1, cluster2 eks.Cluster - - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" resource.ParallelTest(t, resource.TestCase{ @@ -651,7 +682,7 @@ resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" tags = { - Name = "terraform-testacc-eks-cluster-base" + Name = %[1]q "kubernetes.io/cluster/%[1]s" = "shared" } } @@ -664,7 +695,7 @@ resource "aws_subnet" "test" { vpc_id = aws_vpc.test.id tags = { - Name = "terraform-testacc-eks-cluster-base" + Name = %[1]q "kubernetes.io/cluster/%[1]s" = "shared" } } @@ -674,7 +705,7 @@ resource "aws_subnet" "test" { func testAccAWSEksClusterConfig_Required(rName string) string { return composeConfig(testAccAWSEksClusterConfig_Base(rName), fmt.Sprintf(` resource "aws_eks_cluster" "test" { - name = %q + name = %[1]q role_arn = aws_iam_role.test.arn vpc_config { @@ -689,9 +720,9 @@ resource "aws_eks_cluster" "test" { func testAccAWSEksClusterConfig_Version(rName, version string) string { return composeConfig(testAccAWSEksClusterConfig_Base(rName), fmt.Sprintf(` resource "aws_eks_cluster" "test" { - name = %q + name = %[1]q role_arn = aws_iam_role.test.arn - version = %q + version = %[2]q vpc_config { subnet_ids = aws_subnet.test[*].id @@ -705,9 +736,9 @@ resource "aws_eks_cluster" "test" { func testAccAWSEksClusterConfig_Logging(rName string, logTypes []string) string { return composeConfig(testAccAWSEksClusterConfig_Base(rName), fmt.Sprintf(` resource "aws_eks_cluster" "test" { - name = %q + name = %[1]q role_arn = aws_iam_role.test.arn - enabled_cluster_log_types = ["%v"] + enabled_cluster_log_types = ["%[2]v"] vpc_config { subnet_ids = aws_subnet.test[*].id @@ -791,12 +822,12 @@ resource "aws_security_group" "test" { vpc_id = aws_vpc.test.id tags = { - Name = "terraform-testacc-eks-cluster-sg" + Name = %[1]q } } resource "aws_eks_cluster" "test" { - name = %q + name = %[1]q role_arn = aws_iam_role.test.arn vpc_config { @@ -812,11 +843,11 @@ resource "aws_eks_cluster" "test" { func testAccAWSEksClusterConfig_VpcConfig_EndpointPrivateAccess(rName string, endpointPrivateAccess bool) string { return composeConfig(testAccAWSEksClusterConfig_Base(rName), fmt.Sprintf(` resource "aws_eks_cluster" "test" { - name = %q + name = %[1]q role_arn = aws_iam_role.test.arn vpc_config { - endpoint_private_access = %t + endpoint_private_access = %[2]t endpoint_public_access = true subnet_ids = aws_subnet.test[*].id } @@ -829,12 +860,12 @@ resource "aws_eks_cluster" "test" { func testAccAWSEksClusterConfig_VpcConfig_EndpointPublicAccess(rName string, endpointPublicAccess bool) string { return composeConfig(testAccAWSEksClusterConfig_Base(rName), fmt.Sprintf(` resource "aws_eks_cluster" "test" { - name = %q + name = %[1]q role_arn = aws_iam_role.test.arn vpc_config { endpoint_private_access = true - endpoint_public_access = %t + endpoint_public_access = %[2]t subnet_ids = aws_subnet.test[*].id } @@ -846,13 +877,13 @@ resource "aws_eks_cluster" "test" { func testAccAWSEksClusterConfig_VpcConfig_PublicAccessCidrs(rName string, publicAccessCidr string) string { return composeConfig(testAccAWSEksClusterConfig_Base(rName), fmt.Sprintf(` resource "aws_eks_cluster" "test" { - name = %q + name = %[1]q role_arn = aws_iam_role.test.arn vpc_config { endpoint_private_access = true endpoint_public_access = true - public_access_cidrs = %s + public_access_cidrs = %[2]s subnet_ids = aws_subnet.test[*].id } @@ -864,7 +895,7 @@ resource "aws_eks_cluster" "test" { func testAccAWSEksClusterConfig_NetworkConfig_ServiceIpv4Cidr(rName string, serviceIpv4Cidr string) string { return composeConfig(testAccAWSEksClusterConfig_Base(rName), fmt.Sprintf(` resource "aws_eks_cluster" "test" { - name = %q + name = %[1]q role_arn = aws_iam_role.test.arn vpc_config { @@ -872,7 +903,7 @@ resource "aws_eks_cluster" "test" { } kubernetes_network_config { - service_ipv4_cidr = %s + service_ipv4_cidr = %[2]s } depends_on = [aws_iam_role_policy_attachment.test-AmazonEKSClusterPolicy] From 45c5a0ac6bc09c69fb6fd3521dcfcbe07140561a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 18 Jun 2021 17:19:09 -0400 Subject: [PATCH 0631/1208] r/aws_eks_cluster: You cannot disable envelope encryption after enabling it. --- aws/resource_aws_eks_cluster.go | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index 1d1251abb924..2447342f0724 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -1,6 +1,7 @@ package aws import ( + "context" "fmt" "log" "regexp" @@ -9,6 +10,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -30,7 +32,13 @@ func resourceAwsEksCluster() *schema.Resource { State: schema.ImportStatePassthrough, }, - CustomizeDiff: SetTagsDiff, + CustomizeDiff: customdiff.Sequence( + SetTagsDiff, + customdiff.ForceNewIfChange("encryption_config", func(_ context.Context, old, new, meta interface{}) bool { + // You cannot disable envelope encryption after enabling it. This action is irreversible. + return len(old.([]interface{})) == 1 && len(new.([]interface{})) == 0 + }), + ), Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(30 * time.Minute), @@ -67,9 +75,6 @@ func resourceAwsEksCluster() *schema.Resource { ValidateFunc: validation.StringInSlice(eks.LogType_Values(), true), }, }, - // TODO - // TODO You cannot disable envelope encryption after enabling it. This action is irreversible. - // TODO "encryption_config": { Type: schema.TypeList, MaxItems: 1, @@ -260,26 +265,26 @@ func resourceAwsEksClusterCreate(d *schema.ResourceData, meta interface{}) error output, err = conn.CreateCluster(input) // InvalidParameterException: roleArn, arn:aws:iam::123456789012:role/XXX, does not exist - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "does not exist") { + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "does not exist") { return resource.RetryableError(err) } // InvalidParameterException: Error in role params - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "Error in role params") { + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "Error in role params") { return resource.RetryableError(err) } - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "Role could not be assumed because the trusted entity is not correct") { + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "Role could not be assumed because the trusted entity is not correct") { return resource.RetryableError(err) } // InvalidParameterException: The provided role doesn't have the Amazon EKS Managed Policies associated with it. Please ensure the following policy is attached: arn:aws:iam::aws:policy/AmazonEKSClusterPolicy - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "The provided role doesn't have the Amazon EKS Managed Policies associated with it") { + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "The provided role doesn't have the Amazon EKS Managed Policies associated with it") { return resource.RetryableError(err) } // InvalidParameterException: IAM role's policy must include the `ec2:DescribeSubnets` action - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "IAM role's policy must include") { + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "IAM role's policy must include") { return resource.RetryableError(err) } From 05ad3b0f51ddb55c5cfb2dabf69d705c743f8092 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Jun 2021 15:02:33 -0700 Subject: [PATCH 0632/1208] Returns an error from `aws_lb` sweeper when deletion fails --- aws/resource_aws_lb_test.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_lb_test.go b/aws/resource_aws_lb_test.go index 122281d19d30..b3779c3eae5f 100644 --- a/aws/resource_aws_lb_test.go +++ b/aws/resource_aws_lb_test.go @@ -11,6 +11,7 @@ import ( "github.com/aws/aws-sdk-go/service/elb" "github.com/aws/aws-sdk-go/service/elbv2" "github.com/hashicorp/aws-sdk-go-base/tfawserr" + multierror "github.com/hashicorp/go-multierror" "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" @@ -44,6 +45,7 @@ func testSweepLBs(region string) error { } conn := client.(*AWSClient).elbv2conn + var sweeperErrs *multierror.Error err = conn.DescribeLoadBalancersPages(&elbv2.DescribeLoadBalancersInput{}, func(page *elbv2.DescribeLoadBalancersOutput, lastPage bool) bool { if page == nil || len(page.LoadBalancers) == 0 { log.Print("[DEBUG] No LBs to sweep") @@ -58,19 +60,21 @@ func testSweepLBs(region string) error { LoadBalancerArn: loadBalancer.LoadBalancerArn, }) if err != nil { - log.Printf("[ERROR] Failed to delete LB (%s): %s", name, err) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("failed to delete LB (%s): %w", name, err)) + continue } } return !lastPage }) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping LB sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + } if err != nil { - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping LB sweep for %s: %s", region, err) - return nil - } - return fmt.Errorf("Error retrieving LBs: %s", err) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving LBs: %w", err)) } - return nil + + return sweeperErrs.ErrorOrNil() } func TestLBCloudwatchSuffixFromARN(t *testing.T) { From 21b5096b76eb589314e5bfe6f8599fa04d7795d7 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 19 Jun 2021 21:03:24 +0300 Subject: [PATCH 0633/1208] add `copy_tags_to_snapshot` --- aws/resource_aws_neptune_cluster.go | 18 ++++++ aws/resource_aws_neptune_cluster_test.go | 60 ++++++++++++++++++++ website/docs/r/neptune_cluster.html.markdown | 1 + 3 files changed, 79 insertions(+) diff --git a/aws/resource_aws_neptune_cluster.go b/aws/resource_aws_neptune_cluster.go index e9dfb8f6851a..c5e258cdbe39 100644 --- a/aws/resource_aws_neptune_cluster.go +++ b/aws/resource_aws_neptune_cluster.go @@ -102,6 +102,11 @@ func resourceAwsNeptuneCluster() *schema.Resource { Computed: true, }, + "copy_tags_to_snapshot": { + Type: schema.TypeBool, + Optional: true, + }, + "endpoint": { Type: schema.TypeString, Computed: true, @@ -293,6 +298,7 @@ func resourceAwsNeptuneClusterCreate(d *schema.ResourceData, meta interface{}) e createDbClusterInput := &neptune.CreateDBClusterInput{ DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)), + CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)), Engine: aws.String(d.Get("engine").(string)), Port: aws.Int64(int64(d.Get("port").(int))), StorageEncrypted: aws.Bool(d.Get("storage_encrypted").(bool)), @@ -301,6 +307,7 @@ func resourceAwsNeptuneClusterCreate(d *schema.ResourceData, meta interface{}) e } restoreDBClusterFromSnapshotInput := &neptune.RestoreDBClusterFromSnapshotInput{ DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)), + CopyTagsToSnapshot: aws.Bool(d.Get("copy_tags_to_snapshot").(bool)), Engine: aws.String(d.Get("engine").(string)), Port: aws.Int64(int64(d.Get("port").(int))), SnapshotIdentifier: aws.String(d.Get("snapshot_identifier").(string)), @@ -330,6 +337,11 @@ func resourceAwsNeptuneClusterCreate(d *schema.ResourceData, meta interface{}) e restoreDBClusterFromSnapshotInput.EngineVersion = aws.String(attr.(string)) } + if attr, ok := d.GetOk("copy_tags_to_snapshot"); ok { + createDbClusterInput.EngineVersion = aws.String(attr.(string)) + restoreDBClusterFromSnapshotInput.EngineVersion = aws.String(attr.(string)) + } + if attr, ok := d.GetOk("iam_database_authentication_enabled"); ok { createDbClusterInput.EnableIAMDatabaseAuthentication = aws.Bool(attr.(bool)) restoreDBClusterFromSnapshotInput.EnableIAMDatabaseAuthentication = aws.Bool(attr.(bool)) @@ -485,6 +497,7 @@ func flattenAwsNeptuneClusterResource(d *schema.ResourceData, meta interface{}, d.Set("backup_retention_period", dbc.BackupRetentionPeriod) d.Set("cluster_identifier", dbc.DBClusterIdentifier) d.Set("cluster_resource_id", dbc.DbClusterResourceId) + d.Set("copy_tags_to_snapshot", dbc.CopyTagsToSnapshot) if err := d.Set("enable_cloudwatch_logs_exports", aws.StringValueSlice(dbc.EnabledCloudwatchLogsExports)); err != nil { return fmt.Errorf("Error saving EnableCloudwatchLogsExports to state for Neptune Cluster (%s): %s", d.Id(), err) @@ -563,6 +576,11 @@ func resourceAwsNeptuneClusterUpdate(d *schema.ResourceData, meta interface{}) e DBClusterIdentifier: aws.String(d.Id()), } + if d.HasChange("copy_tags_to_snapshot") { + req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) + requestUpdate = true + } + if d.HasChange("vpc_security_group_ids") { if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { req.VpcSecurityGroupIds = expandStringSet(attr) diff --git a/aws/resource_aws_neptune_cluster_test.go b/aws/resource_aws_neptune_cluster_test.go index e9b5e3eda481..326b0da514e1 100644 --- a/aws/resource_aws_neptune_cluster_test.go +++ b/aws/resource_aws_neptune_cluster_test.go @@ -57,6 +57,53 @@ func TestAccAWSNeptuneCluster_basic(t *testing.T) { }) } +func TestAccAWSNeptuneCluster_copyTagsToSnapshot(t *testing.T) { + var dbCluster neptune.DBCluster + rName := acctest.RandomWithPrefix("tf-acc") + resourceName := "aws_neptune_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, neptune.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNeptuneClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSNeptuneClusterCopyTagsConfig(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNeptuneClusterExists(resourceName, &dbCluster), + resource.TestCheckResourceAttr(resourceName, "copy_tags_to_snapshot", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "apply_immediately", + "cluster_identifier_prefix", + "final_snapshot_identifier", + "skip_final_snapshot", + }, + }, + { + Config: testAccAWSNeptuneClusterCopyTagsConfig(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNeptuneClusterExists(resourceName, &dbCluster), + resource.TestCheckResourceAttr(resourceName, "copy_tags_to_snapshot", "false"), + ), + }, + { + Config: testAccAWSNeptuneClusterCopyTagsConfig(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNeptuneClusterExists(resourceName, &dbCluster), + resource.TestCheckResourceAttr(resourceName, "copy_tags_to_snapshot", "true"), + ), + }, + }, + }) +} + func TestAccAWSNeptuneCluster_namePrefix(t *testing.T) { var v neptune.DBCluster rName := "tf-test-" @@ -600,6 +647,19 @@ resource "aws_neptune_cluster" "test" { `, rName)) } +func testAccAWSNeptuneClusterCopyTagsConfig(rName string, copy bool) string { + return composeConfig(testAccAWSNeptuneClusterConfigBase(), fmt.Sprintf(` +resource "aws_neptune_cluster" "test" { + cluster_identifier = %[1]q + availability_zones = local.availability_zone_names + engine = "neptune" + neptune_cluster_parameter_group_name = "default.neptune1" + skip_final_snapshot = true + copy_tags_to_snapshot = %[2]t +} +`, rName, copy)) +} + func testAccAWSNeptuneClusterConfigDeleteProtection(rName string, isProtected bool) string { return composeConfig(testAccAWSNeptuneClusterConfigBase(), fmt.Sprintf(` resource "aws_neptune_cluster" "test" { diff --git a/website/docs/r/neptune_cluster.html.markdown b/website/docs/r/neptune_cluster.html.markdown index 03d54715cd74..6a9b161544d0 100644 --- a/website/docs/r/neptune_cluster.html.markdown +++ b/website/docs/r/neptune_cluster.html.markdown @@ -44,6 +44,7 @@ The following arguments are supported: * `backup_retention_period` - (Optional) The days to retain backups for. Default `1` * `cluster_identifier` - (Optional, Forces new resources) The cluster identifier. If omitted, Terraform will assign a random, unique identifier. * `cluster_identifier_prefix` - (Optional, Forces new resource) Creates a unique cluster identifier beginning with the specified prefix. Conflicts with `cluster_identifier`. +* `copy_tags_to_snapshot` - (Optional) If set to true, tags are copied to any snapshot of the DB cluster that is created. * `enable_cloudwatch_logs_exports` - (Optional) A list of the log types this DB cluster is configured to export to Cloudwatch Logs. Currently only supports `audit`. * `engine` - (Optional) The name of the database engine to be used for this Neptune cluster. Defaults to `neptune`. * `engine_version` - (Optional) The database engine version. From 02c865de34c7a2f314316da3e32528353be0f3ea Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 19 Jun 2021 21:05:13 +0300 Subject: [PATCH 0634/1208] fix --- aws/resource_aws_neptune_cluster.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/aws/resource_aws_neptune_cluster.go b/aws/resource_aws_neptune_cluster.go index c5e258cdbe39..19820c3ce6f5 100644 --- a/aws/resource_aws_neptune_cluster.go +++ b/aws/resource_aws_neptune_cluster.go @@ -337,11 +337,6 @@ func resourceAwsNeptuneClusterCreate(d *schema.ResourceData, meta interface{}) e restoreDBClusterFromSnapshotInput.EngineVersion = aws.String(attr.(string)) } - if attr, ok := d.GetOk("copy_tags_to_snapshot"); ok { - createDbClusterInput.EngineVersion = aws.String(attr.(string)) - restoreDBClusterFromSnapshotInput.EngineVersion = aws.String(attr.(string)) - } - if attr, ok := d.GetOk("iam_database_authentication_enabled"); ok { createDbClusterInput.EnableIAMDatabaseAuthentication = aws.Bool(attr.(bool)) restoreDBClusterFromSnapshotInput.EnableIAMDatabaseAuthentication = aws.Bool(attr.(bool)) From c0daba690d5f58505a330eec25d239e940c93579 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 19 Jun 2021 21:33:42 +0300 Subject: [PATCH 0635/1208] dissapears --- aws/resource_aws_neptune_cluster_test.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/aws/resource_aws_neptune_cluster_test.go b/aws/resource_aws_neptune_cluster_test.go index 326b0da514e1..544771e235c3 100644 --- a/aws/resource_aws_neptune_cluster_test.go +++ b/aws/resource_aws_neptune_cluster_test.go @@ -505,6 +505,29 @@ func TestAccAWSNeptuneCluster_deleteProtection(t *testing.T) { }) } +func TestAccAWSNeptuneCluster_disappears(t *testing.T) { + var dbCluster neptune.DBCluster + rName := acctest.RandomWithPrefix("tf-acc") + resourceName := "aws_neptune_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, neptune.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNeptuneClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSNeptuneClusterConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNeptuneClusterExists(resourceName, &dbCluster), + testAccCheckResourceDisappears(testAccProvider, resourceAwsNeptuneCluster(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAWSNeptuneClusterDestroy(s *terraform.State) error { return testAccCheckAWSNeptuneClusterDestroyWithProvider(s, testAccProvider) } From cb85fc8423945ebeadf3ae80c35bc5688bbb8d19 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 19 Jun 2021 22:19:44 +0300 Subject: [PATCH 0636/1208] waiters --- aws/internal/service/neptune/waiter/status.go | 28 ++++ aws/internal/service/neptune/waiter/waiter.go | 52 ++++++++ aws/resource_aws_neptune_cluster.go | 125 +++--------------- 3 files changed, 100 insertions(+), 105 deletions(-) diff --git a/aws/internal/service/neptune/waiter/status.go b/aws/internal/service/neptune/waiter/status.go index 3c833b0a240a..01ed205572d8 100644 --- a/aws/internal/service/neptune/waiter/status.go +++ b/aws/internal/service/neptune/waiter/status.go @@ -12,6 +12,12 @@ const ( // EventSubscription Unknown EventSubscriptionStatusUnknown = "Unknown" + + // Cluster NotFound + ClusterStatusNotFound = "NotFound" + + // Cluster Unknown + ClusterStatusUnknown = "Unknown" ) // EventSubscriptionStatus fetches the EventSubscription and its Status @@ -34,3 +40,25 @@ func EventSubscriptionStatus(conn *neptune.Neptune, subscriptionName string) res return output.EventSubscriptionsList[0], aws.StringValue(output.EventSubscriptionsList[0].Status), nil } } + +// ClusterStatus fetches the Cluster and its Status +func ClusterStatus(conn *neptune.Neptune, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &neptune.DescribeDBClustersInput{ + DBClusterIdentifier: aws.String(id), + } + + output, err := conn.DescribeDBClusters(input) + + if err != nil { + return nil, ClusterStatusUnknown, err + } + + if len(output.DBClusters) == 0 { + return nil, ClusterStatusNotFound, nil + } + + cluster := output.DBClusters[0] + return cluster, aws.StringValue(cluster.Status), nil + } +} diff --git a/aws/internal/service/neptune/waiter/waiter.go b/aws/internal/service/neptune/waiter/waiter.go index 061e5e080a95..5bfe74bc1778 100644 --- a/aws/internal/service/neptune/waiter/waiter.go +++ b/aws/internal/service/neptune/waiter/waiter.go @@ -29,3 +29,55 @@ func EventSubscriptionDeleted(conn *neptune.Neptune, subscriptionName string) (* return nil, err } + +// DBClusterDeleted waits for a Cluster to return Deleted +func DBClusterDeleted(conn *neptune.Neptune, id string, timeout time.Duration) (*neptune.DBCluster, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + "available", + "deleting", + "backing-up", + "modifying", + }, + Target: []string{ClusterStatusNotFound}, + Refresh: ClusterStatus(conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + Delay: 30 * time.Second, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*neptune.DBCluster); ok { + return v, err + } + + return nil, err +} + +// DBClusterAvailable waits for a Cluster to return Available +func DBClusterAvailable(conn *neptune.Neptune, id string, timeout time.Duration) (*neptune.DBCluster, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + "creating", + "backing-up", + "modifying", + "preparing-data-migration", + "migrating", + "configuring-iam-database-auth", + }, + Target: []string{"available"}, + Refresh: ClusterStatus(conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + Delay: 30 * time.Second, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*neptune.DBCluster); ok { + return v, err + } + + return nil, err +} diff --git a/aws/resource_aws_neptune_cluster.go b/aws/resource_aws_neptune_cluster.go index 19820c3ce6f5..de27ba7af5dc 100644 --- a/aws/resource_aws_neptune_cluster.go +++ b/aws/resource_aws_neptune_cluster.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/neptune/waiter" ) const ( @@ -407,7 +408,7 @@ func resourceAwsNeptuneClusterCreate(d *schema.ResourceData, meta interface{}) e } } if err != nil { - return fmt.Errorf("error creating Neptune Cluster: %s", err) + return fmt.Errorf("error creating Neptune Cluster: %w", err) } d.SetId(d.Get("cluster_identifier").(string)) @@ -415,19 +416,9 @@ func resourceAwsNeptuneClusterCreate(d *schema.ResourceData, meta interface{}) e log.Printf("[INFO] Neptune Cluster ID: %s", d.Id()) log.Println("[INFO] Waiting for Neptune Cluster to be available") - stateConf := &resource.StateChangeConf{ - Pending: resourceAwsNeptuneClusterCreatePendingStates, - Target: []string{"available"}, - Refresh: resourceAwsNeptuneClusterStateRefreshFunc(d, meta), - Timeout: d.Timeout(schema.TimeoutCreate), - MinTimeout: 10 * time.Second, - Delay: 30 * time.Second, - } - - // Wait, catching any errors - _, err = stateConf.WaitForState() + _, err = waiter.DBClusterAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)) if err != nil { - return fmt.Errorf("error waiting for Neptune Cluster state to be \"available\": %s", err) + return fmt.Errorf("error waiting for Neptune Cluster (%q) to be Available: %w", d.Id(), err) } if v, ok := d.GetOk("iam_roles"); ok { @@ -486,7 +477,7 @@ func flattenAwsNeptuneClusterResource(d *schema.ResourceData, meta interface{}, ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig if err := d.Set("availability_zones", aws.StringValueSlice(dbc.AvailabilityZones)); err != nil { - return fmt.Errorf("Error saving AvailabilityZones to state for Neptune Cluster (%s): %s", d.Id(), err) + return fmt.Errorf("Error saving AvailabilityZones to state for Neptune Cluster (%s): %w", d.Id(), err) } d.Set("backup_retention_period", dbc.BackupRetentionPeriod) @@ -495,7 +486,7 @@ func flattenAwsNeptuneClusterResource(d *schema.ResourceData, meta interface{}, d.Set("copy_tags_to_snapshot", dbc.CopyTagsToSnapshot) if err := d.Set("enable_cloudwatch_logs_exports", aws.StringValueSlice(dbc.EnabledCloudwatchLogsExports)); err != nil { - return fmt.Errorf("Error saving EnableCloudwatchLogsExports to state for Neptune Cluster (%s): %s", d.Id(), err) + return fmt.Errorf("Error saving EnableCloudwatchLogsExports to state for Neptune Cluster (%s): %w", d.Id(), err) } d.Set("endpoint", dbc.Endpoint) @@ -519,7 +510,7 @@ func flattenAwsNeptuneClusterResource(d *schema.ResourceData, meta interface{}, sg = append(sg, aws.StringValue(g.VpcSecurityGroupId)) } if err := d.Set("vpc_security_group_ids", sg); err != nil { - return fmt.Errorf("Error saving VPC Security Group IDs to state for Neptune Cluster (%s): %s", d.Id(), err) + return fmt.Errorf("Error saving VPC Security Group IDs to state for Neptune Cluster (%s): %w", d.Id(), err) } var cm []string @@ -527,7 +518,7 @@ func flattenAwsNeptuneClusterResource(d *schema.ResourceData, meta interface{}, cm = append(cm, aws.StringValue(m.DBInstanceIdentifier)) } if err := d.Set("cluster_members", cm); err != nil { - return fmt.Errorf("Error saving Neptune Cluster Members to state for Neptune Cluster (%s): %s", d.Id(), err) + return fmt.Errorf("Error saving Neptune Cluster Members to state for Neptune Cluster (%s): %w", d.Id(), err) } var roles []string @@ -536,7 +527,7 @@ func flattenAwsNeptuneClusterResource(d *schema.ResourceData, meta interface{}, } if err := d.Set("iam_roles", roles); err != nil { - return fmt.Errorf("Error saving IAM Roles to state for Neptune Cluster (%s): %s", d.Id(), err) + return fmt.Errorf("Error saving IAM Roles to state for Neptune Cluster (%s): %w", d.Id(), err) } arn := aws.StringValue(dbc.DBClusterArn) @@ -545,7 +536,7 @@ func flattenAwsNeptuneClusterResource(d *schema.ResourceData, meta interface{}, tags, err := keyvaluetags.NeptuneListTags(conn, d.Get("arn").(string)) if err != nil { - return fmt.Errorf("error listing tags for Neptune Cluster (%s): %s", d.Get("arn").(string), err) + return fmt.Errorf("error listing tags for Neptune Cluster (%s): %w", d.Get("arn").(string), err) } tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -653,22 +644,12 @@ func resourceAwsNeptuneClusterUpdate(d *schema.ResourceData, meta interface{}) e _, err = conn.ModifyDBCluster(req) } if err != nil { - return fmt.Errorf("Failed to modify Neptune Cluster (%s): %s", d.Id(), err) + return fmt.Errorf("Failed to modify Neptune Cluster (%s): %w", d.Id(), err) } - stateConf := &resource.StateChangeConf{ - Pending: resourceAwsNeptuneClusterUpdatePendingStates, - Target: []string{"available"}, - Refresh: resourceAwsNeptuneClusterStateRefreshFunc(d, meta), - Timeout: d.Timeout(schema.TimeoutUpdate), - MinTimeout: 10 * time.Second, - Delay: 10 * time.Second, - } - - log.Printf("[INFO] Waiting for Neptune Cluster (%s) to modify", d.Id()) - _, err = stateConf.WaitForState() + _, err = waiter.DBClusterAvailable(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)) if err != nil { - return fmt.Errorf("error waiting for Neptune Cluster (%s) to modify: %s", d.Id(), err) + return fmt.Errorf("error waiting for Neptune Cluster (%q) to be Available: %w", d.Id(), err) } } @@ -705,7 +686,7 @@ func resourceAwsNeptuneClusterUpdate(d *schema.ResourceData, meta interface{}) e o, n := d.GetChange("tags_all") if err := keyvaluetags.NeptuneUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating Neptune Cluster (%s) tags: %s", d.Get("arn").(string), err) + return fmt.Errorf("error updating Neptune Cluster (%s) tags: %w", d.Get("arn").(string), err) } } @@ -751,65 +732,20 @@ func resourceAwsNeptuneClusterDelete(d *schema.ResourceData, meta interface{}) e _, err = conn.DeleteDBCluster(&deleteOpts) } if err != nil { - return fmt.Errorf("Neptune Cluster cannot be deleted: %s", err) + return fmt.Errorf("Neptune Cluster cannot be deleted: %w", err) } - stateConf := &resource.StateChangeConf{ - Pending: resourceAwsNeptuneClusterDeletePendingStates, - Target: []string{"destroyed"}, - Refresh: resourceAwsNeptuneClusterStateRefreshFunc(d, meta), - Timeout: d.Timeout(schema.TimeoutDelete), - MinTimeout: 10 * time.Second, - Delay: 30 * time.Second, - } - - // Wait, catching any errors - _, err = stateConf.WaitForState() + _, err = waiter.DBClusterDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf("Error deleting Neptune Cluster (%s): %s", d.Id(), err) + if isAWSErr(err, neptune.ErrCodeDBClusterNotFoundFault, "") { + return nil + } + return fmt.Errorf("error waiting for Neptune Cluster (%q) to be Deleted: %w", d.Id(), err) } return nil } -func resourceAwsNeptuneClusterStateRefreshFunc( - d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - conn := meta.(*AWSClient).neptuneconn - - resp, err := conn.DescribeDBClusters(&neptune.DescribeDBClustersInput{ - DBClusterIdentifier: aws.String(d.Id()), - }) - - if err != nil { - if isAWSErr(err, neptune.ErrCodeDBClusterNotFoundFault, "") { - log.Printf("[DEBUG] Neptune Cluster (%s) not found", d.Id()) - return 42, "destroyed", nil - } - log.Printf("[DEBUG] Error on retrieving Neptune Cluster (%s) when waiting: %s", d.Id(), err) - return nil, "", err - } - - var dbc *neptune.DBCluster - - for _, v := range resp.DBClusters { - if aws.StringValue(v.DBClusterIdentifier) == d.Id() { - dbc = v - } - } - - if dbc == nil { - return 42, "destroyed", nil - } - - if dbc.Status != nil { - log.Printf("[DEBUG] Neptune Cluster status (%s): %s", d.Id(), aws.StringValue(dbc.Status)) - } - - return dbc, aws.StringValue(dbc.Status), nil - } -} - func setIamRoleToNeptuneCluster(clusterIdentifier string, roleArn string, conn *neptune.Neptune) error { params := &neptune.AddRoleToDBClusterInput{ DBClusterIdentifier: aws.String(clusterIdentifier), @@ -827,24 +763,3 @@ func removeIamRoleFromNeptuneCluster(clusterIdentifier string, roleArn string, c _, err := conn.RemoveRoleFromDBCluster(params) return err } - -var resourceAwsNeptuneClusterCreatePendingStates = []string{ - "creating", - "backing-up", - "modifying", - "preparing-data-migration", - "migrating", -} - -var resourceAwsNeptuneClusterUpdatePendingStates = []string{ - "backing-up", - "modifying", - "configuring-iam-database-auth", -} - -var resourceAwsNeptuneClusterDeletePendingStates = []string{ - "available", - "deleting", - "backing-up", - "modifying", -} From d6af61d57b6a1beb6531264b6edc3550373322a5 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 19 Jun 2021 22:20:13 +0300 Subject: [PATCH 0637/1208] changelog --- .changelog/19899.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19899.txt diff --git a/.changelog/19899.txt b/.changelog/19899.txt new file mode 100644 index 000000000000..23fadb9c9891 --- /dev/null +++ b/.changelog/19899.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_neptune_cluster: Add `copy_snapshot_to_tags` argument +``` \ No newline at end of file From f8a4f01c9089fedc05360f6bcb0d6477fe8b6c15 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 20 Jun 2021 17:47:43 -0400 Subject: [PATCH 0638/1208] r/aws_eks_fargate_profile: Use internal waiter package. --- aws/internal/service/eks/finder/finder.go | 29 ++++ aws/internal/service/eks/id.go | 19 +++ aws/internal/service/eks/waiter/status.go | 16 ++ aws/internal/service/eks/waiter/waiter.go | 34 ++++ aws/resource_aws_eks_cluster.go | 2 +- aws/resource_aws_eks_fargate_profile.go | 134 ++++------------ aws/resource_aws_eks_fargate_profile_test.go | 158 +++++++++---------- aws/resource_aws_eks_node_group.go | 1 - 8 files changed, 207 insertions(+), 186 deletions(-) diff --git a/aws/internal/service/eks/finder/finder.go b/aws/internal/service/eks/finder/finder.go index a1b8fc712d7d..ccea06c82658 100644 --- a/aws/internal/service/eks/finder/finder.go +++ b/aws/internal/service/eks/finder/finder.go @@ -37,6 +37,35 @@ func ClusterByName(conn *eks.EKS, name string) (*eks.Cluster, error) { return output.Cluster, nil } +func FargateProfileByClusterNameAndFargateProfileName(conn *eks.EKS, clusterName, fargateProfileName string) (*eks.FargateProfile, error) { + input := &eks.DescribeFargateProfileInput{ + ClusterName: aws.String(clusterName), + FargateProfileName: aws.String(fargateProfileName), + } + + output, err := conn.DescribeFargateProfile(input) + + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.FargateProfile == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.FargateProfile, nil +} + func UpdateByNameAndID(conn *eks.EKS, name, id string) (*eks.Update, error) { input := &eks.DescribeUpdateInput{ Name: aws.String(name), diff --git a/aws/internal/service/eks/id.go b/aws/internal/service/eks/id.go index 67651b3c4357..3fe8d2a776c2 100644 --- a/aws/internal/service/eks/id.go +++ b/aws/internal/service/eks/id.go @@ -5,6 +5,25 @@ import ( "strings" ) +const fargateProfileResourceIDSeparator = ":" + +func FargateProfileCreateResourceID(clusterName, fargateProfileName string) string { + parts := []string{clusterName, fargateProfileName} + id := strings.Join(parts, fargateProfileResourceIDSeparator) + + return id +} + +func FargateProfileParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, fargateProfileResourceIDSeparator) + + if len(parts) == 2 && parts[0] != "" && parts[1] != "" { + return parts[0], parts[1], nil + } + + return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected cluster-name%[2]sfargate-profile-name", id, fargateProfileResourceIDSeparator) +} + const nodeGroupResourceIDSeparator = ":" func NodeGroupCreateResourceID(clusterName, nodeGroupName string) string { diff --git a/aws/internal/service/eks/waiter/status.go b/aws/internal/service/eks/waiter/status.go index a2e730460490..4552bf78a3a1 100644 --- a/aws/internal/service/eks/waiter/status.go +++ b/aws/internal/service/eks/waiter/status.go @@ -28,6 +28,22 @@ func ClusterStatus(conn *eks.EKS, name string) resource.StateRefreshFunc { } } +func FargateProfileStatus(conn *eks.EKS, clusterName, fargateProfileName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.FargateProfileByClusterNameAndFargateProfileName(conn, clusterName, fargateProfileName) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} + func UpdateStatus(conn *eks.EKS, name, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { output, err := finder.UpdateByNameAndID(conn, name, id) diff --git a/aws/internal/service/eks/waiter/waiter.go b/aws/internal/service/eks/waiter/waiter.go index c05ef448c64b..d433fc7c607b 100644 --- a/aws/internal/service/eks/waiter/waiter.go +++ b/aws/internal/service/eks/waiter/waiter.go @@ -54,6 +54,40 @@ func ClusterDeleted(conn *eks.EKS, name string, timeout time.Duration) (*eks.Clu return nil, err } +func FargateProfileCreated(conn *eks.EKS, clusterName, fargateProfileName string, timeout time.Duration) (*eks.FargateProfile, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{eks.FargateProfileStatusCreating}, + Target: []string{eks.FargateProfileStatusActive}, + Refresh: FargateProfileStatus(conn, clusterName, fargateProfileName), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*eks.FargateProfile); ok { + return output, err + } + + return nil, err +} + +func FargateProfileDeleted(conn *eks.EKS, clusterName, fargateProfileName string, timeout time.Duration) (*eks.FargateProfile, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{eks.FargateProfileStatusActive, eks.FargateProfileStatusDeleting}, + Target: []string{}, + Refresh: FargateProfileStatus(conn, clusterName, fargateProfileName), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*eks.FargateProfile); ok { + return output, err + } + + return nil, err +} + func UpdateSuccessful(conn *eks.EKS, name, id string, timeout time.Duration) (*eks.Update, error) { stateConf := &resource.StateChangeConf{ Pending: []string{eks.UpdateStatusInProgress}, diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index 2447342f0724..fd0a6e4da6e2 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -508,7 +508,7 @@ func resourceAwsEksClusterDelete(d *schema.ResourceData, meta interface{}) error _, err = waiter.ClusterDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) if err != nil { - return fmt.Errorf("error waiting for EKS Cluster (%s) delete: %w", d.Id(), err) + return fmt.Errorf("error waiting for EKS Cluster (%s) to delete: %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_eks_fargate_profile.go b/aws/resource_aws_eks_fargate_profile.go index 0a8f6bcee288..509f97bd65fe 100644 --- a/aws/resource_aws_eks_fargate_profile.go +++ b/aws/resource_aws_eks_fargate_profile.go @@ -3,16 +3,20 @@ package aws import ( "fmt" "log" - "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/waiter" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsEksFargateProfile() *schema.Resource { @@ -21,7 +25,6 @@ func resourceAwsEksFargateProfile() *schema.Resource { Read: resourceAwsEksFargateProfileRead, Update: resourceAwsEksFargateProfileUpdate, Delete: resourceAwsEksFargateProfileDelete, - Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, @@ -99,9 +102,10 @@ func resourceAwsEksFargateProfileCreate(d *schema.ResourceData, meta interface{} conn := meta.(*AWSClient).eksconn defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) + clusterName := d.Get("cluster_name").(string) fargateProfileName := d.Get("fargate_profile_name").(string) - id := fmt.Sprintf("%s:%s", clusterName, fargateProfileName) + id := tfeks.FargateProfileCreateResourceID(clusterName, fargateProfileName) input := &eks.CreateFargateProfileInput{ ClientRequestToken: aws.String(resource.UniqueId()), @@ -117,7 +121,7 @@ func resourceAwsEksFargateProfileCreate(d *schema.ResourceData, meta interface{} } // mutex lock for creation/deletion serialization - mutexKey := fmt.Sprintf("%s-fargate-profiles", d.Get("cluster_name").(string)) + mutexKey := fmt.Sprintf("%s-fargate-profiles", clusterName) awsMutexKV.Lock(mutexKey) defer awsMutexKV.Unlock(mutexKey) @@ -126,7 +130,7 @@ func resourceAwsEksFargateProfileCreate(d *schema.ResourceData, meta interface{} // Retry for IAM eventual consistency on error: // InvalidParameterException: Misconfigured PodExecutionRole Trust Policy; Please add the eks-fargate-pods.amazonaws.com Service Principal - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "Misconfigured PodExecutionRole Trust Policy") { + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "Misconfigured PodExecutionRole Trust Policy") { return resource.RetryableError(err) } @@ -137,25 +141,20 @@ func resourceAwsEksFargateProfileCreate(d *schema.ResourceData, meta interface{} return nil }) - if isResourceTimeoutError(err) { + if tfresource.TimedOut(err) { _, err = conn.CreateFargateProfile(input) } if err != nil { - return fmt.Errorf("error creating EKS Fargate Profile (%s): %s", id, err) + return fmt.Errorf("error creating EKS Fargate Profile (%s): %w", id, err) } d.SetId(id) - stateConf := resource.StateChangeConf{ - Pending: []string{eks.FargateProfileStatusCreating}, - Target: []string{eks.FargateProfileStatusActive}, - Timeout: d.Timeout(schema.TimeoutCreate), - Refresh: refreshEksFargateProfileStatus(conn, clusterName, fargateProfileName), - } + _, err = waiter.FargateProfileCreated(conn, clusterName, fargateProfileName, d.Timeout(schema.TimeoutCreate)) - if _, err := stateConf.WaitForState(); err != nil { - return fmt.Errorf("error waiting for EKS Fargate Profile (%s) creation: %s", d.Id(), err) + if err != nil { + return fmt.Errorf("error waiting for EKS Fargate Profile (%s) to create: %w", d.Id(), err) } return resourceAwsEksFargateProfileRead(d, meta) @@ -166,34 +165,22 @@ func resourceAwsEksFargateProfileRead(d *schema.ResourceData, meta interface{}) defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - clusterName, fargateProfileName, err := resourceAwsEksFargateProfileParseId(d.Id()) + clusterName, fargateProfileName, err := tfeks.FargateProfileParseResourceID(d.Id()) + if err != nil { return err } - input := &eks.DescribeFargateProfileInput{ - ClusterName: aws.String(clusterName), - FargateProfileName: aws.String(fargateProfileName), - } - - output, err := conn.DescribeFargateProfile(input) + fargateProfile, err := finder.FargateProfileByClusterNameAndFargateProfileName(conn, clusterName, fargateProfileName) - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] EKS Fargate Profile (%s) not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error reading EKS Fargate Profile (%s): %s", d.Id(), err) - } - - fargateProfile := output.FargateProfile - - if fargateProfile == nil { - log.Printf("[WARN] EKS Fargate Profile (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil + return fmt.Errorf("error reading EKS Fargate Profile (%s): %w", d.Id(), err) } d.Set("arn", fargateProfile.FargateProfileArn) @@ -202,13 +189,13 @@ func resourceAwsEksFargateProfileRead(d *schema.ResourceData, meta interface{}) d.Set("pod_execution_role_arn", fargateProfile.PodExecutionRoleArn) if err := d.Set("selector", flattenEksFargateProfileSelectors(fargateProfile.Selectors)); err != nil { - return fmt.Errorf("error setting selector: %s", err) + return fmt.Errorf("error setting selector: %w", err) } d.Set("status", fargateProfile.Status) if err := d.Set("subnet_ids", aws.StringValueSlice(fargateProfile.Subnets)); err != nil { - return fmt.Errorf("error setting subnets: %s", err) + return fmt.Errorf("error setting subnet_ids: %w", err) } tags := keyvaluetags.EksKeyValueTags(fargateProfile.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -231,7 +218,7 @@ func resourceAwsEksFargateProfileUpdate(d *schema.ResourceData, meta interface{} if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") if err := keyvaluetags.EksUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating tags: %s", err) + return fmt.Errorf("error updating tags: %w", err) } } @@ -241,33 +228,35 @@ func resourceAwsEksFargateProfileUpdate(d *schema.ResourceData, meta interface{} func resourceAwsEksFargateProfileDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).eksconn - clusterName, fargateProfileName, err := resourceAwsEksFargateProfileParseId(d.Id()) + clusterName, fargateProfileName, err := tfeks.FargateProfileParseResourceID(d.Id()) + if err != nil { return err } - input := &eks.DeleteFargateProfileInput{ - ClusterName: aws.String(clusterName), - FargateProfileName: aws.String(fargateProfileName), - } - // mutex lock for creation/deletion serialization mutexKey := fmt.Sprintf("%s-fargate-profiles", d.Get("cluster_name").(string)) awsMutexKV.Lock(mutexKey) defer awsMutexKV.Unlock(mutexKey) - _, err = conn.DeleteFargateProfile(input) + log.Printf("[DEBUG] Deleting EKS Fargate Profile: %s", d.Id()) + _, err = conn.DeleteFargateProfile(&eks.DeleteFargateProfileInput{ + ClusterName: aws.String(clusterName), + FargateProfileName: aws.String(fargateProfileName), + }) - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { return nil } if err != nil { - return fmt.Errorf("error deleting EKS Fargate Profile (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting EKS Fargate Profile (%s): %w", d.Id(), err) } - if err := waitForEksFargateProfileDeletion(conn, clusterName, fargateProfileName, d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("error waiting for EKS Fargate Profile (%s) deletion: %s", d.Id(), err) + _, err = waiter.FargateProfileDeleted(conn, clusterName, fargateProfileName, d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return fmt.Errorf("error waiting for EKS Fargate Profile (%s) to delete: %w", d.Id(), err) } return nil @@ -321,56 +310,3 @@ func flattenEksFargateProfileSelectors(fargateProfileSelectors []*eks.FargatePro return l } - -func refreshEksFargateProfileStatus(conn *eks.EKS, clusterName string, fargateProfileName string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - input := &eks.DescribeFargateProfileInput{ - ClusterName: aws.String(clusterName), - FargateProfileName: aws.String(fargateProfileName), - } - - output, err := conn.DescribeFargateProfile(input) - - if err != nil { - return "", "", err - } - - fargateProfile := output.FargateProfile - - if fargateProfile == nil { - return fargateProfile, "", fmt.Errorf("EKS Fargate Profile (%s:%s) missing", clusterName, fargateProfileName) - } - - return fargateProfile, aws.StringValue(fargateProfile.Status), nil - } -} - -func waitForEksFargateProfileDeletion(conn *eks.EKS, clusterName string, fargateProfileName string, timeout time.Duration) error { - stateConf := resource.StateChangeConf{ - Pending: []string{ - eks.FargateProfileStatusActive, - eks.FargateProfileStatusDeleting, - }, - Target: []string{""}, - Timeout: timeout, - Refresh: refreshEksFargateProfileStatus(conn, clusterName, fargateProfileName), - } - - _, err := stateConf.WaitForState() - - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - return nil - } - - return err -} - -func resourceAwsEksFargateProfileParseId(id string) (string, string, error) { - parts := strings.Split(id, ":") - - if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return "", "", fmt.Errorf("unexpected format of ID (%s), expected cluster-name:fargate-profile-name", id) - } - - return parts[0], parts[1], nil -} diff --git a/aws/resource_aws_eks_fargate_profile_test.go b/aws/resource_aws_eks_fargate_profile_test.go index d01b7b2eed12..fceb1dde40db 100644 --- a/aws/resource_aws_eks_fargate_profile_test.go +++ b/aws/resource_aws_eks_fargate_profile_test.go @@ -5,7 +5,6 @@ import ( "log" "regexp" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/endpoints" @@ -14,6 +13,9 @@ import ( "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" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -26,56 +28,63 @@ func init() { func testSweepEksFargateProfiles(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } conn := client.(*AWSClient).eksconn - - var errors error input := &eks.ListClustersInput{} + var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) + err = conn.ListClustersPages(input, func(page *eks.ListClustersOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + for _, cluster := range page.Clusters { - clusterName := aws.StringValue(cluster) input := &eks.ListFargateProfilesInput{ ClusterName: cluster, } + err := conn.ListFargateProfilesPages(input, func(page *eks.ListFargateProfilesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + for _, profile := range page.FargateProfileNames { - profileName := aws.StringValue(profile) - log.Printf("[INFO] Deleting Fargate Profile %q", profileName) - input := &eks.DeleteFargateProfileInput{ - ClusterName: cluster, - FargateProfileName: profile, - } - _, err := conn.DeleteFargateProfile(input) - - if err != nil && !isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - errors = multierror.Append(errors, fmt.Errorf("error deleting EKS Fargate Profile %q: %w", profileName, err)) - continue - } - - if err := waitForEksFargateProfileDeletion(conn, clusterName, profileName, 10*time.Minute); err != nil { - errors = multierror.Append(errors, fmt.Errorf("error waiting for EKS Fargate Profile %q deletion: %w", profileName, err)) - continue - } + r := resourceAwsEksFargateProfile() + d := r.Data(nil) + d.SetId(tfeks.FargateProfileCreateResourceID(aws.StringValue(cluster), aws.StringValue(profile))) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - return true + + return !lastPage }) + if err != nil { - errors = multierror.Append(errors, fmt.Errorf("error listing Fargate Profiles for EKS Cluster %s: %w", clusterName, err)) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Fargate Profiles (%s): %w", region, err)) } } - return true + return !lastPage }) + if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping EKS Clusters sweep for %s: %s", region, err) - return errors // In case we have completed some pages, but had errors + log.Printf("[WARN] Skipping EKS Fargate Profiles sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors } + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Clusters (%s): %w", region, err)) + } + + err = testSweepResourceOrchestrator(sweepResources) + if err != nil { - errors = multierror.Append(errors, fmt.Errorf("error retrieving EKS Clusters: %w", err)) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping EKS Fargate Profiles (%s): %w", region, err)) } - return errors + return sweeperErrs.ErrorOrNil() } func TestAccAWSEksFargateProfile_basic(t *testing.T) { @@ -129,7 +138,7 @@ func TestAccAWSEksFargateProfile_disappears(t *testing.T) { Config: testAccAWSEksFargateProfileConfigFargateProfileName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksFargateProfileExists(resourceName, &fargateProfile), - testAccCheckAWSEksFargateProfileDisappears(&fargateProfile), + testAccCheckResourceDisappears(testAccProvider, resourceAwsEksFargateProfile(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -242,37 +251,21 @@ func testAccCheckAWSEksFargateProfileExists(resourceName string, fargateProfile return fmt.Errorf("No EKS Fargate Profile ID is set") } - clusterName, fargateProfileName, err := resourceAwsEksFargateProfileParseId(rs.Primary.ID) + clusterName, fargateProfileName, err := tfeks.FargateProfileParseResourceID(rs.Primary.ID) + if err != nil { return err } conn := testAccProvider.Meta().(*AWSClient).eksconn - input := &eks.DescribeFargateProfileInput{ - ClusterName: aws.String(clusterName), - FargateProfileName: aws.String(fargateProfileName), - } - - output, err := conn.DescribeFargateProfile(input) + output, err := finder.FargateProfileByClusterNameAndFargateProfileName(conn, clusterName, fargateProfileName) if err != nil { return err } - if output == nil || output.FargateProfile == nil { - return fmt.Errorf("EKS Fargate Profile (%s) not found", rs.Primary.ID) - } - - if aws.StringValue(output.FargateProfile.FargateProfileName) != fargateProfileName { - return fmt.Errorf("EKS Fargate Profile (%s) not found", rs.Primary.ID) - } - - if got, want := aws.StringValue(output.FargateProfile.Status), eks.FargateProfileStatusActive; got != want { - return fmt.Errorf("EKS Fargate Profile (%s) not in %s status, got: %s", rs.Primary.ID, want, got) - } - - *fargateProfile = *output.FargateProfile + *fargateProfile = *output return nil } @@ -286,51 +279,26 @@ func testAccCheckAWSEksFargateProfileDestroy(s *terraform.State) error { continue } - clusterName, fargateProfileName, err := resourceAwsEksFargateProfileParseId(rs.Primary.ID) + clusterName, fargateProfileName, err := tfeks.FargateProfileParseResourceID(rs.Primary.ID) + if err != nil { return err } - input := &eks.DescribeFargateProfileInput{ - ClusterName: aws.String(clusterName), - FargateProfileName: aws.String(fargateProfileName), - } + _, err = finder.FargateProfileByClusterNameAndFargateProfileName(conn, clusterName, fargateProfileName) - output, err := conn.DescribeFargateProfile(input) - - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + if tfresource.NotFound(err) { continue } - if output != nil && output.FargateProfile != nil && aws.StringValue(output.FargateProfile.FargateProfileName) == fargateProfileName { - return fmt.Errorf("EKS Fargate Profile (%s) still exists", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckAWSEksFargateProfileDisappears(fargateProfile *eks.FargateProfile) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).eksconn - - input := &eks.DeleteFargateProfileInput{ - ClusterName: fargateProfile.ClusterName, - FargateProfileName: fargateProfile.FargateProfileName, - } - - _, err := conn.DeleteFargateProfile(input) - - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - return nil - } - if err != nil { return err } - return waitForEksFargateProfileDeletion(conn, aws.StringValue(fargateProfile.ClusterName), aws.StringValue(fargateProfile.FargateProfileName), 10*time.Minute) + return fmt.Errorf("EKS Fargate Profile %s still exists", rs.Primary.ID) } + + return nil } func testAccPreCheckAWSEksFargateProfile(t *testing.T) { @@ -445,13 +413,17 @@ resource "aws_vpc" "test" { enable_dns_support = true tags = { - Name = "tf-acc-test-eks-fargate-profile" + Name = %[1]q "kubernetes.io/cluster/%[1]s" = "shared" } } resource "aws_internet_gateway" "test" { vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } } resource "aws_route_table" "public" { @@ -461,6 +433,10 @@ resource "aws_route_table" "public" { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.test.id } + + tags = { + Name = %[1]q + } } resource "aws_main_route_table_association" "test" { @@ -476,7 +452,7 @@ resource "aws_subnet" "private" { vpc_id = aws_vpc.test.id tags = { - Name = "tf-acc-test-eks-fargate-profile-private" + Name = %[1]q "kubernetes.io/cluster/%[1]s" = "shared" } } @@ -486,6 +462,10 @@ resource "aws_eip" "private" { depends_on = [aws_internet_gateway.test] vpc = true + + tags = { + Name = %[1]q + } } resource "aws_nat_gateway" "private" { @@ -493,6 +473,10 @@ resource "aws_nat_gateway" "private" { allocation_id = aws_eip.private[count.index].id subnet_id = aws_subnet.private[count.index].id + + tags = { + Name = %[1]q + } } resource "aws_route_table" "private" { @@ -504,6 +488,10 @@ resource "aws_route_table" "private" { cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.private[count.index].id } + + tags = { + Name = %[1]q + } } resource "aws_route_table_association" "private" { @@ -521,7 +509,7 @@ resource "aws_subnet" "public" { vpc_id = aws_vpc.test.id tags = { - Name = "tf-acc-test-eks-fargate-profile-public" + Name = %[1]q "kubernetes.io/cluster/%[1]s" = "shared" } } diff --git a/aws/resource_aws_eks_node_group.go b/aws/resource_aws_eks_node_group.go index f47913cd031d..666d1320ba67 100644 --- a/aws/resource_aws_eks_node_group.go +++ b/aws/resource_aws_eks_node_group.go @@ -23,7 +23,6 @@ func resourceAwsEksNodeGroup() *schema.Resource { Read: resourceAwsEksNodeGroupRead, Update: resourceAwsEksNodeGroupUpdate, Delete: resourceAwsEksNodeGroupDelete, - Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, From b3d3054ead5e7b93a4d859e6c38014c95e1952d9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 20 Jun 2021 18:33:13 -0400 Subject: [PATCH 0639/1208] r/aws_eks_node_group: Use internal waiter package. --- aws/internal/service/eks/finder/finder.go | 59 +++++ aws/internal/service/eks/waiter/status.go | 32 +++ aws/internal/service/eks/waiter/waiter.go | 60 +++++ aws/resource_aws_eks_node_group.go | 257 ++++++---------------- aws/resource_aws_eks_node_group_test.go | 108 +++------ 5 files changed, 250 insertions(+), 266 deletions(-) diff --git a/aws/internal/service/eks/finder/finder.go b/aws/internal/service/eks/finder/finder.go index ccea06c82658..ce9bb7586c69 100644 --- a/aws/internal/service/eks/finder/finder.go +++ b/aws/internal/service/eks/finder/finder.go @@ -66,6 +66,65 @@ func FargateProfileByClusterNameAndFargateProfileName(conn *eks.EKS, clusterName return output.FargateProfile, nil } +func NodegroupByClusterNameAndNodegroupName(conn *eks.EKS, clusterName, nodeGroupName string) (*eks.Nodegroup, error) { + input := &eks.DescribeNodegroupInput{ + ClusterName: aws.String(clusterName), + NodegroupName: aws.String(nodeGroupName), + } + + output, err := conn.DescribeNodegroup(input) + + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Nodegroup == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.Nodegroup, nil +} + +func NodegroupUpdateByClusterNameNodegroupNameAndID(conn *eks.EKS, clusterName, nodeGroupName, id string) (*eks.Update, error) { + input := &eks.DescribeUpdateInput{ + Name: aws.String(clusterName), + NodegroupName: aws.String(nodeGroupName), + UpdateId: aws.String(id), + } + + output, err := conn.DescribeUpdate(input) + + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Update == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.Update, nil +} + func UpdateByNameAndID(conn *eks.EKS, name, id string) (*eks.Update, error) { input := &eks.DescribeUpdateInput{ Name: aws.String(name), diff --git a/aws/internal/service/eks/waiter/status.go b/aws/internal/service/eks/waiter/status.go index 4552bf78a3a1..59b63250314a 100644 --- a/aws/internal/service/eks/waiter/status.go +++ b/aws/internal/service/eks/waiter/status.go @@ -44,6 +44,38 @@ func FargateProfileStatus(conn *eks.EKS, clusterName, fargateProfileName string) } } +func NodegroupStatus(conn *eks.EKS, clusterName, nodeGroupName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.NodegroupByClusterNameAndNodegroupName(conn, clusterName, nodeGroupName) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} + +func NodegroupUpdateStatus(conn *eks.EKS, clusterName, nodeGroupName, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.NodegroupUpdateByClusterNameNodegroupNameAndID(conn, clusterName, nodeGroupName, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} + func UpdateStatus(conn *eks.EKS, name, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { output, err := finder.UpdateByNameAndID(conn, name, id) diff --git a/aws/internal/service/eks/waiter/waiter.go b/aws/internal/service/eks/waiter/waiter.go index d433fc7c607b..4056d3cc003a 100644 --- a/aws/internal/service/eks/waiter/waiter.go +++ b/aws/internal/service/eks/waiter/waiter.go @@ -88,6 +88,66 @@ func FargateProfileDeleted(conn *eks.EKS, clusterName, fargateProfileName string return nil, err } +func NodegroupCreated(conn *eks.EKS, clusterName, nodeGroupName string, timeout time.Duration) (*eks.Nodegroup, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{eks.NodegroupStatusCreating}, + Target: []string{eks.NodegroupStatusActive}, + Refresh: NodegroupStatus(conn, clusterName, nodeGroupName), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*eks.Nodegroup); ok { + return output, err + } + + return nil, err +} + +func NodegroupDeleted(conn *eks.EKS, clusterName, nodeGroupName string, timeout time.Duration) (*eks.Nodegroup, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{eks.NodegroupStatusActive, eks.NodegroupStatusDeleting}, + Target: []string{}, + Refresh: NodegroupStatus(conn, clusterName, nodeGroupName), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*eks.Nodegroup); ok { + return output, err + } + + return nil, err +} + +func NodegroupUpdateSuccessful(conn *eks.EKS, clusterName, nodeGroupName, id string, timeout time.Duration) (*eks.Update, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{eks.UpdateStatusInProgress}, + Target: []string{eks.UpdateStatusSuccessful}, + Refresh: NodegroupUpdateStatus(conn, clusterName, nodeGroupName, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*eks.Update); ok { + if status := aws.StringValue(output.Status); status == eks.UpdateStatusCancelled || status == eks.UpdateStatusFailed { + var errs *multierror.Error + + for _, e := range output.Errors { + errs = multierror.Append(errs, fmt.Errorf("%s: %s", aws.StringValue(e.ErrorCode), aws.StringValue(e.ErrorMessage))) + } + tfresource.SetLastError(err, errs.ErrorOrNil()) + } + + return output, err + } + + return nil, err +} + func UpdateSuccessful(conn *eks.EKS, name, id string, timeout time.Duration) (*eks.Update, error) { stateConf := &resource.StateChangeConf{ Pending: []string{eks.UpdateStatusInProgress}, diff --git a/aws/resource_aws_eks_node_group.go b/aws/resource_aws_eks_node_group.go index 666d1320ba67..c385f293deec 100644 --- a/aws/resource_aws_eks_node_group.go +++ b/aws/resource_aws_eks_node_group.go @@ -4,17 +4,20 @@ import ( "fmt" "log" "reflect" - "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsEksNodeGroup() *schema.Resource { @@ -259,6 +262,8 @@ func resourceAwsEksNodeGroupCreate(d *schema.ResourceData, meta interface{}) err clusterName := d.Get("cluster_name").(string) nodeGroupName := naming.Generate(d.Get("node_group_name").(string), d.Get("node_group_name_prefix").(string)) + id := tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName) + input := &eks.CreateNodegroupInput{ ClientRequestToken: aws.String(resource.UniqueId()), ClusterName: aws.String(clusterName), @@ -303,10 +308,6 @@ func resourceAwsEksNodeGroupCreate(d *schema.ResourceData, meta interface{}) err input.ScalingConfig = expandEksNodegroupScalingConfig(v) } - if len(tags) > 0 { - input.Tags = tags.IgnoreAws().EksTags() - } - if v, ok := d.GetOk("taint"); ok && v.(*schema.Set).Len() > 0 { input.Taints = expandEksTaints(v.(*schema.Set).List()) } @@ -315,23 +316,22 @@ func resourceAwsEksNodeGroupCreate(d *schema.ResourceData, meta interface{}) err input.Version = aws.String(v.(string)) } + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().EksTags() + } + _, err := conn.CreateNodegroup(input) if err != nil { - return fmt.Errorf("error creating EKS Node Group (%s/%s): %w", clusterName, nodeGroupName, err) + return fmt.Errorf("error creating EKS Node Group (%s): %w", id, err) } - d.SetId(tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName)) + d.SetId(id) - stateConf := resource.StateChangeConf{ - Pending: []string{eks.NodegroupStatusCreating}, - Target: []string{eks.NodegroupStatusActive}, - Timeout: d.Timeout(schema.TimeoutCreate), - Refresh: refreshEksNodeGroupStatus(conn, clusterName, nodeGroupName), - } + _, err = waiter.NodegroupCreated(conn, clusterName, nodeGroupName, d.Timeout(schema.TimeoutCreate)) - if _, err := stateConf.WaitForState(); err != nil { - return fmt.Errorf("error waiting for EKS Node Group (%s) creation: %w", d.Id(), err) + if err != nil { + return fmt.Errorf("error waiting for EKS Node Groupe (%s) to create: %w", d.Id(), err) } return resourceAwsEksNodeGroupRead(d, meta) @@ -348,14 +348,9 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error return err } - input := &eks.DescribeNodegroupInput{ - ClusterName: aws.String(clusterName), - NodegroupName: aws.String(nodeGroupName), - } - - output, err := conn.DescribeNodegroup(input) + nodeGroup, err := finder.NodegroupByClusterNameAndNodegroupName(conn, clusterName, nodeGroupName) - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] EKS Node Group (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -365,13 +360,6 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error reading EKS Node Group (%s): %w", d.Id(), err) } - nodeGroup := output.Nodegroup - if nodeGroup == nil { - log.Printf("[WARN] EKS Node Group (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - d.Set("ami_type", nodeGroup.AmiType) d.Set("arn", nodeGroup.NodegroupArn) d.Set("capacity_type", nodeGroup.CapacityType) @@ -413,6 +401,12 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error setting subnets: %w", err) } + if err := d.Set("taint", flattenEksTaints(nodeGroup.Taints)); err != nil { + return fmt.Errorf("error setting taint: %w", err) + } + + d.Set("version", nodeGroup.Version) + tags := keyvaluetags.EksKeyValueTags(nodeGroup.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 @@ -424,12 +418,6 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error setting tags_all: %w", err) } - if err := d.Set("taint", flattenEksTaints(nodeGroup.Taints)); err != nil { - return fmt.Errorf("error setting taint: %w", err) - } - - d.Set("version", nodeGroup.Version) - return nil } @@ -442,41 +430,7 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err return err } - if d.HasChanges("labels", "scaling_config", "taint") { - oldLabelsRaw, newLabelsRaw := d.GetChange("labels") - - input := &eks.UpdateNodegroupConfigInput{ - ClientRequestToken: aws.String(resource.UniqueId()), - ClusterName: aws.String(clusterName), - Labels: expandEksUpdateLabelsPayload(oldLabelsRaw, newLabelsRaw), - NodegroupName: aws.String(nodeGroupName), - } - - if v := d.Get("scaling_config").([]interface{}); len(v) > 0 { - input.ScalingConfig = expandEksNodegroupScalingConfig(v) - } - - oldTaintsRaw, newTaintsRaw := d.GetChange("taint") - input.Taints = expandEksUpdateTaintsPayload(oldTaintsRaw.(*schema.Set).List(), newTaintsRaw.(*schema.Set).List()) - - output, err := conn.UpdateNodegroupConfig(input) - - if err != nil { - return fmt.Errorf("error updating EKS Node Group (%s) config: %w", d.Id(), err) - } - - if output == nil || output.Update == nil || output.Update.Id == nil { - return fmt.Errorf("error determining EKS Node Group (%s) config update ID: empty response", d.Id()) - } - - updateID := aws.StringValue(output.Update.Id) - - err = waitForEksNodeGroupUpdate(conn, clusterName, nodeGroupName, updateID, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf("error waiting for EKS Node Group (%s) config update (%s): %w", d.Id(), updateID, err) - } - } - + // Do any version update first. if d.HasChanges("launch_template", "release_version", "version") { input := &eks.UpdateNodegroupVersionInput{ ClientRequestToken: aws.String(resource.UniqueId()), @@ -519,15 +473,44 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("error updating EKS Node Group (%s) version: %w", d.Id(), err) } - if output == nil || output.Update == nil || output.Update.Id == nil { - return fmt.Errorf("error determining EKS Node Group (%s) version update ID: empty response", d.Id()) + updateID := aws.StringValue(output.Update.Id) + + _, err = waiter.NodegroupUpdateSuccessful(conn, clusterName, nodeGroupName, updateID, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("error waiting for EKS Node Group (%s) version update (%s): %w", d.Id(), updateID, err) + } + } + + if d.HasChanges("labels", "scaling_config", "taint") { + oldLabelsRaw, newLabelsRaw := d.GetChange("labels") + + input := &eks.UpdateNodegroupConfigInput{ + ClientRequestToken: aws.String(resource.UniqueId()), + ClusterName: aws.String(clusterName), + Labels: expandEksUpdateLabelsPayload(oldLabelsRaw, newLabelsRaw), + NodegroupName: aws.String(nodeGroupName), + } + + if v := d.Get("scaling_config").([]interface{}); len(v) > 0 { + input.ScalingConfig = expandEksNodegroupScalingConfig(v) + } + + oldTaintsRaw, newTaintsRaw := d.GetChange("taint") + input.Taints = expandEksUpdateTaintsPayload(oldTaintsRaw.(*schema.Set).List(), newTaintsRaw.(*schema.Set).List()) + + output, err := conn.UpdateNodegroupConfig(input) + + if err != nil { + return fmt.Errorf("error updating EKS Node Group (%s) config: %w", d.Id(), err) } updateID := aws.StringValue(output.Update.Id) - err = waitForEksNodeGroupUpdate(conn, clusterName, nodeGroupName, updateID, d.Timeout(schema.TimeoutUpdate)) + _, err = waiter.NodegroupUpdateSuccessful(conn, clusterName, nodeGroupName, updateID, d.Timeout(schema.TimeoutUpdate)) + if err != nil { - return fmt.Errorf("error waiting for EKS Node Group (%s) version update (%s): %w", d.Id(), updateID, err) + return fmt.Errorf("error waiting for EKS Node Group (%s) config update (%s): %w", d.Id(), updateID, err) } } @@ -550,14 +533,13 @@ func resourceAwsEksNodeGroupDelete(d *schema.ResourceData, meta interface{}) err return err } - input := &eks.DeleteNodegroupInput{ + log.Printf("[DEBUG] Deleting EKS Node Group: %s", d.Id()) + _, err = conn.DeleteNodegroup(&eks.DeleteNodegroupInput{ ClusterName: aws.String(clusterName), NodegroupName: aws.String(nodeGroupName), - } + }) - _, err = conn.DeleteNodegroup(input) - - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { return nil } @@ -565,8 +547,10 @@ func resourceAwsEksNodeGroupDelete(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("error deleting EKS Node Group (%s): %w", d.Id(), err) } - if err := waitForEksNodeGroupDeletion(conn, clusterName, nodeGroupName, d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("error waiting for EKS Node Group (%s) deletion: %w", d.Id(), err) + _, err = waiter.NodegroupDeleted(conn, clusterName, nodeGroupName, d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return fmt.Errorf("error waiting for EKS Node Group (%s) to delete: %w", d.Id(), err) } return nil @@ -868,114 +852,3 @@ func flattenEksTaints(taints []*eks.Taint) []interface{} { } return results } - -func refreshEksNodeGroupStatus(conn *eks.EKS, clusterName string, nodeGroupName string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - input := &eks.DescribeNodegroupInput{ - ClusterName: aws.String(clusterName), - NodegroupName: aws.String(nodeGroupName), - } - - output, err := conn.DescribeNodegroup(input) - - if err != nil { - return "", "", err - } - - nodeGroup := output.Nodegroup - - if nodeGroup == nil { - return nodeGroup, "", fmt.Errorf("EKS Node Group (%s) missing", tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName)) - } - - status := aws.StringValue(nodeGroup.Status) - - // Return enhanced error messaging if available, instead of: - // unexpected state 'CREATE_FAILED', wanted target 'ACTIVE'. last error: %!s() - if status == eks.NodegroupStatusCreateFailed || status == eks.NodegroupStatusDeleteFailed { - if nodeGroup.Health == nil || len(nodeGroup.Health.Issues) == 0 || nodeGroup.Health.Issues[0] == nil { - return nodeGroup, status, fmt.Errorf("unable to find additional information about %s status, check EKS Node Group (%s) health", status, tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName)) - } - - issue := nodeGroup.Health.Issues[0] - - return nodeGroup, status, fmt.Errorf("%s: %s. Resource IDs: %v", aws.StringValue(issue.Code), aws.StringValue(issue.Message), aws.StringValueSlice(issue.ResourceIds)) - } - - return nodeGroup, status, nil - } -} - -func refreshEksNodeGroupUpdateStatus(conn *eks.EKS, clusterName string, nodeGroupName string, updateID string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - input := &eks.DescribeUpdateInput{ - Name: aws.String(clusterName), - NodegroupName: aws.String(nodeGroupName), - UpdateId: aws.String(updateID), - } - - output, err := conn.DescribeUpdate(input) - - if err != nil { - return nil, "", err - } - - if output == nil || output.Update == nil { - return nil, "", fmt.Errorf("EKS Node Group (%s) update (%s) missing", tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName), updateID) - } - - return output.Update, aws.StringValue(output.Update.Status), nil - } -} - -func waitForEksNodeGroupDeletion(conn *eks.EKS, clusterName string, nodeGroupName string, timeout time.Duration) error { - stateConf := resource.StateChangeConf{ - Pending: []string{ - eks.NodegroupStatusActive, - eks.NodegroupStatusDeleting, - }, - Target: []string{""}, - Timeout: timeout, - Refresh: refreshEksNodeGroupStatus(conn, clusterName, nodeGroupName), - } - - _, err := stateConf.WaitForState() - - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - return nil - } - - return err -} - -func waitForEksNodeGroupUpdate(conn *eks.EKS, clusterName, nodeGroupName string, updateID string, timeout time.Duration) error { - stateConf := resource.StateChangeConf{ - Pending: []string{eks.UpdateStatusInProgress}, - Target: []string{ - eks.UpdateStatusCancelled, - eks.UpdateStatusFailed, - eks.UpdateStatusSuccessful, - }, - Timeout: timeout, - Refresh: refreshEksNodeGroupUpdateStatus(conn, clusterName, nodeGroupName, updateID), - } - - updateRaw, err := stateConf.WaitForState() - - if err != nil { - return err - } - - update := updateRaw.(*eks.Update) - - if aws.StringValue(update.Status) == eks.UpdateStatusSuccessful { - return nil - } - - var detailedErrors []string - for i, updateError := range update.Errors { - detailedErrors = append(detailedErrors, fmt.Sprintf("Error %d: Code: %s / Message: %s", i+1, aws.StringValue(updateError.ErrorCode), aws.StringValue(updateError.ErrorMessage))) - } - - return fmt.Errorf("EKS Node Group (%s) update (%s) status (%s) not successful: Errors:\n%s", clusterName, updateID, aws.StringValue(update.Status), strings.Join(detailedErrors, "\n")) -} diff --git a/aws/resource_aws_eks_node_group_test.go b/aws/resource_aws_eks_node_group_test.go index 927f63027014..90d5c2cc55cb 100644 --- a/aws/resource_aws_eks_node_group_test.go +++ b/aws/resource_aws_eks_node_group_test.go @@ -5,7 +5,6 @@ import ( "log" "regexp" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" @@ -15,6 +14,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -28,64 +29,64 @@ func init() { func testSweepEksNodeGroups(region string) error { client, err := sharedClientForRegion(region) - if err != nil { return fmt.Errorf("error getting client: %w", err) } - conn := client.(*AWSClient).eksconn - sweepResources := make([]*testSweepResource, 0) - var errs *multierror.Error - input := &eks.ListClustersInput{} + var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) err = conn.ListClustersPages(input, func(page *eks.ListClustersOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + for _, cluster := range page.Clusters { - clusterName := aws.StringValue(cluster) input := &eks.ListNodegroupsInput{ ClusterName: cluster, } err := conn.ListNodegroupsPages(input, func(page *eks.ListNodegroupsOutput, lastPage bool) bool { - for _, nodeGroup := range page.Nodegroups { - nodeGroupName := aws.StringValue(nodeGroup) + if page == nil { + return !lastPage + } + for _, nodeGroup := range page.Nodegroups { r := resourceAwsEksNodeGroup() d := r.Data(nil) - - d.Set("cluster_name", clusterName) - d.Set("node_group_name", nodeGroupName) - d.SetId(tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName)) + d.SetId(tfeks.NodeGroupCreateResourceID(aws.StringValue(cluster), aws.StringValue(nodeGroup))) sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } + return !lastPage }) if err != nil { - errs = multierror.Append(errs, fmt.Errorf("error listing EKS Node Groups: %w", err)) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Node Groups (%s): %w", region, err)) } } return !lastPage }) - if err != nil { - errs = multierror.Append(errs, fmt.Errorf("error listing EKS Clusters: %w", err)) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping EKS Node Groups sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors } - if err = testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping EKS Node Groups for %s: %w", region, err)) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Clusters (%s): %w", region, err)) } - // waiting for deletion is not necessary in the sweeper since the resource's delete waits + err = testSweepResourceOrchestrator(sweepResources) - if testSweepSkipSweepError(errs.ErrorOrNil()) { - log.Printf("[WARN] Skipping EKS Node Group sweep for %s: %s", region, errs) - return nil + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping EKS Node Groups (%s): %w", region, err)) } - return errs.ErrorOrNil() + return sweeperErrs.ErrorOrNil() } func TestAccAWSEksNodeGroup_basic(t *testing.T) { @@ -210,7 +211,7 @@ func TestAccAWSEksNodeGroup_disappears(t *testing.T) { Config: testAccAWSEksNodeGroupConfigNodeGroupName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup), - testAccCheckAWSEksNodeGroupDisappears(&nodeGroup), + testAccCheckResourceDisappears(testAccProvider, resourceAwsEksNodeGroup(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -986,36 +987,20 @@ func testAccCheckAWSEksNodeGroupExists(resourceName string, nodeGroup *eks.Nodeg } clusterName, nodeGroupName, err := tfeks.NodeGroupParseResourceID(rs.Primary.ID) + if err != nil { return err } conn := testAccProvider.Meta().(*AWSClient).eksconn - input := &eks.DescribeNodegroupInput{ - ClusterName: aws.String(clusterName), - NodegroupName: aws.String(nodeGroupName), - } - - output, err := conn.DescribeNodegroup(input) + output, err := finder.NodegroupByClusterNameAndNodegroupName(conn, clusterName, nodeGroupName) if err != nil { return err } - if output == nil || output.Nodegroup == nil { - return fmt.Errorf("EKS Node Group (%s) not found", rs.Primary.ID) - } - - if aws.StringValue(output.Nodegroup.NodegroupName) != nodeGroupName { - return fmt.Errorf("EKS Node Group (%s) not found", rs.Primary.ID) - } - - if got, want := aws.StringValue(output.Nodegroup.Status), eks.NodegroupStatusActive; got != want { - return fmt.Errorf("EKS Node Group (%s) not in %s status, got: %s", rs.Primary.ID, want, got) - } - - *nodeGroup = *output.Nodegroup + *nodeGroup = *output return nil } @@ -1030,50 +1015,25 @@ func testAccCheckAWSEksNodeGroupDestroy(s *terraform.State) error { } clusterName, nodeGroupName, err := tfeks.NodeGroupParseResourceID(rs.Primary.ID) + if err != nil { return err } - input := &eks.DescribeNodegroupInput{ - ClusterName: aws.String(clusterName), - NodegroupName: aws.String(nodeGroupName), - } - - output, err := conn.DescribeNodegroup(input) + _, err = finder.NodegroupByClusterNameAndNodegroupName(conn, clusterName, nodeGroupName) - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + if tfresource.NotFound(err) { continue } - if output != nil && output.Nodegroup != nil && aws.StringValue(output.Nodegroup.NodegroupName) == nodeGroupName { - return fmt.Errorf("EKS Node Group (%s) still exists", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckAWSEksNodeGroupDisappears(nodeGroup *eks.Nodegroup) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).eksconn - - input := &eks.DeleteNodegroupInput{ - ClusterName: nodeGroup.ClusterName, - NodegroupName: nodeGroup.NodegroupName, - } - - _, err := conn.DeleteNodegroup(input) - - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - return nil - } - if err != nil { return err } - return waitForEksNodeGroupDeletion(conn, aws.StringValue(nodeGroup.ClusterName), aws.StringValue(nodeGroup.NodegroupName), 60*time.Minute) + return fmt.Errorf("EKS Node Group %s still exists", rs.Primary.ID) } + + return nil } func testAccCheckAWSEksNodeGroupNotRecreated(i, j *eks.Nodegroup) resource.TestCheckFunc { From 81a9cf6141650bb7a94da65d6de64e7151da651a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 20 Jun 2021 18:36:40 -0400 Subject: [PATCH 0640/1208] EKS updates are per resource type. --- aws/internal/service/eks/finder/finder.go | 48 ++++++++++----------- aws/internal/service/eks/waiter/status.go | 16 +++---- aws/internal/service/eks/waiter/waiter.go | 52 +++++++++++------------ aws/resource_aws_eks_cluster.go | 8 ++-- 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/aws/internal/service/eks/finder/finder.go b/aws/internal/service/eks/finder/finder.go index ce9bb7586c69..2c27bdca3c0c 100644 --- a/aws/internal/service/eks/finder/finder.go +++ b/aws/internal/service/eks/finder/finder.go @@ -37,13 +37,13 @@ func ClusterByName(conn *eks.EKS, name string) (*eks.Cluster, error) { return output.Cluster, nil } -func FargateProfileByClusterNameAndFargateProfileName(conn *eks.EKS, clusterName, fargateProfileName string) (*eks.FargateProfile, error) { - input := &eks.DescribeFargateProfileInput{ - ClusterName: aws.String(clusterName), - FargateProfileName: aws.String(fargateProfileName), +func ClusterUpdateByNameAndID(conn *eks.EKS, name, id string) (*eks.Update, error) { + input := &eks.DescribeUpdateInput{ + Name: aws.String(name), + UpdateId: aws.String(id), } - output, err := conn.DescribeFargateProfile(input) + output, err := conn.DescribeUpdate(input) if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { return nil, &resource.NotFoundError{ @@ -56,23 +56,23 @@ func FargateProfileByClusterNameAndFargateProfileName(conn *eks.EKS, clusterName return nil, err } - if output == nil || output.FargateProfile == nil { + if output == nil || output.Update == nil { return nil, &resource.NotFoundError{ Message: "Empty result", LastRequest: input, } } - return output.FargateProfile, nil + return output.Update, nil } -func NodegroupByClusterNameAndNodegroupName(conn *eks.EKS, clusterName, nodeGroupName string) (*eks.Nodegroup, error) { - input := &eks.DescribeNodegroupInput{ - ClusterName: aws.String(clusterName), - NodegroupName: aws.String(nodeGroupName), +func FargateProfileByClusterNameAndFargateProfileName(conn *eks.EKS, clusterName, fargateProfileName string) (*eks.FargateProfile, error) { + input := &eks.DescribeFargateProfileInput{ + ClusterName: aws.String(clusterName), + FargateProfileName: aws.String(fargateProfileName), } - output, err := conn.DescribeNodegroup(input) + output, err := conn.DescribeFargateProfile(input) if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { return nil, &resource.NotFoundError{ @@ -85,24 +85,23 @@ func NodegroupByClusterNameAndNodegroupName(conn *eks.EKS, clusterName, nodeGrou return nil, err } - if output == nil || output.Nodegroup == nil { + if output == nil || output.FargateProfile == nil { return nil, &resource.NotFoundError{ Message: "Empty result", LastRequest: input, } } - return output.Nodegroup, nil + return output.FargateProfile, nil } -func NodegroupUpdateByClusterNameNodegroupNameAndID(conn *eks.EKS, clusterName, nodeGroupName, id string) (*eks.Update, error) { - input := &eks.DescribeUpdateInput{ - Name: aws.String(clusterName), +func NodegroupByClusterNameAndNodegroupName(conn *eks.EKS, clusterName, nodeGroupName string) (*eks.Nodegroup, error) { + input := &eks.DescribeNodegroupInput{ + ClusterName: aws.String(clusterName), NodegroupName: aws.String(nodeGroupName), - UpdateId: aws.String(id), } - output, err := conn.DescribeUpdate(input) + output, err := conn.DescribeNodegroup(input) if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { return nil, &resource.NotFoundError{ @@ -115,20 +114,21 @@ func NodegroupUpdateByClusterNameNodegroupNameAndID(conn *eks.EKS, clusterName, return nil, err } - if output == nil || output.Update == nil { + if output == nil || output.Nodegroup == nil { return nil, &resource.NotFoundError{ Message: "Empty result", LastRequest: input, } } - return output.Update, nil + return output.Nodegroup, nil } -func UpdateByNameAndID(conn *eks.EKS, name, id string) (*eks.Update, error) { +func NodegroupUpdateByClusterNameNodegroupNameAndID(conn *eks.EKS, clusterName, nodeGroupName, id string) (*eks.Update, error) { input := &eks.DescribeUpdateInput{ - Name: aws.String(name), - UpdateId: aws.String(id), + Name: aws.String(clusterName), + NodegroupName: aws.String(nodeGroupName), + UpdateId: aws.String(id), } output, err := conn.DescribeUpdate(input) diff --git a/aws/internal/service/eks/waiter/status.go b/aws/internal/service/eks/waiter/status.go index 59b63250314a..572bd1f84e42 100644 --- a/aws/internal/service/eks/waiter/status.go +++ b/aws/internal/service/eks/waiter/status.go @@ -28,9 +28,9 @@ func ClusterStatus(conn *eks.EKS, name string) resource.StateRefreshFunc { } } -func FargateProfileStatus(conn *eks.EKS, clusterName, fargateProfileName string) resource.StateRefreshFunc { +func ClusterUpdateStatus(conn *eks.EKS, name, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := finder.FargateProfileByClusterNameAndFargateProfileName(conn, clusterName, fargateProfileName) + output, err := finder.ClusterUpdateByNameAndID(conn, name, id) if tfresource.NotFound(err) { return nil, "", nil @@ -44,9 +44,9 @@ func FargateProfileStatus(conn *eks.EKS, clusterName, fargateProfileName string) } } -func NodegroupStatus(conn *eks.EKS, clusterName, nodeGroupName string) resource.StateRefreshFunc { +func FargateProfileStatus(conn *eks.EKS, clusterName, fargateProfileName string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := finder.NodegroupByClusterNameAndNodegroupName(conn, clusterName, nodeGroupName) + output, err := finder.FargateProfileByClusterNameAndFargateProfileName(conn, clusterName, fargateProfileName) if tfresource.NotFound(err) { return nil, "", nil @@ -60,9 +60,9 @@ func NodegroupStatus(conn *eks.EKS, clusterName, nodeGroupName string) resource. } } -func NodegroupUpdateStatus(conn *eks.EKS, clusterName, nodeGroupName, id string) resource.StateRefreshFunc { +func NodegroupStatus(conn *eks.EKS, clusterName, nodeGroupName string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := finder.NodegroupUpdateByClusterNameNodegroupNameAndID(conn, clusterName, nodeGroupName, id) + output, err := finder.NodegroupByClusterNameAndNodegroupName(conn, clusterName, nodeGroupName) if tfresource.NotFound(err) { return nil, "", nil @@ -76,9 +76,9 @@ func NodegroupUpdateStatus(conn *eks.EKS, clusterName, nodeGroupName, id string) } } -func UpdateStatus(conn *eks.EKS, name, id string) resource.StateRefreshFunc { +func NodegroupUpdateStatus(conn *eks.EKS, clusterName, nodeGroupName, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := finder.UpdateByNameAndID(conn, name, id) + output, err := finder.NodegroupUpdateByClusterNameNodegroupNameAndID(conn, clusterName, nodeGroupName, id) if tfresource.NotFound(err) { return nil, "", nil diff --git a/aws/internal/service/eks/waiter/waiter.go b/aws/internal/service/eks/waiter/waiter.go index 4056d3cc003a..d4ae7299ff79 100644 --- a/aws/internal/service/eks/waiter/waiter.go +++ b/aws/internal/service/eks/waiter/waiter.go @@ -54,6 +54,32 @@ func ClusterDeleted(conn *eks.EKS, name string, timeout time.Duration) (*eks.Clu return nil, err } +func ClusterUpdateSuccessful(conn *eks.EKS, name, id string, timeout time.Duration) (*eks.Update, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{eks.UpdateStatusInProgress}, + Target: []string{eks.UpdateStatusSuccessful}, + Refresh: ClusterUpdateStatus(conn, name, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*eks.Update); ok { + if status := aws.StringValue(output.Status); status == eks.UpdateStatusCancelled || status == eks.UpdateStatusFailed { + var errs *multierror.Error + + for _, e := range output.Errors { + errs = multierror.Append(errs, fmt.Errorf("%s: %s", aws.StringValue(e.ErrorCode), aws.StringValue(e.ErrorMessage))) + } + tfresource.SetLastError(err, errs.ErrorOrNil()) + } + + return output, err + } + + return nil, err +} + func FargateProfileCreated(conn *eks.EKS, clusterName, fargateProfileName string, timeout time.Duration) (*eks.FargateProfile, error) { stateConf := &resource.StateChangeConf{ Pending: []string{eks.FargateProfileStatusCreating}, @@ -148,32 +174,6 @@ func NodegroupUpdateSuccessful(conn *eks.EKS, clusterName, nodeGroupName, id str return nil, err } -func UpdateSuccessful(conn *eks.EKS, name, id string, timeout time.Duration) (*eks.Update, error) { - stateConf := &resource.StateChangeConf{ - Pending: []string{eks.UpdateStatusInProgress}, - Target: []string{eks.UpdateStatusSuccessful}, - Refresh: UpdateStatus(conn, name, id), - Timeout: timeout, - } - - outputRaw, err := stateConf.WaitForState() - - if output, ok := outputRaw.(*eks.Update); ok { - if status := aws.StringValue(output.Status); status == eks.UpdateStatusCancelled || status == eks.UpdateStatusFailed { - var errs *multierror.Error - - for _, e := range output.Errors { - errs = multierror.Append(errs, fmt.Errorf("%s: %s", aws.StringValue(e.ErrorCode), aws.StringValue(e.ErrorMessage))) - } - tfresource.SetLastError(err, errs.ErrorOrNil()) - } - - return output, err - } - - return nil, err -} - // EksAddonCreated waits for a EKS add-on to return status "ACTIVE" or "CREATE_FAILED" func EksAddonCreated(ctx context.Context, conn *eks.EKS, clusterName, addonName string) (*eks.Addon, error) { stateConf := resource.StateChangeConf{ diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index fd0a6e4da6e2..83f552a55aea 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -400,7 +400,7 @@ func resourceAwsEksClusterUpdate(d *schema.ResourceData, meta interface{}) error updateID := aws.StringValue(output.Update.Id) - _, err = waiter.UpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + _, err = waiter.ClusterUpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) if err != nil { return fmt.Errorf("error waiting for EKS Cluster (%s) version update (%s): %w", d.Id(), updateID, err) @@ -422,7 +422,7 @@ func resourceAwsEksClusterUpdate(d *schema.ResourceData, meta interface{}) error updateID := aws.StringValue(output.Update.Id) - _, err = waiter.UpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + _, err = waiter.ClusterUpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) if err != nil { return fmt.Errorf("error waiting for EKS Cluster (%s) encryption config association (%s): %w", d.Id(), updateID, err) @@ -444,7 +444,7 @@ func resourceAwsEksClusterUpdate(d *schema.ResourceData, meta interface{}) error updateID := aws.StringValue(output.Update.Id) - _, err = waiter.UpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + _, err = waiter.ClusterUpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) if err != nil { return fmt.Errorf("error waiting for EKS Cluster (%s) logging update (%s): %w", d.Id(), updateID, err) @@ -466,7 +466,7 @@ func resourceAwsEksClusterUpdate(d *schema.ResourceData, meta interface{}) error updateID := aws.StringValue(output.Update.Id) - _, err = waiter.UpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + _, err = waiter.ClusterUpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) if err != nil { return fmt.Errorf("error waiting for EKS Cluster (%s) VPC config update (%s): %w", d.Id(), updateID, err) From a6baa478e4cda7a0b1c1c6ef5fa524fdfec7fae1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jun 2021 06:04:00 +0000 Subject: [PATCH 0641/1208] build(deps): bump hashicorp/github in /infrastructure/repository Bumps [hashicorp/github](https://github.com/hashicorp/terraform-provider-github) from 4.11.0 to 4.12.0. - [Release notes](https://github.com/hashicorp/terraform-provider-github/releases) - [Changelog](https://github.com/hashicorp/terraform-provider-github/blob/master/CHANGELOG.md) - [Commits](https://github.com/hashicorp/terraform-provider-github/commits) --- updated-dependencies: - dependency-name: hashicorp/github dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- infrastructure/repository/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/repository/main.tf b/infrastructure/repository/main.tf index 826dcb169b7f..ba3056ebd539 100644 --- a/infrastructure/repository/main.tf +++ b/infrastructure/repository/main.tf @@ -10,7 +10,7 @@ terraform { required_providers { github = { source = "hashicorp/github" - version = "4.11.0" + version = "4.12.0" } } From 01f604ccae82f5f2bf7d0669cd538e0874a442bd Mon Sep 17 00:00:00 2001 From: FrancescoFucile-CAZ Date: Mon, 21 Jun 2021 14:48:25 +0100 Subject: [PATCH 0642/1208] Fix documentation examples. --- .../cloudwatch_event_bus_policy.html.markdown | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/website/docs/r/cloudwatch_event_bus_policy.html.markdown b/website/docs/r/cloudwatch_event_bus_policy.html.markdown index 8118baae00e7..045043f8b892 100644 --- a/website/docs/r/cloudwatch_event_bus_policy.html.markdown +++ b/website/docs/r/cloudwatch_event_bus_policy.html.markdown @@ -27,7 +27,7 @@ data "aws_iam_policy_document" "test" { "events:PutEvents", ] resources = [ - "arn:aws:events:eu-west-1:111111111111:event-bus/default" + "arn:aws:events:eu-west-1:123456789012:event-bus/default" ] principals { @@ -38,7 +38,7 @@ data "aws_iam_policy_document" "test" { } resource "aws_cloudwatch_event_bus_policy" "test" { - policy = data.aws_iam_policy_document.access.json + policy = data.aws_iam_policy_document.test.json event_bus_name = aws_cloudwatch_event_bus.test.name } ``` @@ -57,8 +57,8 @@ data "aws_iam_policy_document" "test" { "events:ListTagsForResource", ] resources = [ - "arn:aws:events:eu-west-1:11111111111111:rule/*", - "arn:aws:events:eu-west-1:111111111111:event-bus/default" + "arn:aws:events:eu-west-1:123456789012:rule/*", + "arn:aws:events:eu-west-1:123456789012:event-bus/default" ] principals { @@ -75,7 +75,7 @@ data "aws_iam_policy_document" "test" { } resource "aws_cloudwatch_event_bus_policy" "test" { - policy = data.aws_iam_policy_document.access.json + policy = data.aws_iam_policy_document.test.json event_bus_name = aws_cloudwatch_event_bus.test.name } ``` @@ -92,7 +92,7 @@ data "aws_iam_policy_document" "test" { "events:PutEvents", ] resources = [ - "arn:aws:events:eu-west-1:111111111111:event-bus/default" + "arn:aws:events:eu-west-1:123456789012:event-bus/default" ] principals { @@ -111,8 +111,8 @@ data "aws_iam_policy_document" "test" { "events:ListTagsForResource", ] resources = [ - "arn:aws:events:eu-west-1:11111111111111:rule/*", - "arn:aws:events:eu-west-1:111111111111:event-bus/default" + "arn:aws:events:eu-west-1:123456789012:rule/*", + "arn:aws:events:eu-west-1:123456789012:event-bus/default" ] principals { @@ -129,7 +129,7 @@ data "aws_iam_policy_document" "test" { } resource "aws_cloudwatch_event_bus_policy" "test" { - policy = data.aws_iam_policy_document.access.json + policy = data.aws_iam_policy_document.test.json event_bus_name = aws_cloudwatch_event_bus.test.name } ``` From 21297ccd2d03357f287b450d29ed7171971e89a4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 21 Jun 2021 09:52:40 -0400 Subject: [PATCH 0643/1208] r/aws_eks_addon: Use internal waiter package. --- aws/internal/service/eks/finder/finder.go | 61 +++++++ aws/internal/service/eks/id.go | 19 ++ aws/internal/service/eks/waiter/status.go | 62 +++---- aws/internal/service/eks/waiter/waiter.go | 174 ++++++++---------- aws/resource_aws_eks_addon.go | 213 ++++++++++------------ aws/resource_aws_eks_addon_test.go | 130 ++++++------- 6 files changed, 338 insertions(+), 321 deletions(-) diff --git a/aws/internal/service/eks/finder/finder.go b/aws/internal/service/eks/finder/finder.go index 2c27bdca3c0c..8aef2b0ba6c0 100644 --- a/aws/internal/service/eks/finder/finder.go +++ b/aws/internal/service/eks/finder/finder.go @@ -1,12 +1,73 @@ package finder import ( + "context" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) +func AddonByClusterNameAndAddonName(ctx context.Context, conn *eks.EKS, clusterName, addonName string) (*eks.Addon, error) { + input := &eks.DescribeAddonInput{ + AddonName: aws.String(addonName), + ClusterName: aws.String(clusterName), + } + + output, err := conn.DescribeAddonWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Addon == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.Addon, nil +} + +func AddonUpdateByClusterNameAddonNameAndID(ctx context.Context, conn *eks.EKS, clusterName, addonName, id string) (*eks.Update, error) { + input := &eks.DescribeUpdateInput{ + AddonName: aws.String(addonName), + Name: aws.String(clusterName), + UpdateId: aws.String(id), + } + + output, err := conn.DescribeUpdateWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Update == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.Update, nil +} + func ClusterByName(conn *eks.EKS, name string) (*eks.Cluster, error) { input := &eks.DescribeClusterInput{ Name: aws.String(name), diff --git a/aws/internal/service/eks/id.go b/aws/internal/service/eks/id.go index 3fe8d2a776c2..8aec4cf9a3e5 100644 --- a/aws/internal/service/eks/id.go +++ b/aws/internal/service/eks/id.go @@ -5,6 +5,25 @@ import ( "strings" ) +const addonResourceIDSeparator = ":" + +func AddonCreateResourceID(clusterName, addonName string) string { + parts := []string{clusterName, addonName} + id := strings.Join(parts, addonResourceIDSeparator) + + return id +} + +func AddonParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, addonResourceIDSeparator) + + if len(parts) == 2 && parts[0] != "" && parts[1] != "" { + return parts[0], parts[1], nil + } + + return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected cluster-name%[2]saddon-name", id, addonResourceIDSeparator) +} + const fargateProfileResourceIDSeparator = ":" func FargateProfileCreateResourceID(clusterName, fargateProfileName string) string { diff --git a/aws/internal/service/eks/waiter/status.go b/aws/internal/service/eks/waiter/status.go index 572bd1f84e42..96a1a3daa46d 100644 --- a/aws/internal/service/eks/waiter/status.go +++ b/aws/internal/service/eks/waiter/status.go @@ -2,19 +2,17 @@ package waiter import ( "context" - "fmt" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" - "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -func ClusterStatus(conn *eks.EKS, name string) resource.StateRefreshFunc { +func AddonStatus(ctx context.Context, conn *eks.EKS, clusterName, addonName string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := finder.ClusterByName(conn, name) + output, err := finder.AddonByClusterNameAndAddonName(ctx, conn, clusterName, addonName) if tfresource.NotFound(err) { return nil, "", nil @@ -28,9 +26,9 @@ func ClusterStatus(conn *eks.EKS, name string) resource.StateRefreshFunc { } } -func ClusterUpdateStatus(conn *eks.EKS, name, id string) resource.StateRefreshFunc { +func AddonUpdateStatus(ctx context.Context, conn *eks.EKS, clusterName, addonName, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := finder.ClusterUpdateByNameAndID(conn, name, id) + output, err := finder.AddonUpdateByClusterNameAddonNameAndID(ctx, conn, clusterName, addonName, id) if tfresource.NotFound(err) { return nil, "", nil @@ -44,9 +42,9 @@ func ClusterUpdateStatus(conn *eks.EKS, name, id string) resource.StateRefreshFu } } -func FargateProfileStatus(conn *eks.EKS, clusterName, fargateProfileName string) resource.StateRefreshFunc { +func ClusterStatus(conn *eks.EKS, name string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := finder.FargateProfileByClusterNameAndFargateProfileName(conn, clusterName, fargateProfileName) + output, err := finder.ClusterByName(conn, name) if tfresource.NotFound(err) { return nil, "", nil @@ -60,9 +58,9 @@ func FargateProfileStatus(conn *eks.EKS, clusterName, fargateProfileName string) } } -func NodegroupStatus(conn *eks.EKS, clusterName, nodeGroupName string) resource.StateRefreshFunc { +func ClusterUpdateStatus(conn *eks.EKS, name, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := finder.NodegroupByClusterNameAndNodegroupName(conn, clusterName, nodeGroupName) + output, err := finder.ClusterUpdateByNameAndID(conn, name, id) if tfresource.NotFound(err) { return nil, "", nil @@ -76,9 +74,9 @@ func NodegroupStatus(conn *eks.EKS, clusterName, nodeGroupName string) resource. } } -func NodegroupUpdateStatus(conn *eks.EKS, clusterName, nodeGroupName, id string) resource.StateRefreshFunc { +func FargateProfileStatus(conn *eks.EKS, clusterName, fargateProfileName string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := finder.NodegroupUpdateByClusterNameNodegroupNameAndID(conn, clusterName, nodeGroupName, id) + output, err := finder.FargateProfileByClusterNameAndFargateProfileName(conn, clusterName, fargateProfileName) if tfresource.NotFound(err) { return nil, "", nil @@ -92,38 +90,34 @@ func NodegroupUpdateStatus(conn *eks.EKS, clusterName, nodeGroupName, id string) } } -func EksAddonStatus(ctx context.Context, conn *eks.EKS, addonName, clusterName string) resource.StateRefreshFunc { +func NodegroupStatus(conn *eks.EKS, clusterName, nodeGroupName string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := conn.DescribeAddonWithContext(ctx, &eks.DescribeAddonInput{ - ClusterName: aws.String(clusterName), - AddonName: aws.String(addonName), - }) - if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { + output, err := finder.NodegroupByClusterNameAndNodegroupName(conn, clusterName, nodeGroupName) + + if tfresource.NotFound(err) { return nil, "", nil } + if err != nil { - return output, "", err - } - if output == nil || output.Addon == nil { - return nil, "", fmt.Errorf("EKS Cluster (%s) add-on (%s) missing", clusterName, addonName) + return nil, "", err } - return output.Addon, aws.StringValue(output.Addon.Status), nil + + return output, aws.StringValue(output.Status), nil } } -func EksAddonUpdateStatus(ctx context.Context, conn *eks.EKS, clusterName, addonName, updateID string) resource.StateRefreshFunc { +func NodegroupUpdateStatus(conn *eks.EKS, clusterName, nodeGroupName, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := conn.DescribeUpdateWithContext(ctx, &eks.DescribeUpdateInput{ - Name: aws.String(clusterName), - AddonName: aws.String(addonName), - UpdateId: aws.String(updateID), - }) - if err != nil { - return output, "", err + output, err := finder.NodegroupUpdateByClusterNameNodegroupNameAndID(conn, clusterName, nodeGroupName, id) + + if tfresource.NotFound(err) { + return nil, "", nil } - if output == nil || output.Update == nil { - return nil, "", fmt.Errorf("EKS Cluster (%s) add-on (%s) update (%s) missing", clusterName, addonName, updateID) + + if err != nil { + return nil, "", err } - return output.Update, aws.StringValue(output.Update.Status), nil + + return output, aws.StringValue(output.Status), nil } } diff --git a/aws/internal/service/eks/waiter/waiter.go b/aws/internal/service/eks/waiter/waiter.go index d4ae7299ff79..171f55c27fee 100644 --- a/aws/internal/service/eks/waiter/waiter.go +++ b/aws/internal/service/eks/waiter/waiter.go @@ -3,23 +3,90 @@ package waiter import ( "context" "fmt" - "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" - "github.com/hashicorp/aws-sdk-go-base/tfawserr" multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( - EksAddonCreatedTimeout = 20 * time.Minute - EksAddonUpdatedTimeout = 20 * time.Minute - EksAddonDeletedTimeout = 40 * time.Minute + AddonCreatedTimeout = 20 * time.Minute + AddonUpdatedTimeout = 20 * time.Minute + AddonDeletedTimeout = 40 * time.Minute ) +func AddonCreated(ctx context.Context, conn *eks.EKS, clusterName, addonName string) (*eks.Addon, error) { + stateConf := resource.StateChangeConf{ + Pending: []string{eks.AddonStatusCreating}, + Target: []string{eks.AddonStatusActive}, + Refresh: AddonStatus(ctx, conn, clusterName, addonName), + Timeout: AddonCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*eks.Addon); ok { + if status, health := aws.StringValue(output.Status), output.Health; status == eks.AddonStatusCreateFailed && health != nil { + var errs *multierror.Error + + for _, issue := range health.Issues { + errs = multierror.Append(errs, fmt.Errorf("%s: %s", aws.StringValue(issue.Code), aws.StringValue(issue.Message))) + } + tfresource.SetLastError(err, errs.ErrorOrNil()) + } + + return output, err + } + + return nil, err +} + +func AddonDeleted(ctx context.Context, conn *eks.EKS, clusterName, addonName string) (*eks.Addon, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{eks.AddonStatusActive, eks.AddonStatusDeleting}, + Target: []string{}, + Refresh: AddonStatus(ctx, conn, clusterName, addonName), + Timeout: AddonDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*eks.Addon); ok { + return output, err + } + + return nil, err +} + +func AddonUpdateSuccessful(ctx context.Context, conn *eks.EKS, clusterName, addonName, id string) (*eks.Update, error) { + stateConf := resource.StateChangeConf{ + Pending: []string{eks.UpdateStatusInProgress}, + Target: []string{eks.UpdateStatusSuccessful}, + Refresh: AddonUpdateStatus(ctx, conn, clusterName, addonName, id), + Timeout: AddonUpdatedTimeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*eks.Update); ok { + if status := aws.StringValue(output.Status); status == eks.UpdateStatusCancelled || status == eks.UpdateStatusFailed { + var errs *multierror.Error + + for _, e := range output.Errors { + errs = multierror.Append(errs, fmt.Errorf("%s: %s", aws.StringValue(e.ErrorCode), aws.StringValue(e.ErrorMessage))) + } + tfresource.SetLastError(err, errs.ErrorOrNil()) + } + + return output, err + } + + return nil, err +} + func ClusterCreated(conn *eks.EKS, name string, timeout time.Duration) (*eks.Cluster, error) { stateConf := &resource.StateChangeConf{ Pending: []string{eks.ClusterStatusCreating}, @@ -173,100 +240,3 @@ func NodegroupUpdateSuccessful(conn *eks.EKS, clusterName, nodeGroupName, id str return nil, err } - -// EksAddonCreated waits for a EKS add-on to return status "ACTIVE" or "CREATE_FAILED" -func EksAddonCreated(ctx context.Context, conn *eks.EKS, clusterName, addonName string) (*eks.Addon, error) { - stateConf := resource.StateChangeConf{ - Pending: []string{eks.AddonStatusCreating}, - Target: []string{ - eks.AddonStatusActive, - eks.AddonStatusCreateFailed, - }, - Refresh: EksAddonStatus(ctx, conn, addonName, clusterName), - Timeout: EksAddonCreatedTimeout, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - - if addon, ok := outputRaw.(*eks.Addon); ok { - // If "CREATE_FAILED" status was returned, gather add-on health issues and return error - if aws.StringValue(addon.Status) == eks.AddonStatusCreateFailed { - var detailedErrors []string - for i, addonIssue := range addon.Health.Issues { - detailedErrors = append(detailedErrors, fmt.Sprintf("Error %d: Code: %s / Message: %s", - i+1, aws.StringValue(addonIssue.Code), aws.StringValue(addonIssue.Message))) - } - - return addon, fmt.Errorf("creation not successful (%s): Errors:\n%s", - aws.StringValue(addon.Status), strings.Join(detailedErrors, "\n")) - } - - return addon, err - } - - return nil, err -} - -// EksAddonDeleted waits for a EKS add-on to be deleted -func EksAddonDeleted(ctx context.Context, conn *eks.EKS, clusterName, addonName string) (*eks.Addon, error) { - stateConf := &resource.StateChangeConf{ - Pending: []string{ - eks.AddonStatusActive, - eks.AddonStatusDeleting, - }, - Target: []string{}, - Refresh: EksAddonStatus(ctx, conn, addonName, clusterName), - Timeout: EksAddonDeletedTimeout, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - if err != nil { - // EKS API returns the ResourceNotFound error in this form: - // ResourceNotFoundException: No addon: vpc-cni found in cluster: tf-acc-test-533189557170672934 - if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { - return nil, nil - } - } - if v, ok := outputRaw.(*eks.Addon); ok { - return v, err - } - - return nil, err -} - -// EksAddonUpdateSuccessful waits for a EKS add-on update to return "Successful" -func EksAddonUpdateSuccessful(ctx context.Context, conn *eks.EKS, clusterName, addonName, updateID string) (*eks.Update, error) { - stateConf := resource.StateChangeConf{ - Pending: []string{eks.UpdateStatusInProgress}, - Target: []string{ - eks.UpdateStatusCancelled, - eks.UpdateStatusFailed, - eks.UpdateStatusSuccessful, - }, - Refresh: EksAddonUpdateStatus(ctx, conn, clusterName, addonName, updateID), - Timeout: EksAddonUpdatedTimeout, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - if err != nil { - return nil, err - } - - update, ok := outputRaw.(*eks.Update) - if !ok { - return nil, err - } - - if aws.StringValue(update.Status) == eks.UpdateStatusSuccessful { - return nil, nil - } - - var detailedErrors []string - for i, updateError := range update.Errors { - detailedErrors = append(detailedErrors, fmt.Sprintf("Error %d: Code: %s / Message: %s", - i+1, aws.StringValue(updateError.ErrorCode), aws.StringValue(updateError.ErrorMessage))) - } - - return update, fmt.Errorf("EKS add-on (%s:%s) update (%s) not successful (%s): Errors:\n%s", - clusterName, addonName, updateID, aws.StringValue(update.Status), strings.Join(detailedErrors, "\n")) -} diff --git a/aws/resource_aws_eks_addon.go b/aws/resource_aws_eks_addon.go index cae762dc9a35..fb9b489ab8b9 100644 --- a/aws/resource_aws_eks_addon.go +++ b/aws/resource_aws_eks_addon.go @@ -5,17 +5,21 @@ import ( "fmt" "log" "regexp" - "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/waiter" + iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsEksAddon() *schema.Resource { @@ -38,16 +42,6 @@ func resourceAwsEksAddon() *schema.Resource { ForceNew: true, ValidateFunc: validation.NoZeroValues, }, - "cluster_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validateEKSClusterName, - }, - "arn": { - Type: schema.TypeString, - Computed: true, - }, "addon_version": { Type: schema.TypeString, Optional: true, @@ -57,15 +51,15 @@ func resourceAwsEksAddon() *schema.Resource { validation.StringMatch(regexp.MustCompile(`^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`), "must follow semantic version format"), ), }, - "service_account_role_arn": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateArn, + "arn": { + Type: schema.TypeString, + Computed: true, }, - "resolve_conflicts": { + "cluster_name": { Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(eks.ResolveConflicts_Values(), false), + Required: true, + ForceNew: true, + ValidateFunc: validateEKSClusterName, }, "created_at": { Type: schema.TypeString, @@ -75,6 +69,16 @@ func resourceAwsEksAddon() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "resolve_conflicts": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(eks.ResolveConflicts_Values(), false), + }, + "service_account_role_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), }, @@ -86,23 +90,24 @@ func resourceAwsEksAddonCreate(ctx context.Context, d *schema.ResourceData, meta defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) - clusterName := d.Get("cluster_name").(string) addonName := d.Get("addon_name").(string) + clusterName := d.Get("cluster_name").(string) + id := tfeks.AddonCreateResourceID(clusterName, addonName) input := &eks.CreateAddonInput{ - ClusterName: aws.String(clusterName), AddonName: aws.String(addonName), ClientRequestToken: aws.String(resource.UniqueId()), - } - - if v, ok := d.GetOk("resolve_conflicts"); ok { - input.ResolveConflicts = aws.String(v.(string)) + ClusterName: aws.String(clusterName), } if v, ok := d.GetOk("addon_version"); ok { input.AddonVersion = aws.String(v.(string)) } + if v, ok := d.GetOk("resolve_conflicts"); ok { + input.ResolveConflicts = aws.String(v.(string)) + } + if v, ok := d.GetOk("service_account_role_arn"); ok { input.ServiceAccountRoleArn = aws.String(v.(string)) } @@ -111,29 +116,36 @@ func resourceAwsEksAddonCreate(ctx context.Context, d *schema.ResourceData, meta input.Tags = tags.IgnoreAws().EksTags() } - err := resource.RetryContext(ctx, 1*time.Minute, func() *resource.RetryError { + err := resource.RetryContext(ctx, iamwaiter.PropagationTimeout, func() *resource.RetryError { _, err := conn.CreateAddonWithContext(ctx, input) + + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "CREATE_FAILED") { + return resource.RetryableError(err) + } + + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "does not exist") { + return resource.RetryableError(err) + } + if err != nil { - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "CREATE_FAILED") { - return resource.RetryableError(err) - } - if isAWSErr(err, eks.ErrCodeInvalidParameterException, "does not exist") { - return resource.RetryableError(err) - } return resource.NonRetryableError(err) } + return nil }) - if isResourceTimeoutError(err) { + + if tfresource.TimedOut(err) { _, err = conn.CreateAddonWithContext(ctx, input) } + if err != nil { - return diag.FromErr(fmt.Errorf("error creating EKS add-on (%s): %w", addonName, err)) + return diag.FromErr(fmt.Errorf("error creating EKS Add-On (%s): %w", id, err)) } - d.SetId(fmt.Sprintf("%s:%s", clusterName, addonName)) + d.SetId(id) + + _, err = waiter.AddonCreated(ctx, conn, clusterName, addonName) - _, err = waiter.EksAddonCreated(ctx, conn, clusterName, addonName) if err != nil { // Creating addon w/o setting resolve_conflicts to "OVERWRITE" // might result in a failed creation, if unmanaged version of addon is already deployed @@ -144,7 +156,7 @@ func resourceAwsEksAddonCreate(ctx context.Context, d *schema.ResourceData, meta // Re-creating like this will resolve the error, but it will also purge any // configurations that were applied by the user (that were conflicting). This might we an unwanted // side effect and should be left for the user to decide how to handle it. - return diag.FromErr(fmt.Errorf("unexpected EKS add-on (%s) state returned during creation: %w\n[WARNING] Running terraform apply again will remove the kubernetes add-on and attempt to create it again effectively purging previous add-on configuration", + return diag.FromErr(fmt.Errorf("unexpected EKS Add-On (%s) state returned during creation: %w\n[WARNING] Running terraform apply again will remove the kubernetes add-on and attempt to create it again effectively purging previous add-on configuration", d.Id(), err)) } @@ -156,41 +168,31 @@ func resourceAwsEksAddonRead(ctx context.Context, d *schema.ResourceData, meta i defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - clusterName, addonName, err := resourceAwsEksAddonParseId(d.Id()) + clusterName, addonName, err := tfeks.AddonParseResourceID(d.Id()) + if err != nil { return diag.FromErr(err) } - input := &eks.DescribeAddonInput{ - ClusterName: aws.String(clusterName), - AddonName: aws.String(addonName), - } - - log.Printf("[DEBUG] Reading EKS add-on: %s", d.Id()) - output, err := conn.DescribeAddonWithContext(ctx, input) - if err != nil { - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] EKS add-on (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - return diag.FromErr(fmt.Errorf("error reading EKS add-on (%s): %w", d.Id(), err)) - } + addon, err := finder.AddonByClusterNameAndAddonName(ctx, conn, clusterName, addonName) - addon := output.Addon - if addon == nil { - log.Printf("[WARN] EKS add-on (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] EKS Add-On (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - d.Set("cluster_name", addon.ClusterName) + if err != nil { + return diag.FromErr(fmt.Errorf("error reading EKS Add-On (%s): %w", d.Id(), err)) + } + d.Set("addon_name", addon.AddonName) - d.Set("arn", addon.AddonArn) d.Set("addon_version", addon.AddonVersion) - d.Set("service_account_role_arn", addon.ServiceAccountRoleArn) + d.Set("arn", addon.AddonArn) + d.Set("cluster_name", addon.ClusterName) d.Set("created_at", aws.TimeValue(addon.CreatedAt).Format(time.RFC3339)) d.Set("modified_at", aws.TimeValue(addon.ModifiedAt).Format(time.RFC3339)) + d.Set("service_account_role_arn", addon.ServiceAccountRoleArn) tags := keyvaluetags.EksKeyValueTags(addon.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -209,66 +211,60 @@ func resourceAwsEksAddonRead(ctx context.Context, d *schema.ResourceData, meta i func resourceAwsEksAddonUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).eksconn - clusterName, addonName, err := resourceAwsEksAddonParseId(d.Id()) + clusterName, addonName, err := tfeks.AddonParseResourceID(d.Id()) + if err != nil { return diag.FromErr(err) } - input := &eks.UpdateAddonInput{ - ClusterName: aws.String(clusterName), - AddonName: aws.String(addonName), - ClientRequestToken: aws.String(resource.UniqueId()), - } - - if d.HasChange("resolve_conflicts") { - if v, ok := d.GetOk("resolve_conflicts"); ok { - d.Set("resolve_conflicts", aws.String(v.(string))) + if d.HasChanges("addon_version", "service_account_role_arn") { + input := &eks.UpdateAddonInput{ + AddonName: aws.String(addonName), + ClientRequestToken: aws.String(resource.UniqueId()), + ClusterName: aws.String(clusterName), } - } - if v, ok := d.GetOk("resolve_conflicts"); ok { - input.ResolveConflicts = aws.String(v.(string)) - } - - if d.HasChange("tags_all") { - o, n := d.GetChange("tags_all") - if err := keyvaluetags.EksUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return diag.FromErr(fmt.Errorf("error updating tags: %w", err)) + if d.HasChange("addon_version") { + input.AddonVersion = aws.String(d.Get("addon_version").(string)) } - } - if d.HasChange("addon_version") { - input.AddonVersion = aws.String(d.Get("addon_version").(string)) - } + if v, ok := d.GetOk("resolve_conflicts"); ok { + input.ResolveConflicts = aws.String(v.(string)) + } - // If service account role ARN is already provided, use it. Otherwise, the add-on uses - // permissions assigned to the node IAM role. - if d.HasChange("service_account_role_arn") || d.Get("service_account_role_arn").(string) != "" { - input.ServiceAccountRoleArn = aws.String(d.Get("service_account_role_arn").(string)) - } + // If service account role ARN is already provided, use it. Otherwise, the add-on uses + // permissions assigned to the node IAM role. + if d.HasChange("service_account_role_arn") || d.Get("service_account_role_arn").(string) != "" { + input.ServiceAccountRoleArn = aws.String(d.Get("service_account_role_arn").(string)) + } - if d.HasChanges("addon_version", "service_account_role_arn") { output, err := conn.UpdateAddonWithContext(ctx, input) - if err != nil { - return diag.FromErr(fmt.Errorf("error updating EKS add-on (%s) version: %w", d.Id(), err)) - } - if output == nil || output.Update == nil || output.Update.Id == nil { - return diag.FromErr(fmt.Errorf("error determining EKS add-on (%s) version update ID: empty response", d.Id())) + if err != nil { + return diag.FromErr(fmt.Errorf("error updating EKS Add-On (%s): %w", d.Id(), err)) } updateID := aws.StringValue(output.Update.Id) - _, err = waiter.EksAddonUpdateSuccessful(ctx, conn, clusterName, addonName, updateID) + _, err = waiter.AddonUpdateSuccessful(ctx, conn, clusterName, addonName, updateID) + if err != nil { if d.Get("resolve_conflicts") != eks.ResolveConflictsOverwrite { // Changing addon version w/o setting resolve_conflicts to "OVERWRITE" // might result in a failed update if there are conflicts: // ConfigurationConflict Apply failed with 1 conflict: conflict with "kubectl"... - return diag.FromErr(fmt.Errorf("error waiting for EKS add-on (%s) update (%s): %w, consider setting attribute %q to %q", + return diag.FromErr(fmt.Errorf("error waiting for EKS Add-On (%s) update (%s): %w, consider setting attribute %q to %q", d.Id(), updateID, err, "resolve_conflicts", eks.ResolveConflictsOverwrite)) } - return diag.FromErr(fmt.Errorf("error waiting for EKS add-on (%s) update (%s): %w", d.Id(), updateID, err)) + + return diag.FromErr(fmt.Errorf("error waiting for EKS Add-On (%s) update (%s): %w", d.Id(), updateID, err)) + } + } + + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + if err := keyvaluetags.EksUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return diag.FromErr(fmt.Errorf("error updating tags: %w", err)) } } @@ -278,34 +274,27 @@ func resourceAwsEksAddonUpdate(ctx context.Context, d *schema.ResourceData, meta func resourceAwsEksAddonDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).eksconn - clusterName, addonName, err := resourceAwsEksAddonParseId(d.Id()) + clusterName, addonName, err := tfeks.AddonParseResourceID(d.Id()) + if err != nil { return diag.FromErr(err) } - input := &eks.DeleteAddonInput{ - ClusterName: aws.String(clusterName), + log.Printf("[DEBUG] Deleting EKS Add-On: %s", d.Id()) + _, err = conn.DeleteAddonWithContext(ctx, &eks.DeleteAddonInput{ AddonName: aws.String(addonName), - } + ClusterName: aws.String(clusterName), + }) - _, err = conn.DeleteAddonWithContext(ctx, input) if err != nil { - return diag.FromErr(fmt.Errorf("error deleting EKS add-on (%s): %w", d.Id(), err)) + return diag.FromErr(fmt.Errorf("error deleting EKS Add-On (%s): %w", d.Id(), err)) } - _, err = waiter.EksAddonDeleted(ctx, conn, clusterName, addonName) + _, err = waiter.AddonDeleted(ctx, conn, clusterName, addonName) + if err != nil { - return diag.FromErr(fmt.Errorf("error waiting for EKS add-on (%s) deletion: %w", d.Id(), err)) + return diag.FromErr(fmt.Errorf("error waiting for EKS Add-On (%s) to delete: %w", d.Id(), err)) } return nil } - -func resourceAwsEksAddonParseId(id string) (string, string, error) { - parts := strings.Split(id, ":") - if len(parts) != 2 { - return "", "", fmt.Errorf("unexpected format of ID (%s), expected cluster-name:addon-name", id) - } - - return parts[0], parts[1], nil -} diff --git a/aws/resource_aws_eks_addon_test.go b/aws/resource_aws_eks_addon_test.go index f79c68c52c7a..e436d0eae6da 100644 --- a/aws/resource_aws_eks_addon_test.go +++ b/aws/resource_aws_eks_addon_test.go @@ -6,18 +6,18 @@ import ( "log" "regexp" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" - "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/go-multierror" + multierror "github.com/hashicorp/go-multierror" "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/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/waiter" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -32,53 +32,59 @@ func testSweepEksAddon(region string) error { if err != nil { return fmt.Errorf("error getting client: %w", err) } - conn := client.(*AWSClient).eksconn ctx := context.TODO() + conn := client.(*AWSClient).eksconn + input := &eks.ListClustersInput{} var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) - input := &eks.ListClustersInput{MaxResults: aws.Int64(100)} err = conn.ListClustersPagesWithContext(ctx, input, func(page *eks.ListClustersOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + for _, cluster := range page.Clusters { - clusterName := aws.StringValue(cluster) input := &eks.ListAddonsInput{ - ClusterName: aws.String(clusterName), + ClusterName: cluster, } + err := conn.ListAddonsPagesWithContext(ctx, input, func(page *eks.ListAddonsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + for _, addon := range page.Addons { - addonName := aws.StringValue(addon) - log.Printf("[INFO] Deleting EKS Addon %s from Cluster %s", addonName, clusterName) - input := &eks.DeleteAddonInput{ - AddonName: aws.String(addonName), - ClusterName: aws.String(clusterName), - } - - _, err := conn.DeleteAddonWithContext(ctx, input) - - if err != nil && !tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error deleting EKS Addon %s from Cluster %s: %w", addonName, clusterName, err)) - continue - } - - if _, err := waiter.EksAddonDeleted(ctx, conn, clusterName, addonName); err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error waiting for EKS Addon %s deletion: %w", addonName, err)) - continue - } + r := resourceAwsEksAddon() + d := r.Data(nil) + d.SetId(tfeks.AddonCreateResourceID(aws.StringValue(cluster), aws.StringValue(addon))) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - return true + + return !lastPage }) + if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Addons for Cluster %s: %w", clusterName, err)) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Add-Ons (%s): %w", region, err)) } } - return true + return !lastPage }) + if testSweepSkipSweepError(err) { - log.Print(fmt.Errorf("[WARN] Skipping EKS Addon sweep for %s: %w", region, err)) + log.Print(fmt.Errorf("[WARN] Skipping EKS Add-Ons sweep for %s: %w", region, err)) return sweeperErrs // In case we have completed some pages, but had errors } + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Clusters (%s): %w", region, err)) + } + + err = testSweepResourceOrchestrator(sweepResources) + if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving EKS Clusters: %w", err)) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping EKS Add-Ons (%s): %w", region, err)) } return sweeperErrs.ErrorOrNil() @@ -717,40 +723,28 @@ func testAccCheckAWSEksAddonExists(ctx context.Context, resourceName string, add return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { - return fmt.Errorf("not found: %s", resourceName) + return fmt.Errorf("Not found: %s", resourceName) } if rs.Primary.ID == "" { - return fmt.Errorf("no EKS Addon ID is set") + return fmt.Errorf("no EKS Add-On ID is set") } - clusterName, addonName, err := resourceAwsEksAddonParseId(rs.Primary.ID) - if err != nil { - return err - } + clusterName, addonName, err := tfeks.AddonParseResourceID(rs.Primary.ID) - conn := testAccProvider.Meta().(*AWSClient).eksconn - output, err := conn.DescribeAddonWithContext(ctx, &eks.DescribeAddonInput{ - ClusterName: aws.String(clusterName), - AddonName: aws.String(addonName), - }) if err != nil { return err } - if output == nil || output.Addon == nil { - return fmt.Errorf("EKS Addon (%s) not found", rs.Primary.ID) - } + conn := testAccProvider.Meta().(*AWSClient).eksconn - if aws.StringValue(output.Addon.AddonName) != addonName { - return fmt.Errorf("EKS Addon (%s) not found", rs.Primary.ID) - } + output, err := finder.AddonByClusterNameAndAddonName(ctx, conn, clusterName, addonName) - if aws.StringValue(output.Addon.ClusterName) != clusterName { - return fmt.Errorf("EKS Addon (%s) not found", rs.Primary.ID) + if err != nil { + return err } - *addon = *output.Addon + *addon = *output return nil } @@ -758,40 +752,30 @@ func testAccCheckAWSEksAddonExists(ctx context.Context, resourceName string, add func testAccCheckAWSEksAddonDestroy(s *terraform.State) error { ctx := context.TODO() + conn := testAccProvider.Meta().(*AWSClient).eksconn + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_eks_addon" { continue } - clusterName, addonName, err := resourceAwsEksAddonParseId(rs.Primary.ID) + clusterName, addonName, err := tfeks.AddonParseResourceID(rs.Primary.ID) + if err != nil { return err } - conn := testAccProvider.Meta().(*AWSClient).eksconn - - // Handle eventual consistency - err = resource.RetryContext(ctx, 1*time.Minute, func() *resource.RetryError { - output, err := conn.DescribeAddonWithContext(ctx, &eks.DescribeAddonInput{ - AddonName: aws.String(addonName), - ClusterName: aws.String(clusterName), - }) - - if err != nil { - if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { - return nil - } - return resource.NonRetryableError(err) - } + _, err = finder.AddonByClusterNameAndAddonName(ctx, conn, clusterName, addonName) - if output != nil && output.Addon != nil && aws.StringValue(output.Addon.AddonName) == addonName { - return resource.RetryableError(fmt.Errorf("EKS Addon (%s) still exists", rs.Primary.ID)) - } + if tfresource.NotFound(err) { + continue + } - return nil - }) + if err != nil { + return err + } - return err + return fmt.Errorf("EKS Node Group %s still exists", rs.Primary.ID) } return nil From 5feb7af24c949c2e13fa14d84e9e11b4780774e1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 21 Jun 2021 10:01:35 -0400 Subject: [PATCH 0644/1208] d/aws_eks_addon: Use internal finder package. --- aws/data_source_aws_eks_addon.go | 45 ++++++++++++++------------------ 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/aws/data_source_aws_eks_addon.go b/aws/data_source_aws_eks_addon.go index 28e5b7b81127..676ee8c89e57 100644 --- a/aws/data_source_aws_eks_addon.go +++ b/aws/data_source_aws_eks_addon.go @@ -6,11 +6,12 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/eks" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "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" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" ) func dataSourceAwsEksAddon() *schema.Resource { @@ -22,23 +23,19 @@ func dataSourceAwsEksAddon() *schema.Resource { Required: true, ValidateFunc: validation.NoZeroValues, }, - "cluster_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateEKSClusterName, - }, - "arn": { - Type: schema.TypeString, - Computed: true, - }, "addon_version": { Type: schema.TypeString, Computed: true, }, - "service_account_role_arn": { + "arn": { Type: schema.TypeString, Computed: true, }, + "cluster_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateEKSClusterName, + }, "created_at": { Type: schema.TypeString, Computed: true, @@ -47,6 +44,10 @@ func dataSourceAwsEksAddon() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "service_account_role_arn": { + Type: schema.TypeString, + Computed: true, + }, "tags": tagsSchemaComputed(), }, } @@ -58,31 +59,23 @@ func dataSourceAwsEksAddonRead(ctx context.Context, d *schema.ResourceData, meta addonName := d.Get("addon_name").(string) clusterName := d.Get("cluster_name").(string) + id := tfeks.AddonCreateResourceID(clusterName, addonName) - input := &eks.DescribeAddonInput{ - AddonName: aws.String(addonName), - ClusterName: aws.String(clusterName), - } + addon, err := finder.AddonByClusterNameAndAddonName(ctx, conn, clusterName, addonName) - output, err := conn.DescribeAddonWithContext(ctx, input) if err != nil { - return diag.FromErr(fmt.Errorf("error reading EKS Addon (%s): %w", addonName, err)) + return diag.FromErr(fmt.Errorf("error reading EKS Add-On (%s): %w", id, err)) } - addon := output.Addon - if addon == nil { - return diag.FromErr(fmt.Errorf("EKS Addon (%s) not found", addonName)) - } - - d.SetId(fmt.Sprintf("%s:%s", clusterName, addonName)) - d.Set("arn", addon.AddonArn) + d.SetId(id) d.Set("addon_version", addon.AddonVersion) - d.Set("service_account_role_arn", addon.ServiceAccountRoleArn) + d.Set("arn", addon.AddonArn) d.Set("created_at", aws.TimeValue(addon.CreatedAt).Format(time.RFC3339)) d.Set("modified_at", aws.TimeValue(addon.ModifiedAt).Format(time.RFC3339)) + d.Set("service_account_role_arn", addon.ServiceAccountRoleArn) if err := d.Set("tags", keyvaluetags.EksKeyValueTags(addon.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return diag.FromErr(fmt.Errorf("error setting tags attribute: %w", err)) + return diag.FromErr(fmt.Errorf("error setting tags: %w", err)) } return nil From d0c797c64401e29a69907e42d3246d61b6e39961 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 21 Jun 2021 10:08:52 -0400 Subject: [PATCH 0645/1208] d/aws_eks_cluster: Use internal finder package. --- aws/data_source_aws_eks_cluster.go | 43 ++++++++++++------------------ 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/aws/data_source_aws_eks_cluster.go b/aws/data_source_aws_eks_cluster.go index f933d2fee3bd..6fc5f3877624 100644 --- a/aws/data_source_aws_eks_cluster.go +++ b/aws/data_source_aws_eks_cluster.go @@ -2,12 +2,11 @@ package aws import ( "fmt" - "log" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/eks" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" ) func dataSourceAwsEksCluster() *schema.Resource { @@ -95,6 +94,10 @@ func dataSourceAwsEksCluster() *schema.Resource { Computed: true, }, "tags": tagsSchemaComputed(), + "version": { + Type: schema.TypeString, + Computed: true, + }, "vpc_config": { Type: schema.TypeList, Computed: true, @@ -112,17 +115,17 @@ func dataSourceAwsEksCluster() *schema.Resource { Type: schema.TypeBool, Computed: true, }, - "security_group_ids": { + "public_access_cidrs": { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "subnet_ids": { + "security_group_ids": { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "public_access_cidrs": { + "subnet_ids": { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, @@ -134,10 +137,6 @@ func dataSourceAwsEksCluster() *schema.Resource { }, }, }, - "version": { - Type: schema.TypeString, - Computed: true, - }, }, } } @@ -147,22 +146,12 @@ func dataSourceAwsEksClusterRead(d *schema.ResourceData, meta interface{}) error ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig name := d.Get("name").(string) + cluster, err := finder.ClusterByName(conn, name) - input := &eks.DescribeClusterInput{ - Name: aws.String(name), - } - - log.Printf("[DEBUG] Reading EKS Cluster: %s", input) - output, err := conn.DescribeCluster(input) if err != nil { return fmt.Errorf("error reading EKS Cluster (%s): %w", name, err) } - cluster := output.Cluster - if cluster == nil { - return fmt.Errorf("EKS Cluster (%s) not found", name) - } - d.SetId(name) d.Set("arn", cluster.Arn) @@ -171,32 +160,34 @@ func dataSourceAwsEksClusterRead(d *schema.ResourceData, meta interface{}) error } d.Set("created_at", aws.TimeValue(cluster.CreatedAt).String()) + if err := d.Set("enabled_cluster_log_types", flattenEksEnabledLogTypes(cluster.Logging)); err != nil { return fmt.Errorf("error setting enabled_cluster_log_types: %w", err) } + d.Set("endpoint", cluster.Endpoint) if err := d.Set("identity", flattenEksIdentity(cluster.Identity)); err != nil { return fmt.Errorf("error setting identity: %w", err) } + if err := d.Set("kubernetes_network_config", flattenEksNetworkConfig(cluster.KubernetesNetworkConfig)); err != nil { + return fmt.Errorf("error setting kubernetes_network_config: %w", err) + } + d.Set("name", cluster.Name) d.Set("platform_version", cluster.PlatformVersion) d.Set("role_arn", cluster.RoleArn) d.Set("status", cluster.Status) - if err := d.Set("tags", keyvaluetags.EksKeyValueTags(cluster.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %w", err) - } - d.Set("version", cluster.Version) if err := d.Set("vpc_config", flattenEksVpcConfigResponse(cluster.ResourcesVpcConfig)); err != nil { return fmt.Errorf("error setting vpc_config: %w", err) } - if err := d.Set("kubernetes_network_config", flattenEksNetworkConfig(cluster.KubernetesNetworkConfig)); err != nil { - return fmt.Errorf("error setting kubernetes_network_config: %w", err) + if err := d.Set("tags", keyvaluetags.EksKeyValueTags(cluster.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) } return nil From b17b50a01ebf0a9069f7c1bc190f30edaea91ec2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 21 Jun 2021 10:39:21 -0400 Subject: [PATCH 0646/1208] r/aws_vpc_endpoint: Better error reporting when 'waiter.VpcEndpointAvailable' fails. --- aws/internal/service/ec2/waiter/waiter.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/internal/service/ec2/waiter/waiter.go b/aws/internal/service/ec2/waiter/waiter.go index 73ff47bfbd78..55c20d4c8ea5 100644 --- a/aws/internal/service/ec2/waiter/waiter.go +++ b/aws/internal/service/ec2/waiter/waiter.go @@ -727,6 +727,10 @@ func VpcEndpointAvailable(conn *ec2.EC2, vpcEndpointID string, timeout time.Dura outputRaw, err := stateConf.WaitForState() if output, ok := outputRaw.(*ec2.VpcEndpoint); ok { + if state, lastError := aws.StringValue(output.State), output.LastError; state == tfec2.VpcEndpointStateFailed && lastError != nil { + tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.StringValue(lastError.Code), aws.StringValue(lastError.Message))) + } + return output, err } From 01086c3e148e2a02c4a46d103ff21ba2efa3454c Mon Sep 17 00:00:00 2001 From: Krzysztof Szyper <45788587+ChristophShyper@users.noreply.github.com> Date: Mon, 21 Jun 2021 18:48:23 +0200 Subject: [PATCH 0647/1208] Fixed description of `role_arn` attribute of `aws_cloudwatch_event_target` As stated in https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-targets.html#:~:text=For%20EC2%20instances%2C%20Kinesis%20data%20streams%2C%20and%20Step%20Functions%20state%20machines%2C%20EventBridge%20uses%20IAM%20roles%20that%20you%20specify%20in%20the%20RoleARN%20parameter%20in%20PutTargets. --- website/docs/r/cloudwatch_event_target.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cloudwatch_event_target.html.markdown b/website/docs/r/cloudwatch_event_target.html.markdown index efd4622356f5..9e97e856faf3 100644 --- a/website/docs/r/cloudwatch_event_target.html.markdown +++ b/website/docs/r/cloudwatch_event_target.html.markdown @@ -333,7 +333,7 @@ The following arguments are supported: * `arn` - (Required) The Amazon Resource Name (ARN) of the target. * `input` - (Optional) Valid JSON text passed to the target. Conflicts with `input_path` and `input_transformer`. * `input_path` - (Optional) The value of the [JSONPath](http://goessner.net/articles/JsonPath/) that is used for extracting part of the matched event when passing it to the target. Conflicts with `input` and `input_transformer`. -* `role_arn` - (Optional) The Amazon Resource Name (ARN) of the IAM role to be used for this target when the rule is triggered. Required if `ecs_target` is used. +* `role_arn` - (Optional) The Amazon Resource Name (ARN) of the IAM role to be used for this target when the rule is triggered. Required if `ecs_target` is used or target in `arn` is EC2 instance, Kinesis data stream or Step Functions state machine. * `run_command_targets` - (Optional) Parameters used when you are using the rule to invoke Amazon EC2 Run Command. Documented below. A maximum of 5 are allowed. * `ecs_target` - (Optional) Parameters used when you are using the rule to invoke Amazon ECS Task. Documented below. A maximum of 1 are allowed. * `batch_target` - (Optional) Parameters used when you are using the rule to invoke an Amazon Batch Job. Documented below. A maximum of 1 are allowed. From 9578fd78ee9eb4ded0a424abfaf735956142e500 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 17:48:24 -0400 Subject: [PATCH 0648/1208] Add configurable retry --- aws/retry.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 aws/retry.go diff --git a/aws/retry.go b/aws/retry.go new file mode 100644 index 000000000000..fa64cbf6f77e --- /dev/null +++ b/aws/retry.go @@ -0,0 +1,78 @@ +package aws + +import ( + "context" + "math/rand" + "sync" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func RetryConfigContext(ctx context.Context, delay time.Duration, delayRand time.Duration, minTimeout time.Duration, pollInterval time.Duration, timeout time.Duration, f resource.RetryFunc) error { + // These are used to pull the error out of the function; need a mutex to + // avoid a data race. + var resultErr error + var resultErrMu sync.Mutex + + c := &resource.StateChangeConf{ + Pending: []string{"retryableerror"}, + Target: []string{"success"}, + Timeout: timeout, + Refresh: func() (interface{}, string, error) { + rerr := f() + + resultErrMu.Lock() + defer resultErrMu.Unlock() + + if rerr == nil { + resultErr = nil + return 42, "success", nil + } + + resultErr = rerr.Err + + if rerr.Retryable { + return 42, "retryableerror", nil + } + + return nil, "quit", rerr.Err + }, + } + + if delay.Milliseconds() > 0 { + c.Delay = delay + } + + if delayRand.Milliseconds() > 0 { + // Hitting the API at exactly the same time on each iteration of the retry is more likely to + // cause Throttling problems. We introduce randomness in order to help AWS be happier. + rand.Seed(time.Now().UTC().UnixNano()) + + c.Delay = time.Duration(rand.Int63n(delayRand.Milliseconds())) * time.Millisecond + } + + if minTimeout.Milliseconds() > 0 { + c.MinTimeout = minTimeout + } + + if pollInterval.Milliseconds() > 0 { + c.PollInterval = pollInterval + } + + _, waitErr := c.WaitForStateContext(ctx) + + // Need to acquire the lock here to be able to avoid race using resultErr as + // the return value + resultErrMu.Lock() + defer resultErrMu.Unlock() + + // resultErr may be nil because the wait timed out and resultErr was never + // set; this is still an error + if resultErr == nil { + return waitErr + } + // resultErr takes precedence over waitErr if both are set because it is + // more likely to be useful + return resultErr +} From 42afbff4091d686de17af272398403b4cead34ca Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 17:48:58 -0400 Subject: [PATCH 0649/1208] sweeper: Rework configurability of retry --- aws/aws_sweeper_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/aws/aws_sweeper_test.go b/aws/aws_sweeper_test.go index e064db16de30..1309a6a8f9d3 100644 --- a/aws/aws_sweeper_test.go +++ b/aws/aws_sweeper_test.go @@ -1,6 +1,7 @@ package aws import ( + "context" "fmt" "log" "os" @@ -79,13 +80,17 @@ func NewTestSweepResource(resource *schema.Resource, d *schema.ResourceData, met } func testSweepResourceOrchestrator(sweepResources []*testSweepResource) error { + return testSweepResourceOrchestratorContext(context.Background(), sweepResources, 0*time.Millisecond, 0*time.Millisecond, 0*time.Millisecond, 0*time.Millisecond, SweepThrottlingRetryTimeout) +} + +func testSweepResourceOrchestratorContext(ctx context.Context, sweepResources []*testSweepResource, delay time.Duration, delayRand time.Duration, minTimeout time.Duration, pollInterval time.Duration, timeout time.Duration) error { var g multierror.Group for _, sweepResource := range sweepResources { sweepResource := sweepResource g.Go(func() error { - err := resource.Retry(SweepThrottlingRetryTimeout, func() *resource.RetryError { + err := RetryConfigContext(ctx, delay, delayRand, minTimeout, pollInterval, timeout, func() *resource.RetryError { err := testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) if err != nil { From 623c6baa6a24f642f83fd2fc2bd2bee23f4eadfa Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 17:49:37 -0400 Subject: [PATCH 0650/1208] i/route53: Make waiter easier on throttling --- aws/internal/service/route53/waiter/waiter.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/aws/internal/service/route53/waiter/waiter.go b/aws/internal/service/route53/waiter/waiter.go index c95144886ffa..c5c860cdda28 100644 --- a/aws/internal/service/route53/waiter/waiter.go +++ b/aws/internal/service/route53/waiter/waiter.go @@ -3,6 +3,7 @@ package waiter import ( "errors" "fmt" + "math/rand" "time" "github.com/aws/aws-sdk-go/aws" @@ -19,13 +20,16 @@ const ( ) func ChangeInfoStatusInsync(conn *route53.Route53, changeID string) (*route53.ChangeInfo, error) { + rand.Seed(time.Now().UTC().UnixNano()) + stateConf := &resource.StateChangeConf{ - Pending: []string{route53.ChangeStatusPending}, - Target: []string{route53.ChangeStatusInsync}, - Refresh: ChangeInfoStatus(conn, changeID), - Delay: 30 * time.Second, - MinTimeout: 5 * time.Second, - Timeout: ChangeTimeout, + Pending: []string{route53.ChangeStatusPending}, + Target: []string{route53.ChangeStatusInsync}, + Delay: time.Duration(rand.Int63n(20)+10) * time.Second, + MinTimeout: 5 * time.Second, + PollInterval: 30 * time.Second, + Refresh: ChangeInfoStatus(conn, changeID), + Timeout: ChangeTimeout, } outputRaw, err := stateConf.WaitForState() From d08c23472484844434c7d416ed63a6ec073f48a2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 17:50:24 -0400 Subject: [PATCH 0651/1208] r/route53_key_signing_key: Clean up delete --- aws/resource_aws_route53_key_signing_key.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_key_signing_key.go b/aws/resource_aws_route53_key_signing_key.go index 46f93d6fc076..1fb20fe7d975 100644 --- a/aws/resource_aws_route53_key_signing_key.go +++ b/aws/resource_aws_route53_key_signing_key.go @@ -287,7 +287,7 @@ func resourceAwsRoute53KeySigningKeyDelete(d *schema.ResourceData, meta interfac } if err != nil { - return fmt.Errorf("error deleting Route 53 Key Signing Key (%s): %w", d.Id(), err) + return fmt.Errorf("error deleting Route 53 Key Signing Key (%s), status (%s): %w", d.Id(), d.Get("status").(string), err) } if output != nil && output.ChangeInfo != nil { From b774d0af9952dbd580f0cb891f3d685285565fe0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 17:51:07 -0400 Subject: [PATCH 0652/1208] tests/r/route53_key_signing_key: Add sweeper --- ...source_aws_route53_key_signing_key_test.go | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/aws/resource_aws_route53_key_signing_key_test.go b/aws/resource_aws_route53_key_signing_key_test.go index 2917e6980569..8d2e45aad304 100644 --- a/aws/resource_aws_route53_key_signing_key_test.go +++ b/aws/resource_aws_route53_key_signing_key_test.go @@ -1,12 +1,18 @@ package aws import ( + "context" "fmt" + "log" "regexp" + "strings" "testing" + "time" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/route53" "github.com/hashicorp/aws-sdk-go-base/tfawserr" + multierror "github.com/hashicorp/go-multierror" "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" @@ -14,6 +20,92 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53/finder" ) +// add sweeper to delete resources +func init() { + resource.AddTestSweepers("aws_route53_key_signing_key", &resource.Sweeper{ + Name: "aws_route53_key_signing_key", + F: testSweepRoute53KeySigningKeys, + }) +} + +func testSweepRoute53KeySigningKeys(region string) error { + client, err := sharedClientForRegion(region) + + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + + conn := client.(*AWSClient).r53conn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + + input := &route53.ListHostedZonesInput{} + + err = conn.ListHostedZonesPages(input, func(page *route53.ListHostedZonesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, detail := range page.HostedZones { + if detail == nil { + continue + } + + id := aws.StringValue(detail.Id) + + for _, domain := range hostedZonesToPreserve() { + if strings.Contains(aws.StringValue(detail.Name), domain) { + log.Printf("[DEBUG] Skipping Route53 Hosted Zone (%s): %s", domain, id) + continue + } + } + + dnsInput := &route53.GetDNSSECInput{ + HostedZoneId: detail.Id, + } + + output, err := conn.GetDNSSEC(dnsInput) + + if tfawserr.ErrMessageContains(err, route53.ErrCodeInvalidArgument, "private hosted zones") { + continue + } + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error getting Route53 DNS SEC for %s: %w", region, err)) + } + + for _, dns := range output.KeySigningKeys { + r := resourceAwsRoute53KeySigningKey() + d := r.Data(nil) + d.SetId(id) + d.Set("hosted_zone_id", id) + d.Set("name", dns.Name) + d.Set("status", dns.Status) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error getting Route53 Key-Signing Keys for %s: %w", region, err)) + } + + if err = testSweepResourceOrchestratorContext(context.Background(), sweepResources, 0*time.Millisecond, 1*time.Minute, 30*time.Second, 2*time.Minute, 10*time.Minute); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Route53 Key-Signing Keys for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping Route53 Key-Signing Keys sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} + func TestAccAwsRoute53KeySigningKey_basic(t *testing.T) { kmsKeyResourceName := "aws_kms_key.test" route53ZoneResourceName := "aws_route53_zone.test" From 33fc535d644949462b51413198346865f4011aca Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 17:52:11 -0400 Subject: [PATCH 0653/1208] r/route53_record: Make retries easier on throttling --- aws/resource_aws_route53_record.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 5e0061b0ce49..dd355983c612 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "log" + "math/rand" "regexp" "strconv" "strings" @@ -488,12 +489,15 @@ func changeRoute53RecordSet(conn *route53.Route53, input *route53.ChangeResource } func waitForRoute53RecordSetToSync(conn *route53.Route53, requestId string) error { + rand.Seed(time.Now().UTC().UnixNano()) + wait := resource.StateChangeConf{ - Delay: 30 * time.Second, - Pending: []string{route53.ChangeStatusPending}, - Target: []string{route53.ChangeStatusInsync}, - Timeout: 30 * time.Minute, - MinTimeout: 5 * time.Second, + Pending: []string{route53.ChangeStatusPending}, + Target: []string{route53.ChangeStatusInsync}, + Delay: time.Duration(rand.Int63n(20)+10) * time.Second, + MinTimeout: 5 * time.Second, + PollInterval: 30 * time.Second, + Timeout: 30 * time.Minute, Refresh: func() (result interface{}, state string, err error) { changeRequest := &route53.GetChangeInput{ Id: aws.String(requestId), From 5b8baae89c80e406326fbffcc151757d5f120d68 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 17:53:02 -0400 Subject: [PATCH 0654/1208] r/route53_zone: Disable DNS SEC on force delete --- aws/resource_aws_route53_zone.go | 79 ++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index 15b071c43c1e..9bf688bb1e40 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -2,8 +2,10 @@ package aws import ( "bytes" + "context" "fmt" "log" + "math/rand" "sort" "strings" "time" @@ -318,7 +320,7 @@ func resourceAwsRoute53ZoneDelete(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("error while force deleting Route53 Hosted Zone (%s), deleting records: %w", d.Id(), err) } - if err := deleteDNSSECForZone(conn, d.Id()); err != nil { + if err := disableDNSSECForZone(conn, d.Id()); err != nil { return fmt.Errorf("error while force deleting Route53 Hosted Zone (%s), disabling DNSSEC: %w", d.Id(), err) } } @@ -364,6 +366,11 @@ func deleteAllRecordsInHostedZoneId(hostedZoneId, hostedZoneName string, conn *r ResourceRecordSet: set, }) } + + if len(changes) == 0 { + return !lastPage + } + log.Printf("[DEBUG] Deleting %d records (page %d) from %s", len(changes), pageNum, hostedZoneId) req := &route53.ChangeResourceRecordSetsInput{ @@ -389,6 +396,7 @@ func deleteAllRecordsInHostedZoneId(hostedZoneId, hostedZoneName string, conn *r return !lastPage }) + if err != nil { return fmt.Errorf("Failed listing/deleting record sets: %s\nLast error from deletion: %s\nLast error from waiter: %s", err, lastDeleteErr, lastErrorFromWaiter) @@ -397,20 +405,72 @@ func deleteAllRecordsInHostedZoneId(hostedZoneId, hostedZoneName string, conn *r return nil } -func deleteDNSSECForZone(conn *route53.Route53, hostedZoneId string) error { +func dnsSECStatus(conn *route53.Route53, hostedZoneID string) (string, error) { + input := &route53.GetDNSSECInput{ + HostedZoneId: aws.String(hostedZoneID), + } + + var output *route53.GetDNSSECOutput + err := RetryConfigContext(context.Background(), 0*time.Millisecond, 1*time.Minute, 0*time.Millisecond, 30*time.Second, 10*time.Minute, func() *resource.RetryError { + var err error + + output, err = conn.GetDNSSEC(input) + + if err != nil { + if strings.Contains(err.Error(), "Throttling") { + log.Printf("[DEBUG] Retrying to get DNS SEC for zone %s: %s", hostedZoneID, err) + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + output, err = conn.GetDNSSEC(input) + } + + if err != nil { + return "", err + } + + if output == nil || output.Status == nil { + return "", fmt.Errorf("getting DNS SEC for hosted zone (%s): empty response (%v)", hostedZoneID, output) + } + + return aws.StringValue(output.Status.ServeSignature), nil +} + +func disableDNSSECForZone(conn *route53.Route53, hostedZoneId string) error { // hosted zones cannot be deleted if DNSSEC Key Signing Keys exist + log.Printf("[DEBUG] Disabling DNS SEC for zone %s", hostedZoneId) + + status, err := dnsSECStatus(conn, hostedZoneId) + + if err != nil { + return fmt.Errorf("could not get DNS SEC status for hosted zone (%s): %w", hostedZoneId, err) + } + + if status != "SIGNING" { + log.Printf("[DEBUG] Not necessary to disable DNS SEC for hosted zone (%s): %s (status)", hostedZoneId, status) + return nil + } + input := &route53.DisableHostedZoneDNSSECInput{ HostedZoneId: aws.String(hostedZoneId), } var output *route53.DisableHostedZoneDNSSECOutput - err := resource.Retry(10*time.Minute, func() *resource.RetryError { + err = RetryConfigContext(context.Background(), 0*time.Millisecond, 1*time.Minute, 0*time.Millisecond, 30*time.Second, 10*time.Minute, func() *resource.RetryError { var err error output, err = conn.DisableHostedZoneDNSSEC(input) if err != nil { if tfawserr.ErrCodeEquals(err, route53.ErrCodeKeySigningKeyInParentDSRecord) { + log.Printf("[DEBUG] Unable to disable DNS SEC for zone %s because key-signing key in parent DS record. Retrying...", hostedZoneId) return resource.RetryableError(err) } @@ -605,12 +665,15 @@ func route53HostedZoneVPCHash(v interface{}) int { } func route53WaitForChangeSynchronization(conn *route53.Route53, changeID string) error { + rand.Seed(time.Now().UTC().UnixNano()) + conf := resource.StateChangeConf{ - Delay: 30 * time.Second, - Pending: []string{route53.ChangeStatusPending}, - Target: []string{route53.ChangeStatusInsync}, - Timeout: 15 * time.Minute, - MinTimeout: 2 * time.Second, + Pending: []string{route53.ChangeStatusPending}, + Target: []string{route53.ChangeStatusInsync}, + Delay: time.Duration(rand.Int63n(20)+10) * time.Second, + MinTimeout: 5 * time.Second, + PollInterval: 30 * time.Second, + Timeout: 15 * time.Minute, Refresh: func() (result interface{}, state string, err error) { input := &route53.GetChangeInput{ Id: aws.String(changeID), From 89733592289d64b4db31a89c7d9a046f08dbe6b1 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 17:53:29 -0400 Subject: [PATCH 0655/1208] tests/r/route53_zone: Rework sweeper a little --- aws/resource_aws_route53_zone_test.go | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index b0c61a531037..e3bd7ef77e5a 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -1,11 +1,13 @@ package aws import ( + "context" "fmt" "log" "sort" "strings" "testing" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/route53" @@ -84,11 +86,21 @@ func init() { "aws_service_discovery_public_dns_namespace", "aws_service_discovery_private_dns_namespace", "aws_elb", + "aws_route53_key_signing_key", }, F: testSweepRoute53Zones, }) } +func hostedZonesToPreserve() []string { + return []string{ + "acmetest.hashicorp.engineering", + "tfacc.hashicorptest.com", + "aws.tfacc.hashicorptest.com", + "hashicorp.com", + } +} + func testSweepRoute53Zones(region string) error { client, err := sharedClientForRegion(region) @@ -102,13 +114,6 @@ func testSweepRoute53Zones(region string) error { input := &route53.ListHostedZonesInput{} - hostedZonesToPreserve := []string{ - "acmetest.hashicorp.engineering", - "tfacc.hashicorptest.com", - "aws.tfacc.hashicorptest.com", - "hashicorp.com", - } - err = conn.ListHostedZonesPages(input, func(page *route53.ListHostedZonesOutput, lastPage bool) bool { if page == nil { return !lastPage @@ -121,7 +126,7 @@ func testSweepRoute53Zones(region string) error { id := aws.StringValue(detail.Id) - for _, domain := range hostedZonesToPreserve { + for _, domain := range hostedZonesToPreserve() { if strings.Contains(aws.StringValue(detail.Name), domain) { log.Printf("[DEBUG] Skipping Route53 Hosted Zone (%s): %s", domain, id) continue @@ -144,7 +149,7 @@ func testSweepRoute53Zones(region string) error { errs = multierror.Append(errs, fmt.Errorf("error describing Route53 Hosted Zones for %s: %w", region, err)) } - if err = testSweepResourceOrchestrator(sweepResources); err != nil { + if err = testSweepResourceOrchestratorContext(context.Background(), sweepResources, 0*time.Minute, 2*time.Minute, 30*time.Second, 30*time.Second, 10*time.Minute); err != nil { errs = multierror.Append(errs, fmt.Errorf("error sweeping Route53 Hosted Zones for %s: %w", region, err)) } From 459ab86af49019b849e37512ce01b9de3aa376c0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 18:23:53 -0400 Subject: [PATCH 0656/1208] tests/r/route53_key_signing_key: Skip sweeping if zone gets stuck --- aws/resource_aws_route53_key_signing_key_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aws/resource_aws_route53_key_signing_key_test.go b/aws/resource_aws_route53_key_signing_key_test.go index 8d2e45aad304..ff137d5233c4 100644 --- a/aws/resource_aws_route53_key_signing_key_test.go +++ b/aws/resource_aws_route53_key_signing_key_test.go @@ -98,6 +98,11 @@ func testSweepRoute53KeySigningKeys(region string) error { errs = multierror.Append(errs, fmt.Errorf("error sweeping Route53 Key-Signing Keys for %s: %w", region, err)) } + if strings.Contains(errs.ErrorOrNil().Error(), "cannot be deleted because") { + log.Printf("[WARN] Skipping Route53 Key-Signing Keys sweep for %s: %s", region, errs) + return nil + } + if testSweepSkipSweepError(errs.ErrorOrNil()) { log.Printf("[WARN] Skipping Route53 Key-Signing Keys sweep for %s: %s", region, errs) return nil From 439d03e98690b98eda7d9d8e7a6564170cf0d1d0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 18:39:12 -0400 Subject: [PATCH 0657/1208] tests/r/route53_zone: Skip private zones from DNSSEC error --- aws/aws_sweeper_test.go | 8 ++++++++ aws/resource_aws_route53_key_signing_key_test.go | 2 +- aws/resource_aws_route53_zone.go | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/aws/aws_sweeper_test.go b/aws/aws_sweeper_test.go index 1309a6a8f9d3..16e7470a5d9a 100644 --- a/aws/aws_sweeper_test.go +++ b/aws/aws_sweeper_test.go @@ -155,6 +155,14 @@ func testSweepSkipSweepError(err error) bool { if isAWSErr(err, "InvalidAction", "Unavailable Operation") { return true } + // For example from us-west-2 Route53 key signing key + if isAWSErr(err, "InvalidKeySigningKeyStatus", "cannot be deleted because") { + return true + } + // For example from us-west-2 Route53 zone + if isAWSErr(err, "KeySigningKeyInParentDSRecord", "Due to DNS lookup failure") { + return true + } return false } diff --git a/aws/resource_aws_route53_key_signing_key_test.go b/aws/resource_aws_route53_key_signing_key_test.go index ff137d5233c4..0a0e5a850653 100644 --- a/aws/resource_aws_route53_key_signing_key_test.go +++ b/aws/resource_aws_route53_key_signing_key_test.go @@ -98,7 +98,7 @@ func testSweepRoute53KeySigningKeys(region string) error { errs = multierror.Append(errs, fmt.Errorf("error sweeping Route53 Key-Signing Keys for %s: %w", region, err)) } - if strings.Contains(errs.ErrorOrNil().Error(), "cannot be deleted because") { + if errs.ErrorOrNil() != nil && strings.Contains(errs.ErrorOrNil().Error(), "cannot be deleted because") { log.Printf("[WARN] Skipping Route53 Key-Signing Keys sweep for %s: %s", region, errs) return nil } diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index 9bf688bb1e40..c06f67f8c694 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -432,6 +432,10 @@ func dnsSECStatus(conn *route53.Route53, hostedZoneID string) (string, error) { output, err = conn.GetDNSSEC(input) } + if tfawserr.ErrMessageContains(err, route53.ErrCodeInvalidArgument, "Operation is unsupported for private") { + return "NOT_SIGNING", nil + } + if err != nil { return "", err } From a528b927646cad402238e4a42ed38ae386b71d1e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 18:49:47 -0400 Subject: [PATCH 0658/1208] tests/r/route53_zone: Continue the correct loop --- aws/resource_aws_route53_zone_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index e3bd7ef77e5a..81eeda10f0a0 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -119,6 +119,7 @@ func testSweepRoute53Zones(region string) error { return !lastPage } + MAIN: for _, detail := range page.HostedZones { if detail == nil { continue @@ -129,7 +130,7 @@ func testSweepRoute53Zones(region string) error { for _, domain := range hostedZonesToPreserve() { if strings.Contains(aws.StringValue(detail.Name), domain) { log.Printf("[DEBUG] Skipping Route53 Hosted Zone (%s): %s", domain, id) - continue + continue MAIN } } From da89aa8e4c7221a3cbd2fcf2ca5a70211b660bea Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 18:55:50 -0400 Subject: [PATCH 0659/1208] tests/route53_key_signing_key: Continue the correct loop --- aws/resource_aws_route53_key_signing_key_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_key_signing_key_test.go b/aws/resource_aws_route53_key_signing_key_test.go index 0a0e5a850653..8b5f7c29ae2f 100644 --- a/aws/resource_aws_route53_key_signing_key_test.go +++ b/aws/resource_aws_route53_key_signing_key_test.go @@ -46,6 +46,7 @@ func testSweepRoute53KeySigningKeys(region string) error { return !lastPage } + MAIN: for _, detail := range page.HostedZones { if detail == nil { continue @@ -56,7 +57,7 @@ func testSweepRoute53KeySigningKeys(region string) error { for _, domain := range hostedZonesToPreserve() { if strings.Contains(aws.StringValue(detail.Name), domain) { log.Printf("[DEBUG] Skipping Route53 Hosted Zone (%s): %s", domain, id) - continue + continue MAIN } } From af73f20937edf95b9f976937dc184e345c3ebda9 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 18:59:54 -0400 Subject: [PATCH 0660/1208] tests/route53_key_signing_key: Leave skip to main skipper --- aws/resource_aws_route53_key_signing_key_test.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/aws/resource_aws_route53_key_signing_key_test.go b/aws/resource_aws_route53_key_signing_key_test.go index 8b5f7c29ae2f..1c75b25da069 100644 --- a/aws/resource_aws_route53_key_signing_key_test.go +++ b/aws/resource_aws_route53_key_signing_key_test.go @@ -99,11 +99,6 @@ func testSweepRoute53KeySigningKeys(region string) error { errs = multierror.Append(errs, fmt.Errorf("error sweeping Route53 Key-Signing Keys for %s: %w", region, err)) } - if errs.ErrorOrNil() != nil && strings.Contains(errs.ErrorOrNil().Error(), "cannot be deleted because") { - log.Printf("[WARN] Skipping Route53 Key-Signing Keys sweep for %s: %s", region, errs) - return nil - } - if testSweepSkipSweepError(errs.ErrorOrNil()) { log.Printf("[WARN] Skipping Route53 Key-Signing Keys sweep for %s: %s", region, errs) return nil From c4be52843b3f53155bb629608484df956139a32c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 19:11:24 -0400 Subject: [PATCH 0661/1208] tests/route53: Adjust sweeper poll intervals --- aws/internal/service/route53/waiter/waiter.go | 10 +++++++--- aws/resource_aws_route53_key_signing_key_test.go | 2 +- aws/resource_aws_route53_record.go | 2 +- aws/resource_aws_route53_zone.go | 6 +++--- aws/resource_aws_route53_zone_test.go | 2 +- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/aws/internal/service/route53/waiter/waiter.go b/aws/internal/service/route53/waiter/waiter.go index c5c860cdda28..4ae1af4d65b4 100644 --- a/aws/internal/service/route53/waiter/waiter.go +++ b/aws/internal/service/route53/waiter/waiter.go @@ -12,7 +12,9 @@ import ( ) const ( - ChangeTimeout = 30 * time.Minute + ChangeTimeout = 30 * time.Minute + ChangeMinTimeout = 5 * time.Second + ChangePollInterval = 15 * time.Second HostedZoneDnssecStatusTimeout = 5 * time.Minute @@ -22,12 +24,14 @@ const ( func ChangeInfoStatusInsync(conn *route53.Route53, changeID string) (*route53.ChangeInfo, error) { rand.Seed(time.Now().UTC().UnixNano()) + // Route53 is vulnerable to throttling so longer delays, poll intervals helps significantly to avoid + stateConf := &resource.StateChangeConf{ Pending: []string{route53.ChangeStatusPending}, Target: []string{route53.ChangeStatusInsync}, Delay: time.Duration(rand.Int63n(20)+10) * time.Second, - MinTimeout: 5 * time.Second, - PollInterval: 30 * time.Second, + MinTimeout: ChangeMinTimeout, + PollInterval: ChangePollInterval, Refresh: ChangeInfoStatus(conn, changeID), Timeout: ChangeTimeout, } diff --git a/aws/resource_aws_route53_key_signing_key_test.go b/aws/resource_aws_route53_key_signing_key_test.go index 1c75b25da069..4da3e7331781 100644 --- a/aws/resource_aws_route53_key_signing_key_test.go +++ b/aws/resource_aws_route53_key_signing_key_test.go @@ -95,7 +95,7 @@ func testSweepRoute53KeySigningKeys(region string) error { errs = multierror.Append(errs, fmt.Errorf("error getting Route53 Key-Signing Keys for %s: %w", region, err)) } - if err = testSweepResourceOrchestratorContext(context.Background(), sweepResources, 0*time.Millisecond, 1*time.Minute, 30*time.Second, 2*time.Minute, 10*time.Minute); err != nil { + if err = testSweepResourceOrchestratorContext(context.Background(), sweepResources, 0*time.Millisecond, 1*time.Minute, 30*time.Second, 30*time.Second, 10*time.Minute); err != nil { errs = multierror.Append(errs, fmt.Errorf("error sweeping Route53 Key-Signing Keys for %s: %w", region, err)) } diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index dd355983c612..0a26f9c49b45 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -496,7 +496,7 @@ func waitForRoute53RecordSetToSync(conn *route53.Route53, requestId string) erro Target: []string{route53.ChangeStatusInsync}, Delay: time.Duration(rand.Int63n(20)+10) * time.Second, MinTimeout: 5 * time.Second, - PollInterval: 30 * time.Second, + PollInterval: 20 * time.Second, Timeout: 30 * time.Minute, Refresh: func() (result interface{}, state string, err error) { changeRequest := &route53.GetChangeInput{ diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index c06f67f8c694..d1b5d2749e75 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -467,14 +467,14 @@ func disableDNSSECForZone(conn *route53.Route53, hostedZoneId string) error { } var output *route53.DisableHostedZoneDNSSECOutput - err = RetryConfigContext(context.Background(), 0*time.Millisecond, 1*time.Minute, 0*time.Millisecond, 30*time.Second, 10*time.Minute, func() *resource.RetryError { + err = RetryConfigContext(context.Background(), 0*time.Millisecond, 1*time.Minute, 0*time.Millisecond, 20*time.Second, 5*time.Minute, func() *resource.RetryError { var err error output, err = conn.DisableHostedZoneDNSSEC(input) if err != nil { if tfawserr.ErrCodeEquals(err, route53.ErrCodeKeySigningKeyInParentDSRecord) { - log.Printf("[DEBUG] Unable to disable DNS SEC for zone %s because key-signing key in parent DS record. Retrying...", hostedZoneId) + log.Printf("[DEBUG] Unable to disable DNS SEC for zone %s because key-signing key in parent DS record. Retrying... (%s)", hostedZoneId, err) return resource.RetryableError(err) } @@ -676,7 +676,7 @@ func route53WaitForChangeSynchronization(conn *route53.Route53, changeID string) Target: []string{route53.ChangeStatusInsync}, Delay: time.Duration(rand.Int63n(20)+10) * time.Second, MinTimeout: 5 * time.Second, - PollInterval: 30 * time.Second, + PollInterval: time.Duration(rand.Int63n(15)+15) * time.Second, Timeout: 15 * time.Minute, Refresh: func() (result interface{}, state string, err error) { input := &route53.GetChangeInput{ diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index 81eeda10f0a0..122667dd79a2 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -150,7 +150,7 @@ func testSweepRoute53Zones(region string) error { errs = multierror.Append(errs, fmt.Errorf("error describing Route53 Hosted Zones for %s: %w", region, err)) } - if err = testSweepResourceOrchestratorContext(context.Background(), sweepResources, 0*time.Minute, 2*time.Minute, 30*time.Second, 30*time.Second, 10*time.Minute); err != nil { + if err = testSweepResourceOrchestratorContext(context.Background(), sweepResources, 0*time.Minute, 1*time.Minute, 10*time.Second, 18*time.Second, 10*time.Minute); err != nil { errs = multierror.Append(errs, fmt.Errorf("error sweeping Route53 Hosted Zones for %s: %w", region, err)) } From 06134abd519ffd10106559bf93ecaca21752bc10 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 21 Jun 2021 19:14:36 -0400 Subject: [PATCH 0662/1208] tests/route53: Adjust timeout intervals --- aws/resource_aws_route53_zone.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index d1b5d2749e75..85a141356127 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -411,7 +411,7 @@ func dnsSECStatus(conn *route53.Route53, hostedZoneID string) (string, error) { } var output *route53.GetDNSSECOutput - err := RetryConfigContext(context.Background(), 0*time.Millisecond, 1*time.Minute, 0*time.Millisecond, 30*time.Second, 10*time.Minute, func() *resource.RetryError { + err := RetryConfigContext(context.Background(), 0*time.Millisecond, 1*time.Minute, 0*time.Millisecond, 30*time.Second, 3*time.Minute, func() *resource.RetryError { var err error output, err = conn.GetDNSSEC(input) From 26996f9b596d54d41016828370d9aee50878ec19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Jun 2021 06:10:51 +0000 Subject: [PATCH 0663/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.64 to 1.38.65. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.64...v1.38.65) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 +- .../aws/aws-sdk-go/aws/endpoints/defaults.go | 7 +++ .../aws-sdk-go/aws/signer/v4/header_rules.go | 16 +++--- .../aws/aws-sdk-go/aws/signer/v4/v4.go | 11 ++-- .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- .../aws-sdk-go/private/protocol/timestamp.go | 57 +++++++++++++++++-- awsproviderlint/vendor/modules.txt | 2 +- 8 files changed, 78 insertions(+), 23 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 8abf77b85da4..7b7056e0c5dd 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.64 + github.com/aws/aws-sdk-go v1.38.65 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index d14dc6138d03..07c66db6f178 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.64 h1:aE178SZNBpAT9T2U5hacKJiyiRE/Li2Hax6xddVuyGA= -github.com/aws/aws-sdk-go v1.38.64/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.65 h1:umGu5gjIOKxzhi34T0DIA1TWupUDjV2aAW5vK6154Gg= +github.com/aws/aws-sdk-go v1.38.65/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index a07649e9063b..cef754e1ae4b 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -9623,6 +9623,13 @@ var awsusgovPartition = partition{ "us-gov-west-1": endpoint{}, }, }, + "mq": service{ + + Endpoints: endpoints{ + "us-gov-east-1": endpoint{}, + "us-gov-west-1": endpoint{}, + }, + }, "neptune": service{ Endpoints: endpoints{ diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go index 07ea799fbd37..716e6181f54b 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules.go @@ -34,23 +34,23 @@ func (m mapRule) IsValid(value string) bool { return ok } -// whitelist is a generic rule for whitelisting -type whitelist struct { +// allowList is a generic rule for allow listing +type allowList struct { rule } -// IsValid for whitelist checks if the value is within the whitelist -func (w whitelist) IsValid(value string) bool { +// IsValid for allow list checks if the value is within the allow list +func (w allowList) IsValid(value string) bool { return w.rule.IsValid(value) } -// blacklist is a generic rule for blacklisting -type blacklist struct { +// excludeList is a generic rule for blacklisting +type excludeList struct { rule } -// IsValid for whitelist checks if the value is within the whitelist -func (b blacklist) IsValid(value string) bool { +// IsValid for allow list checks if the value is within the allow list +func (b excludeList) IsValid(value string) bool { return !b.rule.IsValid(value) } diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go index 1737c2686de4..c1949859ad52 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4.go @@ -90,7 +90,7 @@ const ( ) var ignoredHeaders = rules{ - blacklist{ + excludeList{ mapRule{ authorizationHeader: struct{}{}, "User-Agent": struct{}{}, @@ -99,9 +99,9 @@ var ignoredHeaders = rules{ }, } -// requiredSignedHeaders is a whitelist for build canonical headers. +// requiredSignedHeaders is a allow list for build canonical headers. var requiredSignedHeaders = rules{ - whitelist{ + allowList{ mapRule{ "Cache-Control": struct{}{}, "Content-Disposition": struct{}{}, @@ -145,12 +145,13 @@ var requiredSignedHeaders = rules{ }, }, patterns{"X-Amz-Meta-"}, + patterns{"X-Amz-Object-Lock-"}, } -// allowedHoisting is a whitelist for build query headers. The boolean value +// allowedHoisting is a allow list for build query headers. The boolean value // represents whether or not it is a pattern. var allowedQueryHoisting = inclusiveRules{ - blacklist{requiredSignedHeaders}, + excludeList{requiredSignedHeaders}, patterns{"X-Amz-"}, } diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index a4136ac05fcb..f8acf1cffcb5 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.64" +const SDKVersion = "1.38.65" diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/private/protocol/timestamp.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/private/protocol/timestamp.go index 98f4caed91cc..d486a4c2a0dc 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/private/protocol/timestamp.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/private/protocol/timestamp.go @@ -1,6 +1,8 @@ package protocol import ( + "bytes" + "fmt" "math" "strconv" "time" @@ -19,7 +21,9 @@ const ( // Output time is intended to not contain decimals const ( // RFC 7231#section-7.1.1.1 timetamp format. e.g Tue, 29 Apr 2014 18:30:38 GMT - RFC822TimeFormat = "Mon, 2 Jan 2006 15:04:05 GMT" + RFC822TimeFormat = "Mon, 2 Jan 2006 15:04:05 GMT" + rfc822TimeFormatSingleDigitDay = "Mon, _2 Jan 2006 15:04:05 GMT" + rfc822TimeFormatSingleDigitDayTwoDigitYear = "Mon, _2 Jan 06 15:04:05 GMT" // This format is used for output time without seconds precision RFC822OutputTimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" @@ -67,10 +71,20 @@ func FormatTime(name string, t time.Time) string { // the time if it was able to be parsed, and fails otherwise. func ParseTime(formatName, value string) (time.Time, error) { switch formatName { - case RFC822TimeFormatName: - return time.Parse(RFC822TimeFormat, value) - case ISO8601TimeFormatName: - return time.Parse(ISO8601TimeFormat, value) + case RFC822TimeFormatName: // Smithy HTTPDate format + return tryParse(value, + RFC822TimeFormat, + rfc822TimeFormatSingleDigitDay, + rfc822TimeFormatSingleDigitDayTwoDigitYear, + time.RFC850, + time.ANSIC, + ) + case ISO8601TimeFormatName: // Smithy DateTime format + return tryParse(value, + ISO8601TimeFormat, + time.RFC3339Nano, + time.RFC3339, + ) case UnixTimeFormatName: v, err := strconv.ParseFloat(value, 64) _, dec := math.Modf(v) @@ -83,3 +97,36 @@ func ParseTime(formatName, value string) (time.Time, error) { panic("unknown timestamp format name, " + formatName) } } + +func tryParse(v string, formats ...string) (time.Time, error) { + var errs parseErrors + for _, f := range formats { + t, err := time.Parse(f, v) + if err != nil { + errs = append(errs, parseError{ + Format: f, + Err: err, + }) + continue + } + return t, nil + } + + return time.Time{}, fmt.Errorf("unable to parse time string, %v", errs) +} + +type parseErrors []parseError + +func (es parseErrors) Error() string { + var s bytes.Buffer + for _, e := range es { + fmt.Fprintf(&s, "\n * %q: %v", e.Format, e.Err) + } + + return "parse errors:" + s.String() +} + +type parseError struct { + Format string + Err error +} diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index bb94845e0c39..083f0bec1577 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.64 +# github.com/aws/aws-sdk-go v1.38.65 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 6b5754af9091fd00971ae6bd97c72f45e88a959f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Jun 2021 06:13:15 +0000 Subject: [PATCH 0664/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.64 to 1.38.65 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.64 to 1.38.65. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.64...v1.38.65) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 39dc0ea060fd..07a45b70b8ff 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.64 + github.com/aws/aws-sdk-go v1.38.65 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index f127cb957cc8..b5c0cbed582c 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.64 h1:aE178SZNBpAT9T2U5hacKJiyiRE/Li2Hax6xddVuyGA= -github.com/aws/aws-sdk-go v1.38.64/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.65 h1:umGu5gjIOKxzhi34T0DIA1TWupUDjV2aAW5vK6154Gg= +github.com/aws/aws-sdk-go v1.38.65/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 2ce69a81fadad4a14c15099876335276566fe0e5 Mon Sep 17 00:00:00 2001 From: Peter Mescalchin Date: Tue, 22 Jun 2021 16:31:01 +1000 Subject: [PATCH 0665/1208] Metric stream tags are optional, so moved/grouped with others --- website/docs/r/cloudwatch_metric_stream.html.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/r/cloudwatch_metric_stream.html.markdown b/website/docs/r/cloudwatch_metric_stream.html.markdown index ec85b9a075f4..c318297f2f6d 100644 --- a/website/docs/r/cloudwatch_metric_stream.html.markdown +++ b/website/docs/r/cloudwatch_metric_stream.html.markdown @@ -111,10 +111,10 @@ resource "aws_iam_role_policy" "firehose_to_s3" { "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:PutObject" - ], - "Resource": [ + ], + "Resource": [ "${aws_s3_bucket.bucket.arn}", - "${aws_s3_bucket.bucket.arn}/*" + "${aws_s3_bucket.bucket.arn}/*" ] } ] @@ -140,7 +140,6 @@ The following arguments are required: * `firehose_arn` - (Required) ARN of the Amazon Kinesis Firehose delivery stream to use for this metric stream. * `role_arn` - (Required) ARN of the IAM role that this metric stream will use to access Amazon Kinesis Firehose resources. For more information about role permissions, see [Trust between CloudWatch and Kinesis Data Firehose](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-metric-streams-trustpolicy.html). * `output_format` - (Required) Output format for the stream. For more information about output formats, see [Metric streams output formats](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-metric-streams-formats.html). -* `tags` - (Optional) 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. The following arguments are optional: @@ -148,6 +147,7 @@ The following arguments are optional: * `include_filter` - (Optional) List of inclusive metric filters. If you specify this parameter, the stream sends only the metrics from the metric namespaces that you specify here. Conflicts with `exclude_filter`. * `name` - (Optional, Forces new resource) Friendly name of the metric stream. If omitted, Terraform will assign a random, unique name. Conflicts with `name_prefix`. * `name_prefix` - (Optional, Forces new resource) Creates a unique friendly name beginning with the specified prefix. Conflicts with `name`. +* `tags` - (Optional) 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. ### `exclude_filter` From 3dd108c3d6008cd602302e189147aa6cd901c391 Mon Sep 17 00:00:00 2001 From: Peter Mescalchin Date: Tue, 22 Jun 2021 16:33:00 +1000 Subject: [PATCH 0666/1208] Added possible values for metric stream `output_format` --- website/docs/r/cloudwatch_metric_stream.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cloudwatch_metric_stream.html.markdown b/website/docs/r/cloudwatch_metric_stream.html.markdown index c318297f2f6d..e9b91f2a59f9 100644 --- a/website/docs/r/cloudwatch_metric_stream.html.markdown +++ b/website/docs/r/cloudwatch_metric_stream.html.markdown @@ -139,7 +139,7 @@ The following arguments are required: * `firehose_arn` - (Required) ARN of the Amazon Kinesis Firehose delivery stream to use for this metric stream. * `role_arn` - (Required) ARN of the IAM role that this metric stream will use to access Amazon Kinesis Firehose resources. For more information about role permissions, see [Trust between CloudWatch and Kinesis Data Firehose](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-metric-streams-trustpolicy.html). -* `output_format` - (Required) Output format for the stream. For more information about output formats, see [Metric streams output formats](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-metric-streams-formats.html). +* `output_format` - (Required) Output format for the stream. Possible values are `json` and `opentelemetry0.7`. For more information about output formats, see [Metric streams output formats](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-metric-streams-formats.html). The following arguments are optional: From 3bebba3b81245f53e723856cbbf1423a354c658f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 22 Jun 2021 09:14:43 -0400 Subject: [PATCH 0667/1208] Minor fixes after running all acceptance tests. --- aws/data_source_aws_eks_cluster_test.go | 9 +++------ aws/resource_aws_eks_addon_test.go | 2 +- aws/resource_aws_eks_cluster.go | 1 + 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/aws/data_source_aws_eks_cluster_test.go b/aws/data_source_aws_eks_cluster_test.go index e83cb6bb612a..94a0e56dad39 100644 --- a/aws/data_source_aws_eks_cluster_test.go +++ b/aws/data_source_aws_eks_cluster_test.go @@ -1,7 +1,6 @@ package aws import ( - "fmt" "regexp" "testing" @@ -11,7 +10,7 @@ import ( ) func TestAccAWSEksClusterDataSource_basic(t *testing.T) { - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") dataSourceResourceName := "data.aws_eks_cluster.test" resourceName := "aws_eks_cluster.test" @@ -57,11 +56,9 @@ func TestAccAWSEksClusterDataSource_basic(t *testing.T) { } func testAccAWSEksClusterDataSourceConfig_Basic(rName string) string { - return fmt.Sprintf(` -%[1]s - + return composeConfig(testAccAWSEksClusterConfig_Logging(rName, []string{"api", "audit"}), ` data "aws_eks_cluster" "test" { name = aws_eks_cluster.test.name } -`, testAccAWSEksClusterConfig_Logging(rName, []string{"api", "audit"})) +`) } diff --git a/aws/resource_aws_eks_addon_test.go b/aws/resource_aws_eks_addon_test.go index e436d0eae6da..29b9cfb91ab7 100644 --- a/aws/resource_aws_eks_addon_test.go +++ b/aws/resource_aws_eks_addon_test.go @@ -153,7 +153,7 @@ func TestAccAWSEksAddon_disappears_Cluster(t *testing.T) { var addon eks.Addon rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_addon.test" - clusterResourceName := "aws_eks_cluster" + clusterResourceName := "aws_eks_cluster.test" addonName := "vpc-cni" ctx := context.TODO() diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index 83f552a55aea..57737fdbb759 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -74,6 +74,7 @@ func resourceAwsEksCluster() *schema.Resource { Type: schema.TypeString, ValidateFunc: validation.StringInSlice(eks.LogType_Values(), true), }, + Set: schema.HashString, }, "encryption_config": { Type: schema.TypeList, From a4b72484a56228893deb6550dc27cc59d1e20d39 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 19 Jun 2021 19:29:32 +0300 Subject: [PATCH 0668/1208] initial commit --- aws/internal/service/neptune/finder/finder.go | 44 +++ aws/internal/service/neptune/id.go | 14 + aws/internal/service/neptune/waiter/status.go | 23 ++ aws/internal/service/neptune/waiter/waiter.go | 44 ++- aws/provider.go | 1 + aws/resource_aws_neptune_cluster_endpoint.go | 218 +++++++++++++++ ...ource_aws_neptune_cluster_endpoint_test.go | 252 ++++++++++++++++++ 7 files changed, 595 insertions(+), 1 deletion(-) create mode 100644 aws/internal/service/neptune/finder/finder.go create mode 100644 aws/internal/service/neptune/id.go create mode 100644 aws/resource_aws_neptune_cluster_endpoint.go create mode 100644 aws/resource_aws_neptune_cluster_endpoint_test.go diff --git a/aws/internal/service/neptune/finder/finder.go b/aws/internal/service/neptune/finder/finder.go new file mode 100644 index 000000000000..196fc2ae5a7d --- /dev/null +++ b/aws/internal/service/neptune/finder/finder.go @@ -0,0 +1,44 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/neptune" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + tfneptune "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/neptune" +) + +func EndpointById(conn *neptune.Neptune, id string) (*neptune.DBClusterEndpoint, error) { + clusterId, endpointId, err := tfneptune.ReadAwsNeptuneClusterEndpointId(id) + if err != nil { + return nil, err + } + input := &neptune.DescribeDBClusterEndpointsInput{ + DBClusterIdentifier: aws.String(clusterId), + DBClusterEndpointIdentifier: aws.String(endpointId), + } + + output, err := conn.DescribeDBClusterEndpoints(input) + if err != nil { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if output == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + endpoints := output.DBClusterEndpoints + if len(endpoints) == 0 { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return endpoints[0], nil +} diff --git a/aws/internal/service/neptune/id.go b/aws/internal/service/neptune/id.go new file mode 100644 index 000000000000..12be11e52984 --- /dev/null +++ b/aws/internal/service/neptune/id.go @@ -0,0 +1,14 @@ +package glue + +import ( + "fmt" + "strings" +) + +func ReadAwsNeptuneClusterEndpointId(id string) (clusterIdentifier string, endpointIndetifer string, err error) { + idParts := strings.Split(id, ":") + if len(idParts) != 2 { + return "", "", fmt.Errorf("expected ID in format clusterIdentifier:endpointIndetifer, received: %s", id) + } + return idParts[0], idParts[1], nil +} diff --git a/aws/internal/service/neptune/waiter/status.go b/aws/internal/service/neptune/waiter/status.go index 01ed205572d8..20cb83867c36 100644 --- a/aws/internal/service/neptune/waiter/status.go +++ b/aws/internal/service/neptune/waiter/status.go @@ -4,6 +4,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/neptune" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/neptune/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -18,6 +20,9 @@ const ( // Cluster Unknown ClusterStatusUnknown = "Unknown" + + // DBClusterEndpoint Unknown + DBClusterEndpointStatusUnknown = "Unknown" ) // EventSubscriptionStatus fetches the EventSubscription and its Status @@ -59,6 +64,24 @@ func ClusterStatus(conn *neptune.Neptune, id string) resource.StateRefreshFunc { } cluster := output.DBClusters[0] + return cluster, aws.StringValue(cluster.Status), nil } } + +// DBClusterEndpointStatus fetches the DBClusterEndpoint and its Status +func DBClusterEndpointStatus(conn *neptune.Neptune, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.EndpointById(conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, DBClusterEndpointStatusUnknown, err + } + + return output, aws.StringValue(output.Status), nil + } +} diff --git a/aws/internal/service/neptune/waiter/waiter.go b/aws/internal/service/neptune/waiter/waiter.go index 5bfe74bc1778..7fd64dac1ce3 100644 --- a/aws/internal/service/neptune/waiter/waiter.go +++ b/aws/internal/service/neptune/waiter/waiter.go @@ -10,9 +10,15 @@ import ( const ( // Maximum amount of time to wait for an EventSubscription to return Deleted EventSubscriptionDeletedTimeout = 10 * time.Minute + + // Maximum amount of time to wait for an DBClusterEndpoint to return Available + DBClusterEndpointAvailableTimeout = 10 * time.Minute + + // Maximum amount of time to wait for an DBClusterEndpoint to return Deleted + DBClusterEndpointDeletedTimeout = 10 * time.Minute ) -// DeploymentDeployed waits for a EventSubscription to return Deleted +// EventSubscriptionDeleted waits for a EventSubscription to return Deleted func EventSubscriptionDeleted(conn *neptune.Neptune, subscriptionName string) (*neptune.EventSubscription, error) { stateConf := &resource.StateChangeConf{ Pending: []string{"deleting"}, @@ -81,3 +87,39 @@ func DBClusterAvailable(conn *neptune.Neptune, id string, timeout time.Duration) return nil, err } + +// DBClusterEndpointAvailable waits for a DBClusterEndpoint to return Available +func DBClusterEndpointAvailable(conn *neptune.Neptune, id string) (*neptune.DBClusterEndpoint, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"creating", "modifying"}, + Target: []string{"available"}, + Refresh: DBClusterEndpointStatus(conn, id), + Timeout: DBClusterEndpointAvailableTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*neptune.DBClusterEndpoint); ok { + return v, err + } + + return nil, err +} + +// DBClusterEndpointDeleted waits for a DBClusterEndpoint to return Deleted +func DBClusterEndpointDeleted(conn *neptune.Neptune, id string) (*neptune.DBClusterEndpoint, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting"}, + Target: []string{}, + Refresh: DBClusterEndpointStatus(conn, id), + Timeout: DBClusterEndpointDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*neptune.DBClusterEndpoint); ok { + return v, err + } + + return nil, err +} diff --git a/aws/provider.go b/aws/provider.go index 5e91aefcac2e..d0d6e9b9846d 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -893,6 +893,7 @@ func Provider() *schema.Provider { "aws_network_acl": resourceAwsNetworkAcl(), "aws_default_network_acl": resourceAwsDefaultNetworkAcl(), "aws_neptune_cluster": resourceAwsNeptuneCluster(), + "aws_neptune_cluster_endpoint": resourceAwsNeptuneClusterEndpoint(), "aws_neptune_cluster_instance": resourceAwsNeptuneClusterInstance(), "aws_neptune_cluster_parameter_group": resourceAwsNeptuneClusterParameterGroup(), "aws_neptune_cluster_snapshot": resourceAwsNeptuneClusterSnapshot(), diff --git a/aws/resource_aws_neptune_cluster_endpoint.go b/aws/resource_aws_neptune_cluster_endpoint.go new file mode 100644 index 000000000000..d00aced86c67 --- /dev/null +++ b/aws/resource_aws_neptune_cluster_endpoint.go @@ -0,0 +1,218 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/neptune" + "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/neptune/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/neptune/waiter" +) + +func resourceAwsNeptuneClusterEndpoint() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsNeptuneClusterEndpointCreate, + Read: resourceAwsNeptuneClusterEndpointRead, + Update: resourceAwsNeptuneClusterEndpointUpdate, + Delete: resourceAwsNeptuneClusterEndpointDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "cluster_identifier": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateNeptuneIdentifier, + }, + "cluster_endpoint_identifier": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateNeptuneIdentifier, + }, + "endpoint": { + Type: schema.TypeString, + Computed: true, + }, + "endpoint_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"READER", "WRITER", "ANY"}, false), + }, + "static_members": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + }, + "excluded_members": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + }, + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), + }, + + CustomizeDiff: SetTagsDiff, + } +} + +func resourceAwsNeptuneClusterEndpointCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).neptuneconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) + + input := &neptune.CreateDBClusterEndpointInput{ + DBClusterEndpointIdentifier: aws.String(d.Get("cluster_endpoint_identifier").(string)), + DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)), + EndpointType: aws.String(d.Get("endpoint_type").(string)), + Tags: tags.IgnoreAws().NeptuneTags(), + } + + if attr := d.Get("static_members").(*schema.Set); attr.Len() > 0 { + input.StaticMembers = expandStringSet(attr) + } + + if attr := d.Get("excluded_members").(*schema.Set); attr.Len() > 0 { + input.ExcludedMembers = expandStringSet(attr) + } + + out, err := conn.CreateDBClusterEndpoint(input) + if err != nil { + return fmt.Errorf("error creating Neptune Cluster Endpoint: %w", err) + } + + clusterId := aws.StringValue(out.DBClusterIdentifier) + endpointId := aws.StringValue(out.DBClusterEndpointIdentifier) + d.SetId(fmt.Sprintf("%s:%s", clusterId, endpointId)) + + _, err = waiter.DBClusterEndpointAvailable(conn, d.Id()) + if err != nil { + return fmt.Errorf("error waiting for Neptune Cluster Endpoint (%q) to be Available: %w", d.Id(), err) + } + + return resourceAwsNeptuneClusterEndpointRead(d, meta) + +} + +func resourceAwsNeptuneClusterEndpointRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).neptuneconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + resp, err := finder.EndpointById(conn, d.Id()) + if err != nil { + if tfawserr.ErrCodeEquals(err, neptune.ErrCodeDBClusterEndpointNotFoundFault) { + d.SetId("") + log.Printf("[DEBUG] Neptune Cluster Endpoint (%s) not found", d.Id()) + return nil + } + return fmt.Errorf("error describing Neptune Cluster Endpoint (%s): %w", d.Id(), err) + } + + d.Set("cluster_endpoint_identifier", resp.DBClusterEndpointIdentifier) + d.Set("cluster_identifier", resp.DBClusterIdentifier) + d.Set("endpoint_type", resp.CustomEndpointType) + d.Set("endpoint", resp.Endpoint) + d.Set("excluded_members", flattenStringSet(resp.ExcludedMembers)) + d.Set("static_members", flattenStringSet(resp.StaticMembers)) + + arn := aws.StringValue(resp.DBClusterEndpointArn) + d.Set("arn", arn) + + tags, err := keyvaluetags.NeptuneListTags(conn, arn) + + if err != nil { + return fmt.Errorf("error listing tags for Neptune Cluster Endpoint (%s): %w", arn, 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_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) + } + return nil +} + +func resourceAwsNeptuneClusterEndpointUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).neptuneconn + + if d.HasChangeExcept("tags_all") { + req := &neptune.ModifyDBClusterEndpointInput{ + DBClusterEndpointIdentifier: aws.String(d.Get("cluster_endpoint_identifier").(string)), + } + + if d.HasChange("endpoint_type") { + req.EndpointType = aws.String(d.Get("endpoint_type").(string)) + } + + if d.HasChange("static_members") { + req.StaticMembers = expandStringSet(d.Get("static_members").(*schema.Set)) + } + + if d.HasChange("excluded_members") { + req.ExcludedMembers = expandStringSet(d.Get("excluded_members").(*schema.Set)) + } + + _, err := conn.ModifyDBClusterEndpoint(req) + if err != nil { + return fmt.Errorf("error updating Neptune Cluster Endpoint (%q): %w", d.Id(), err) + } + + _, err = waiter.DBClusterEndpointAvailable(conn, d.Id()) + if err != nil { + return fmt.Errorf("error waiting for Neptune Cluster Endpoint (%q) to be Available: %w", d.Id(), err) + } + } + + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + + if err := keyvaluetags.NeptuneUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating Neptune Cluster Endpoint (%s) tags: %w", d.Get("arn").(string), err) + } + + } + + return resourceAwsNeptuneClusterEndpointRead(d, meta) +} + +func resourceAwsNeptuneClusterEndpointDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).neptuneconn + + endpointId := d.Get("cluster_endpoint_identifier").(string) + input := &neptune.DeleteDBClusterEndpointInput{ + DBClusterEndpointIdentifier: aws.String(endpointId), + } + + _, err := conn.DeleteDBClusterEndpoint(input) + if err != nil { + return fmt.Errorf("Neptune Cluster Endpoint cannot be deleted: %w", err) + } + _, err = waiter.DBClusterEndpointDeleted(conn, d.Id()) + if err != nil { + if tfawserr.ErrCodeEquals(err, neptune.ErrCodeDBClusterEndpointNotFoundFault) { + return nil + } + return fmt.Errorf("error waiting for Neptune Cluster Endpoint (%q) to be Deleted: %w", d.Id(), err) + } + + return nil +} diff --git a/aws/resource_aws_neptune_cluster_endpoint_test.go b/aws/resource_aws_neptune_cluster_endpoint_test.go new file mode 100644 index 000000000000..3e43651d22da --- /dev/null +++ b/aws/resource_aws_neptune_cluster_endpoint_test.go @@ -0,0 +1,252 @@ +package aws + +import ( + //"errors" + "fmt" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/service/neptune" + "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/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/neptune/finder" +) + +func TestAccAWSNeptuneClusterEndpoint_basic(t *testing.T) { + var dbCluster neptune.DBClusterEndpoint + rName := acctest.RandomWithPrefix("tf-acc") + resourceName := "aws_neptune_cluster_endpoint.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, neptune.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNeptuneClusterEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSNeptuneClusterEndpointConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNeptuneClusterEndpointExists(resourceName, &dbCluster), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "rds", regexp.MustCompile(`cluster-endpoint:.+`)), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "READER"), + resource.TestCheckResourceAttr(resourceName, "cluster_endpoint_identifier", rName), + resource.TestCheckResourceAttrPair(resourceName, "cluster_identifier", "aws_neptune_cluster.test", "cluster_identifier"), + resource.TestCheckResourceAttr(resourceName, "tags.#", "0"), + resource.TestCheckResourceAttr(resourceName, "static_members.#", "0"), + resource.TestCheckResourceAttr(resourceName, "excluded_members.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSNeptuneClusterEndpoint_tags(t *testing.T) { + var v neptune.DBClusterEndpoint + rName := acctest.RandomWithPrefix("tf-acc") + resourceName := "aws_neptune_cluster_endpoint.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, neptune.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNeptuneClusterEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSNeptuneClusterEndpointConfigTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNeptuneClusterEndpointExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSNeptuneClusterEndpointConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNeptuneClusterEndpointExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSNeptuneClusterEndpointConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNeptuneClusterEndpointExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func TestAccAWSNeptuneClusterEndpoint_disappears(t *testing.T) { + var dbCluster neptune.DBClusterEndpoint + rName := acctest.RandomWithPrefix("tf-acc") + resourceName := "aws_neptune_cluster_endpoint.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, neptune.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNeptuneClusterEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSNeptuneClusterEndpointConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNeptuneClusterEndpointExists(resourceName, &dbCluster), + testAccCheckResourceDisappears(testAccProvider, resourceAwsNeptuneClusterEndpoint(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSNeptuneClusterEndpoint_disappears_cluster(t *testing.T) { + var dbCluster neptune.DBClusterEndpoint + rName := acctest.RandomWithPrefix("tf-acc") + resourceName := "aws_neptune_cluster_endpoint.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, neptune.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSNeptuneClusterEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSNeptuneClusterEndpointConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSNeptuneClusterEndpointExists(resourceName, &dbCluster), + testAccCheckResourceDisappears(testAccProvider, resourceAwsNeptuneCluster(), "aws_neptune_cluster.test"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSNeptuneClusterEndpointDestroy(s *terraform.State) error { + return testAccCheckAWSNeptuneClusterEndpointDestroyWithProvider(s, testAccProvider) +} + +func testAccCheckAWSNeptuneClusterEndpointDestroyWithProvider(s *terraform.State, provider *schema.Provider) error { + conn := provider.Meta().(*AWSClient).neptuneconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_neptune_cluster_endpoint" { + continue + } + + _, err := finder.EndpointById(conn, rs.Primary.ID) + // Return nil if the cluster is already destroyed + if err != nil { + if isAWSErr(err, neptune.ErrCodeDBClusterNotFoundFault, "") { + return nil + } + } + + return err + } + + return nil +} + +func testAccCheckAWSNeptuneClusterEndpointExists(n string, v *neptune.DBClusterEndpoint) resource.TestCheckFunc { + return testAccCheckAWSNeptuneClusterEndpointExistsWithProvider(n, v, func() *schema.Provider { return testAccProvider }) +} + +func testAccCheckAWSNeptuneClusterEndpointExistsWithProvider(n string, v *neptune.DBClusterEndpoint, providerF func() *schema.Provider) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Neptune Instance ID is set") + } + + provider := providerF() + conn := provider.Meta().(*AWSClient).neptuneconn + resp, err := finder.EndpointById(conn, rs.Primary.ID) + if err != nil { + return fmt.Errorf("Neptune Cluster Endpoint (%s) not found: %w", rs.Primary.ID, err) + } + + *v = *resp + + return nil + } +} + +func testAccAWSNeptuneClusterEndpointConfigBase(rName string) string { + return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(` +locals { + availability_zone_names = slice(data.aws_availability_zones.available.names, 0, min(3, length(data.aws_availability_zones.available.names))) +} + +resource "aws_neptune_cluster" "test" { + cluster_identifier = %[1]q + availability_zones = local.availability_zone_names + engine = "neptune" + neptune_cluster_parameter_group_name = "default.neptune1" + skip_final_snapshot = true +} +`, rName)) +} + +func testAccAWSNeptuneClusterEndpointConfig(rName string) string { + return composeConfig(testAccAWSNeptuneClusterEndpointConfigBase(rName), fmt.Sprintf(` +resource "aws_neptune_cluster_endpoint" "test" { + cluster_identifier = aws_neptune_cluster.test.cluster_identifier + cluster_endpoint_identifier = %[1]q + endpoint_type = "READER" +} +`, rName)) +} + +func testAccAWSNeptuneClusterEndpointConfigTags1(rName, tagKey1, tagValue1 string) string { + return composeConfig(testAccAWSNeptuneClusterEndpointConfigBase(rName), fmt.Sprintf(` +resource "aws_neptune_cluster" "test" { + cluster_identifier = %[1]q + availability_zones = local.availability_zone_names + engine = "neptune" + neptune_cluster_parameter_group_name = "default.neptune1" + skip_final_snapshot = true + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1)) +} + +func testAccAWSNeptuneClusterEndpointConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return composeConfig(testAccAWSNeptuneClusterEndpointConfigBase(rName), fmt.Sprintf(` +resource "aws_neptune_cluster" "test" { + cluster_identifier = %[1]q + availability_zones = local.availability_zone_names + engine = "neptune" + neptune_cluster_parameter_group_name = "default.neptune1" + skip_final_snapshot = true + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) +} From bca41dd8119a745f4a457bd26c6a70d41839d1e3 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 19 Jun 2021 20:24:18 +0300 Subject: [PATCH 0669/1208] fix disappears --- aws/internal/service/neptune/finder/finder.go | 9 ++++++++- aws/resource_aws_neptune_cluster_endpoint.go | 16 ++++++++++----- ...ource_aws_neptune_cluster_endpoint_test.go | 20 ++++++++----------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/aws/internal/service/neptune/finder/finder.go b/aws/internal/service/neptune/finder/finder.go index 196fc2ae5a7d..d46df9c82385 100644 --- a/aws/internal/service/neptune/finder/finder.go +++ b/aws/internal/service/neptune/finder/finder.go @@ -3,6 +3,7 @@ package finder import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/neptune" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" tfneptune "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/neptune" ) @@ -18,13 +19,19 @@ func EndpointById(conn *neptune.Neptune, id string) (*neptune.DBClusterEndpoint, } output, err := conn.DescribeDBClusterEndpoints(input) - if err != nil { + + if tfawserr.ErrCodeEquals(err, neptune.ErrCodeDBClusterEndpointNotFoundFault) || + tfawserr.ErrCodeEquals(err, neptune.ErrCodeDBClusterNotFoundFault) { return nil, &resource.NotFoundError{ LastError: err, LastRequest: input, } } + if err != nil { + return nil, err + } + if output == nil { return nil, &resource.NotFoundError{ Message: "Empty result", diff --git a/aws/resource_aws_neptune_cluster_endpoint.go b/aws/resource_aws_neptune_cluster_endpoint.go index d00aced86c67..b1edcab3db63 100644 --- a/aws/resource_aws_neptune_cluster_endpoint.go +++ b/aws/resource_aws_neptune_cluster_endpoint.go @@ -12,6 +12,7 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/neptune/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/neptune/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsNeptuneClusterEndpoint() *schema.Resource { @@ -113,12 +114,13 @@ func resourceAwsNeptuneClusterEndpointRead(d *schema.ResourceData, meta interfac ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig resp, err := finder.EndpointById(conn, d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + d.SetId("") + log.Printf("[DEBUG] Neptune Cluster Endpoint (%s) not found", d.Id()) + return nil + } + if err != nil { - if tfawserr.ErrCodeEquals(err, neptune.ErrCodeDBClusterEndpointNotFoundFault) { - d.SetId("") - log.Printf("[DEBUG] Neptune Cluster Endpoint (%s) not found", d.Id()) - return nil - } return fmt.Errorf("error describing Neptune Cluster Endpoint (%s): %w", d.Id(), err) } @@ -204,6 +206,10 @@ func resourceAwsNeptuneClusterEndpointDelete(d *schema.ResourceData, meta interf _, err := conn.DeleteDBClusterEndpoint(input) if err != nil { + if tfawserr.ErrCodeEquals(err, neptune.ErrCodeDBClusterEndpointNotFoundFault) || + tfawserr.ErrCodeEquals(err, neptune.ErrCodeDBClusterNotFoundFault) { + return nil + } return fmt.Errorf("Neptune Cluster Endpoint cannot be deleted: %w", err) } _, err = waiter.DBClusterEndpointDeleted(conn, d.Id()) diff --git a/aws/resource_aws_neptune_cluster_endpoint_test.go b/aws/resource_aws_neptune_cluster_endpoint_test.go index 3e43651d22da..26a3d19086b6 100644 --- a/aws/resource_aws_neptune_cluster_endpoint_test.go +++ b/aws/resource_aws_neptune_cluster_endpoint_test.go @@ -220,12 +220,10 @@ resource "aws_neptune_cluster_endpoint" "test" { func testAccAWSNeptuneClusterEndpointConfigTags1(rName, tagKey1, tagValue1 string) string { return composeConfig(testAccAWSNeptuneClusterEndpointConfigBase(rName), fmt.Sprintf(` -resource "aws_neptune_cluster" "test" { - cluster_identifier = %[1]q - availability_zones = local.availability_zone_names - engine = "neptune" - neptune_cluster_parameter_group_name = "default.neptune1" - skip_final_snapshot = true +resource "aws_neptune_cluster_endpoint" "test" { + cluster_identifier = aws_neptune_cluster.test.cluster_identifier + cluster_endpoint_identifier = %[1]q + endpoint_type = "READER" tags = { %[2]q = %[3]q @@ -236,12 +234,10 @@ resource "aws_neptune_cluster" "test" { func testAccAWSNeptuneClusterEndpointConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return composeConfig(testAccAWSNeptuneClusterEndpointConfigBase(rName), fmt.Sprintf(` -resource "aws_neptune_cluster" "test" { - cluster_identifier = %[1]q - availability_zones = local.availability_zone_names - engine = "neptune" - neptune_cluster_parameter_group_name = "default.neptune1" - skip_final_snapshot = true +resource "aws_neptune_cluster_endpoint" "test" { + cluster_identifier = aws_neptune_cluster.test.cluster_identifier + cluster_endpoint_identifier = %[1]q + endpoint_type = "READER" tags = { %[2]q = %[3]q From 8ecb04b34927b2e63a5dcecf1bc25e23270ab7e9 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 19 Jun 2021 20:31:55 +0300 Subject: [PATCH 0670/1208] docs --- .../r/neptune_cluster_endpoint.html.markdown | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 website/docs/r/neptune_cluster_endpoint.html.markdown diff --git a/website/docs/r/neptune_cluster_endpoint.html.markdown b/website/docs/r/neptune_cluster_endpoint.html.markdown new file mode 100644 index 000000000000..8f99b146b2a6 --- /dev/null +++ b/website/docs/r/neptune_cluster_endpoint.html.markdown @@ -0,0 +1,49 @@ +--- +subcategory: "Neptune" +layout: "aws" +page_title: "AWS: aws_neptune_cluster_endpoint" +description: |- + Provides an Neptune Cluster Endpoint Resource +--- + +# Resource: aws_neptune_cluster_endpoint + +Provides an Neptune Cluster Endpoint Resource. + +## Example Usage + +```terraform +resource "aws_neptune_cluster_endpoint" "example" { + cluster_identifier = aws_neptune_cluster.test.cluster_identifier + cluster_endpoint_identifier = "example" + endpoint_type = "READER" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `cluster_identifier` - (Required, Forces new resources) The DB cluster identifier of the DB cluster associated with the endpoint. +* `cluster_identifier_endpoint` - (Required, Forces new resources) The identifier of the endpoint. +* `endpoint_type` - (Required) The type of the endpoint. One of: `READER`, `WRITER`, `ANY`. +* `excluded_members` - (Optional) List of DB instance identifiers that aren't part of the custom endpoint group. All other eligible instances are reachable through the custom endpoint. Only relevant if the list of static members is empty. +* `static_members` - (Optional) List of DB instance identifiers that are part of the custom endpoint group. +* `tags` - (Optional) A map of tags to assign to the Neptune cluster. 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 Neptune Cluster Endpoint Amazon Resource Name (ARN). +* `endpoint` - The DNS address of the endpoint. +* `id` - The Neptune Cluster Endpoint Identifier. +* `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_neptune_cluster_endpoint` can be imported by using the `cluster-identifier:endpoint-identfier`, e.g. + +``` +$ terraform import aws_neptune_cluster_endpoint.example my-cluster:my-endpoint +``` From 63482a3127a0da272de5b09080f14b15bf32821e Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 19 Jun 2021 20:34:48 +0300 Subject: [PATCH 0671/1208] changelog --- .changelog/19898.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19898.txt diff --git a/.changelog/19898.txt b/.changelog/19898.txt new file mode 100644 index 000000000000..698d9aaaebfb --- /dev/null +++ b/.changelog/19898.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_neptune_cluster_endpoint +``` From 4be2635b9534d4c7efbdbca5b721050474f022bc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 22 Jun 2021 10:12:48 -0400 Subject: [PATCH 0672/1208] r/aws_neptune_cluster_endpoint: GovCloud 'InvalidParameterValue: Tagging endpoints is currently not available'. --- aws/resource_aws_neptune_cluster_endpoint.go | 40 ++++++++++++------- ...ource_aws_neptune_cluster_endpoint_test.go | 4 ++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/aws/resource_aws_neptune_cluster_endpoint.go b/aws/resource_aws_neptune_cluster_endpoint.go index b1edcab3db63..555c0cb2e0ca 100644 --- a/aws/resource_aws_neptune_cluster_endpoint.go +++ b/aws/resource_aws_neptune_cluster_endpoint.go @@ -5,6 +5,7 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/service/neptune" "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -79,7 +80,6 @@ func resourceAwsNeptuneClusterEndpointCreate(d *schema.ResourceData, meta interf DBClusterEndpointIdentifier: aws.String(d.Get("cluster_endpoint_identifier").(string)), DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)), EndpointType: aws.String(d.Get("endpoint_type").(string)), - Tags: tags.IgnoreAws().NeptuneTags(), } if attr := d.Get("static_members").(*schema.Set); attr.Len() > 0 { @@ -90,6 +90,11 @@ func resourceAwsNeptuneClusterEndpointCreate(d *schema.ResourceData, meta interf input.ExcludedMembers = expandStringSet(attr) } + // Tags are currently only supported in AWS Commercial. + if len(tags) > 0 && meta.(*AWSClient).partition == endpoints.AwsPartitionID { + input.Tags = tags.IgnoreAws().NeptuneTags() + } + out, err := conn.CreateDBClusterEndpoint(input) if err != nil { return fmt.Errorf("error creating Neptune Cluster Endpoint: %w", err) @@ -134,22 +139,29 @@ func resourceAwsNeptuneClusterEndpointRead(d *schema.ResourceData, meta interfac arn := aws.StringValue(resp.DBClusterEndpointArn) d.Set("arn", arn) - tags, err := keyvaluetags.NeptuneListTags(conn, arn) + // Tags are currently only supported in AWS Commercial. + if meta.(*AWSClient).partition == endpoints.AwsPartitionID { + tags, err := keyvaluetags.NeptuneListTags(conn, arn) - if err != nil { - return fmt.Errorf("error listing tags for Neptune Cluster Endpoint (%s): %w", arn, err) - } + if err != nil { + return fmt.Errorf("error listing tags for Neptune Cluster Endpoint (%s): %w", arn, err) + } - tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) + 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) - } + //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_all", tags.Map()); err != nil { - return fmt.Errorf("error setting tags_all: %w", err) + if err := d.Set("tags_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) + } + } else { + d.Set("tags", nil) + d.Set("tags_all", nil) } + return nil } @@ -184,13 +196,13 @@ func resourceAwsNeptuneClusterEndpointUpdate(d *schema.ResourceData, meta interf } } - if d.HasChange("tags_all") { + // Tags are currently only supported in AWS Commercial. + if d.HasChange("tags_all") && meta.(*AWSClient).partition == endpoints.AwsPartitionID { o, n := d.GetChange("tags_all") if err := keyvaluetags.NeptuneUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating Neptune Cluster Endpoint (%s) tags: %w", d.Get("arn").(string), err) } - } return resourceAwsNeptuneClusterEndpointRead(d, meta) diff --git a/aws/resource_aws_neptune_cluster_endpoint_test.go b/aws/resource_aws_neptune_cluster_endpoint_test.go index 26a3d19086b6..64ec8f3fee31 100644 --- a/aws/resource_aws_neptune_cluster_endpoint_test.go +++ b/aws/resource_aws_neptune_cluster_endpoint_test.go @@ -48,6 +48,10 @@ func TestAccAWSNeptuneClusterEndpoint_basic(t *testing.T) { } func TestAccAWSNeptuneClusterEndpoint_tags(t *testing.T) { + if testAccGetPartition() == "aws-us-gov" { + t.Skip("Neptune Cluster Endpoint tags are not supported in GovCloud partition") + } + var v neptune.DBClusterEndpoint rName := acctest.RandomWithPrefix("tf-acc") resourceName := "aws_neptune_cluster_endpoint.test" From 8d410f4251b58184c082252d6ee395bda295a394 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 22 Jun 2021 12:17:42 -0400 Subject: [PATCH 0673/1208] sweeper: Switch to use tfresource --- aws/aws_sweeper_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/aws_sweeper_test.go b/aws/aws_sweeper_test.go index 16e7470a5d9a..49bf9e6e23f4 100644 --- a/aws/aws_sweeper_test.go +++ b/aws/aws_sweeper_test.go @@ -90,7 +90,7 @@ func testSweepResourceOrchestratorContext(ctx context.Context, sweepResources [] sweepResource := sweepResource g.Go(func() error { - err := RetryConfigContext(ctx, delay, delayRand, minTimeout, pollInterval, timeout, func() *resource.RetryError { + err := tfresource.RetryConfigContext(ctx, delay, delayRand, minTimeout, pollInterval, timeout, func() *resource.RetryError { err := testAccDeleteResource(sweepResource.resource, sweepResource.d, sweepResource.meta) if err != nil { From 7f35420632b467fb93e625a35a9bd92744e4e134 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 22 Jun 2021 12:18:07 -0400 Subject: [PATCH 0674/1208] tfresource: New retry func --- aws/internal/tfresource/retry.go | 71 ++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/aws/internal/tfresource/retry.go b/aws/internal/tfresource/retry.go index 517a6b219334..2e30512c4321 100644 --- a/aws/internal/tfresource/retry.go +++ b/aws/internal/tfresource/retry.go @@ -1,6 +1,9 @@ package tfresource import ( + "context" + "math/rand" + "sync" "time" "github.com/hashicorp/aws-sdk-go-base/tfawserr" @@ -39,3 +42,71 @@ func RetryWhenAwsErrCodeEquals(timeout time.Duration, f func() (interface{}, err return output, nil } + +func RetryConfigContext(ctx context.Context, delay time.Duration, delayRand time.Duration, minTimeout time.Duration, pollInterval time.Duration, timeout time.Duration, f resource.RetryFunc) error { + // These are used to pull the error out of the function; need a mutex to + // avoid a data race. + var resultErr error + var resultErrMu sync.Mutex + + c := &resource.StateChangeConf{ + Pending: []string{"retryableerror"}, + Target: []string{"success"}, + Timeout: timeout, + Refresh: func() (interface{}, string, error) { + rerr := f() + + resultErrMu.Lock() + defer resultErrMu.Unlock() + + if rerr == nil { + resultErr = nil + return 42, "success", nil + } + + resultErr = rerr.Err + + if rerr.Retryable { + return 42, "retryableerror", nil + } + + return nil, "quit", rerr.Err + }, + } + + if delay.Milliseconds() > 0 { + c.Delay = delay + } + + if delayRand.Milliseconds() > 0 { + // Hitting the API at exactly the same time on each iteration of the retry is more likely to + // cause Throttling problems. We introduce randomness in order to help AWS be happier. + rand.Seed(time.Now().UTC().UnixNano()) + + c.Delay = time.Duration(rand.Int63n(delayRand.Milliseconds())) * time.Millisecond + } + + if minTimeout.Milliseconds() > 0 { + c.MinTimeout = minTimeout + } + + if pollInterval.Milliseconds() > 0 { + c.PollInterval = pollInterval + } + + _, waitErr := c.WaitForStateContext(ctx) + + // Need to acquire the lock here to be able to avoid race using resultErr as + // the return value + resultErrMu.Lock() + defer resultErrMu.Unlock() + + // resultErr may be nil because the wait timed out and resultErr was never + // set; this is still an error + if resultErr == nil { + return waitErr + } + // resultErr takes precedence over waitErr if both are set because it is + // more likely to be useful + return resultErr +} From e868a0b5aa10544c2d959e5e44c034f42289e3e5 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 22 Jun 2021 12:18:29 -0400 Subject: [PATCH 0675/1208] tests/tfresource: Unit test new retry func --- aws/internal/tfresource/retry_test.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/aws/internal/tfresource/retry_test.go b/aws/internal/tfresource/retry_test.go index 8a396b9e3de5..2edbf74723da 100644 --- a/aws/internal/tfresource/retry_test.go +++ b/aws/internal/tfresource/retry_test.go @@ -1,12 +1,15 @@ package tfresource_test import ( + "context" "errors" + "fmt" "sync/atomic" "testing" "time" "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -71,3 +74,26 @@ func TestRetryWhenAwsErrCodeEquals(t *testing.T) { }) } } + +func TestRetryConfigContext_error(t *testing.T) { + t.Parallel() + + expected := fmt.Errorf("nope") + f := func() *resource.RetryError { + return resource.NonRetryableError(expected) + } + + errCh := make(chan error) + go func() { + errCh <- tfresource.RetryConfigContext(context.Background(), 0*time.Second, 0*time.Second, 0*time.Second, 0*time.Second, 1*time.Second, f) + }() + + select { + case err := <-errCh: + if err != expected { + t.Fatalf("bad: %#v", err) + } + case <-time.After(5 * time.Second): + t.Fatal("timeout") + } +} From 6e33e0073880bb01f0322364ac01bbdf0a63985e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 22 Jun 2021 12:19:16 -0400 Subject: [PATCH 0676/1208] r/route53_zone: Use new retry func to avoid throttling --- aws/resource_aws_route53_zone.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index 85a141356127..99411f34e388 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -411,7 +411,7 @@ func dnsSECStatus(conn *route53.Route53, hostedZoneID string) (string, error) { } var output *route53.GetDNSSECOutput - err := RetryConfigContext(context.Background(), 0*time.Millisecond, 1*time.Minute, 0*time.Millisecond, 30*time.Second, 3*time.Minute, func() *resource.RetryError { + err := tfresource.RetryConfigContext(context.Background(), 0*time.Millisecond, 1*time.Minute, 0*time.Millisecond, 30*time.Second, 3*time.Minute, func() *resource.RetryError { var err error output, err = conn.GetDNSSEC(input) @@ -467,7 +467,7 @@ func disableDNSSECForZone(conn *route53.Route53, hostedZoneId string) error { } var output *route53.DisableHostedZoneDNSSECOutput - err = RetryConfigContext(context.Background(), 0*time.Millisecond, 1*time.Minute, 0*time.Millisecond, 20*time.Second, 5*time.Minute, func() *resource.RetryError { + err = tfresource.RetryConfigContext(context.Background(), 0*time.Millisecond, 1*time.Minute, 0*time.Millisecond, 20*time.Second, 5*time.Minute, func() *resource.RetryError { var err error output, err = conn.DisableHostedZoneDNSSEC(input) From b47b8cb060a1c10b5defb15c831f6be8e861cb4b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 22 Jun 2021 12:19:37 -0400 Subject: [PATCH 0677/1208] Move retry to internal --- aws/retry.go | 78 ---------------------------------------------------- 1 file changed, 78 deletions(-) delete mode 100644 aws/retry.go diff --git a/aws/retry.go b/aws/retry.go deleted file mode 100644 index fa64cbf6f77e..000000000000 --- a/aws/retry.go +++ /dev/null @@ -1,78 +0,0 @@ -package aws - -import ( - "context" - "math/rand" - "sync" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func RetryConfigContext(ctx context.Context, delay time.Duration, delayRand time.Duration, minTimeout time.Duration, pollInterval time.Duration, timeout time.Duration, f resource.RetryFunc) error { - // These are used to pull the error out of the function; need a mutex to - // avoid a data race. - var resultErr error - var resultErrMu sync.Mutex - - c := &resource.StateChangeConf{ - Pending: []string{"retryableerror"}, - Target: []string{"success"}, - Timeout: timeout, - Refresh: func() (interface{}, string, error) { - rerr := f() - - resultErrMu.Lock() - defer resultErrMu.Unlock() - - if rerr == nil { - resultErr = nil - return 42, "success", nil - } - - resultErr = rerr.Err - - if rerr.Retryable { - return 42, "retryableerror", nil - } - - return nil, "quit", rerr.Err - }, - } - - if delay.Milliseconds() > 0 { - c.Delay = delay - } - - if delayRand.Milliseconds() > 0 { - // Hitting the API at exactly the same time on each iteration of the retry is more likely to - // cause Throttling problems. We introduce randomness in order to help AWS be happier. - rand.Seed(time.Now().UTC().UnixNano()) - - c.Delay = time.Duration(rand.Int63n(delayRand.Milliseconds())) * time.Millisecond - } - - if minTimeout.Milliseconds() > 0 { - c.MinTimeout = minTimeout - } - - if pollInterval.Milliseconds() > 0 { - c.PollInterval = pollInterval - } - - _, waitErr := c.WaitForStateContext(ctx) - - // Need to acquire the lock here to be able to avoid race using resultErr as - // the return value - resultErrMu.Lock() - defer resultErrMu.Unlock() - - // resultErr may be nil because the wait timed out and resultErr was never - // set; this is still an error - if resultErr == nil { - return waitErr - } - // resultErr takes precedence over waitErr if both are set because it is - // more likely to be useful - return resultErr -} From 4b5763e60c2f0b510aa115a1d77d65dee21dec56 Mon Sep 17 00:00:00 2001 From: shuheiktgw Date: Wed, 10 Mar 2021 07:37:08 +0900 Subject: [PATCH 0678/1208] Add efs_file_system_backup_policy resource --- aws/internal/service/efs/finder/finder.go | 24 +++ aws/internal/service/efs/waiter/status.go | 18 +++ aws/internal/service/efs/waiter/waiter.go | 42 ++++- aws/provider.go | 1 + ...ource_aws_efs_file_system_backup_policy.go | 143 ++++++++++++++++++ 5 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 aws/internal/service/efs/finder/finder.go create mode 100644 aws/resource_aws_efs_file_system_backup_policy.go diff --git a/aws/internal/service/efs/finder/finder.go b/aws/internal/service/efs/finder/finder.go new file mode 100644 index 000000000000..efeb33896e57 --- /dev/null +++ b/aws/internal/service/efs/finder/finder.go @@ -0,0 +1,24 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/efs" +) + +// FileSystemBackupPolicyById returns the EFS Backup Policy corresponding to the specified Id. +// Returns nil if no policy is found. +func FileSystemBackupPolicyById(conn *efs.EFS, id string) (*efs.BackupPolicy, error) { + output, err := conn.DescribeBackupPolicy(&efs.DescribeBackupPolicyInput{ + FileSystemId: aws.String(id), + }) + + if err != nil { + return nil, err + } + + if output == nil { + return nil, nil + } + + return output.BackupPolicy, nil +} diff --git a/aws/internal/service/efs/waiter/status.go b/aws/internal/service/efs/waiter/status.go index 97d4f7d1612d..27a8d2e28aa6 100644 --- a/aws/internal/service/efs/waiter/status.go +++ b/aws/internal/service/efs/waiter/status.go @@ -4,6 +4,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/efs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/efs/finder" ) // AccessPointLifeCycleState fetches the Access Point and its LifecycleState @@ -29,6 +30,23 @@ func AccessPointLifeCycleState(conn *efs.EFS, accessPointId string) resource.Sta } } +// FileSystemBackupPolicyStatus fetches the EFS Backup Policy status +func FileSystemBackupPolicyStatus(conn *efs.EFS, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + bp, err := finder.FileSystemBackupPolicyById(conn, id) + + if err != nil { + return nil, "", err + } + + if bp == nil { + return nil, "", nil + } + + return bp, aws.StringValue(bp.Status), nil + } +} + // FileSystemLifeCycleState fetches the Access Point and its LifecycleState func FileSystemLifeCycleState(conn *efs.EFS, fileSystemID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { diff --git a/aws/internal/service/efs/waiter/waiter.go b/aws/internal/service/efs/waiter/waiter.go index fd065e5c89d4..47fe932d2a8e 100644 --- a/aws/internal/service/efs/waiter/waiter.go +++ b/aws/internal/service/efs/waiter/waiter.go @@ -17,6 +17,10 @@ const ( FileSystemDeletedTimeout = 10 * time.Minute FileSystemDeletedDelayTimeout = 2 * time.Second FileSystemDeletedMinTimeout = 3 * time.Second + + // Maximum amount of time to wait for an EFS Backup policy operation + FileSystemBackupPolicyCreatedTimeout = 10 * time.Minute + FileSystemBackupPolicyDeletedTimeout = 10 * time.Minute ) // AccessPointCreated waits for an Operation to return Success @@ -37,7 +41,7 @@ func AccessPointCreated(conn *efs.EFS, accessPointId string) (*efs.AccessPointDe return nil, err } -// AccessPointDelete waits for an Access Point to return Deleted +// AccessPointDeleted waits for an Access Point to return Deleted func AccessPointDeleted(conn *efs.EFS, accessPointId string) (*efs.AccessPointDescription, error) { stateConf := &resource.StateChangeConf{ Pending: []string{efs.LifeCycleStateAvailable, efs.LifeCycleStateDeleting, efs.LifeCycleStateDeleted}, @@ -94,3 +98,39 @@ func FileSystemDeleted(conn *efs.EFS, fileSystemID string) (*efs.FileSystemDescr return nil, err } + +// FileSystemBackupPolicyCreated waits for a EFS Backup Policy creation +func FileSystemBackupPolicyCreated(conn *efs.EFS, id string) (*efs.BackupPolicy, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{efs.StatusEnabling}, + Target: []string{efs.StatusEnabled}, + Refresh: FileSystemBackupPolicyStatus(conn, id), + Timeout: FileSystemBackupPolicyCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*efs.BackupPolicy); ok { + return output, err + } + + return nil, err +} + +// FileSystemBackupPolicyDeleted waits for a EFS Backup Policy deletion +func FileSystemBackupPolicyDeleted(conn *efs.EFS, id string) (*efs.BackupPolicy, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{efs.StatusDisabling}, + Target: []string{efs.StatusDisabled}, + Refresh: FileSystemBackupPolicyStatus(conn, id), + Timeout: FileSystemBackupPolicyDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*efs.BackupPolicy); ok { + return output, err + } + + return nil, err +} diff --git a/aws/provider.go b/aws/provider.go index d0d6e9b9846d..5d6981bcf751 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -714,6 +714,7 @@ func Provider() *schema.Provider { "aws_ecs_task_definition": resourceAwsEcsTaskDefinition(), "aws_efs_access_point": resourceAwsEfsAccessPoint(), "aws_efs_file_system": resourceAwsEfsFileSystem(), + "aws_efs_file_system_backup_policy": resourceAwsEfsFileSystemBackupPolicy(), "aws_efs_file_system_policy": resourceAwsEfsFileSystemPolicy(), "aws_efs_mount_target": resourceAwsEfsMountTarget(), "aws_egress_only_internet_gateway": resourceAwsEgressOnlyInternetGateway(), diff --git a/aws/resource_aws_efs_file_system_backup_policy.go b/aws/resource_aws_efs_file_system_backup_policy.go new file mode 100644 index 000000000000..f0d8bf63dd71 --- /dev/null +++ b/aws/resource_aws_efs_file_system_backup_policy.go @@ -0,0 +1,143 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/efs" + "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/service/efs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/efs/waiter" +) + +func resourceAwsEfsFileSystemBackupPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsEfsFileSystemBackupPolicyPut, + Read: resourceAwsEfsFileSystemBackupPolicyRead, + Delete: resourceAwsEfsFileSystemBackupPolicyDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "file_system_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "backup_policy": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + efs.StatusEnabled, + }, false), + }, + }, + }, + }, + }, + } +} + +func resourceAwsEfsFileSystemBackupPolicyPut(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).efsconn + + fsId := d.Get("file_system_id").(string) + input := &efs.PutBackupPolicyInput{ + FileSystemId: aws.String(fsId), + } + + if v, ok := d.GetOk("backup_policy"); ok { + input.BackupPolicy = expandEfsFileSystemBackupPolicy(v.([]interface{})) + } + + log.Printf("[DEBUG] Adding EFS File System Backup Policy: %#v", input) + _, err := conn.PutBackupPolicy(input) + if err != nil { + return fmt.Errorf("error creating EFS File System Backup Policy %q: %s", fsId, err.Error()) + } + + d.SetId(fsId) + + if _, err := waiter.FileSystemBackupPolicyCreated(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for EFS File System Backup Policy (%q) creation : %s", d.Id(), err) + } + + return resourceAwsEfsFileSystemBackupPolicyRead(d, meta) +} + +func resourceAwsEfsFileSystemBackupPolicyRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).efsconn + + bp, err := finder.FileSystemBackupPolicyById(conn, d.Id()) + if err != nil { + if isAWSErr(err, efs.ErrCodeFileSystemNotFound, "") { + log.Printf("[WARN] EFS File System (%q) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + if isAWSErr(err, efs.ErrCodePolicyNotFound, "") { + log.Printf("[WARN] EFS File System Backup Policy (%q) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("error describing policy for EFS File System Backup Policy (%q): %s", d.Id(), err) + } + + if bp == nil || aws.StringValue(bp.Status) == efs.StatusDisabled { + log.Printf("[WARN] EFS File System Backup Policy (%q) is disabled, removing from state", d.Id()) + d.SetId("") + return nil + } + + d.Set("file_system_id", d.Id()) + if err := d.Set("backup_policy", flattenEfsFileSystemBackupPolicy(bp)); err != nil { + return fmt.Errorf("error setting backup_policy: %s", err) + } + + return nil +} + +func resourceAwsEfsFileSystemBackupPolicyDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).efsconn + + log.Printf("[DEBUG] Deleting EFS File System Backup Policy: %s", d.Id()) + _, err := conn.PutBackupPolicy(&efs.PutBackupPolicyInput{ + FileSystemId: aws.String(d.Id()), + BackupPolicy: &efs.BackupPolicy{ + Status: aws.String(efs.StatusDisabled), + }, + }) + + if err != nil { + return fmt.Errorf("error deleting EFS File System Backup Policy: %s with err %s", d.Id(), err.Error()) + } + + if _, err := waiter.FileSystemBackupPolicyDeleted(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for EFS File System Backup Policy (%q) deletion : %s", d.Id(), err) + } + + log.Printf("[DEBUG] EFS File System Backup Policy %q deleted.", d.Id()) + + return nil +} + +func expandEfsFileSystemBackupPolicy(tfList []interface{}) *efs.BackupPolicy { + return &efs.BackupPolicy{ + Status: aws.String(tfList[0].(map[string]interface{})["status"].(string)), + } +} + +func flattenEfsFileSystemBackupPolicy(apiObjects *efs.BackupPolicy) []interface{} { + return []interface{}{map[string]interface{}{"status": apiObjects.Status}} +} From aa3a359790780293494ef76e22da06e5b9cc0133 Mon Sep 17 00:00:00 2001 From: shuheiktgw Date: Thu, 11 Mar 2021 07:50:40 +0900 Subject: [PATCH 0679/1208] Add tests for efs_file_system_backup_policy resource --- ..._aws_efs_file_system_backup_policy_test.go | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 aws/resource_aws_efs_file_system_backup_policy_test.go diff --git a/aws/resource_aws_efs_file_system_backup_policy_test.go b/aws/resource_aws_efs_file_system_backup_policy_test.go new file mode 100644 index 000000000000..6ad5ed7b5bab --- /dev/null +++ b/aws/resource_aws_efs_file_system_backup_policy_test.go @@ -0,0 +1,131 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/efs" + "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 TestAccAWSEFSFileSystemBackupPolicy_basic(t *testing.T) { + var out efs.DescribeBackupPolicyOutput + resourceName := "aws_efs_file_system_backup_policy.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &out), + resource.TestCheckResourceAttr(resourceName, "backup_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "backup_policy.0.status", "ENABLED"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSEFSFileSystemBackupPolicy_disappears(t *testing.T) { + var out efs.DescribeBackupPolicyOutput + resourceName := "aws_efs_file_system_backup_policy.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &out), + testAccCheckResourceDisappears(testAccProvider, resourceAwsEfsFileSystemBackupPolicy(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckEFSFileSystemBackupPolicyExists(name string, bp *efs.DescribeBackupPolicyOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("not found: %s", name) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("no ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).efsconn + fs, err := conn.DescribeBackupPolicy(&efs.DescribeBackupPolicyInput{ + FileSystemId: aws.String(rs.Primary.ID), + }) + + if err != nil { + return err + } + + *bp = *fs + + return nil + } +} + +func testAccCheckEfsFileSystemBackupPolicyDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).efsconn + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_efs_file_system_backup_policy" { + continue + } + + resp, err := conn.DescribeBackupPolicy(&efs.DescribeBackupPolicyInput{ + FileSystemId: aws.String(rs.Primary.ID), + }) + if err != nil { + if isAWSErr(err, efs.ErrCodeFileSystemNotFound, "") || + isAWSErr(err, efs.ErrCodePolicyNotFound, "") { + return nil + } + return fmt.Errorf("error describing EFS file system backup policy in tests: %s", err) + } + + if resp == nil || resp.BackupPolicy == nil || aws.StringValue(resp.BackupPolicy.Status) == efs.StatusDisabled { + return nil + } + + return fmt.Errorf("EFS file system backup policy %q still exists", rs.Primary.ID) + } + + return nil +} + +func testAccAWSEFSFileSystemBackupPolicyConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_efs_file_system" "test" { + creation_token = %q +} + +resource "aws_efs_file_system_backup_policy" "test" { + file_system_id = aws_efs_file_system.test.id + + backup_policy { + status = "ENABLED" + } +} +`, rName) +} From d577344e500558df078aac6d15f20741ce9f93ca Mon Sep 17 00:00:00 2001 From: shuheiktgw Date: Thu, 11 Mar 2021 07:57:53 +0900 Subject: [PATCH 0680/1208] Add document for efs_file_system_backup_policy resource --- ...fs_file_system_backup_policy.html.markdown | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 website/docs/r/efs_file_system_backup_policy.html.markdown diff --git a/website/docs/r/efs_file_system_backup_policy.html.markdown b/website/docs/r/efs_file_system_backup_policy.html.markdown new file mode 100644 index 000000000000..1925b2eb6f71 --- /dev/null +++ b/website/docs/r/efs_file_system_backup_policy.html.markdown @@ -0,0 +1,53 @@ +--- +subcategory: "EFS" +layout: "aws" +page_title: "AWS: aws_efs_file_system_backup_policy" +description: |- + Provides an Elastic File System (EFS) File System Backup Policy resource. +--- + +# Resource: aws_efs_file_system_backup_policy + +Provides an Elastic File System (EFS) File System Backup Policy resource. + +## Example Usage + +```hcl +resource "aws_efs_file_system" "fs" { + creation_token = "my-product" +} + +resource "aws_efs_file_system_backup_policy" "policy" { + file_system_id = aws_efs_file_system.fs.id + + backup_policy { + status = "ENABLED" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `file_system_id` - (Required) The ID of the EFS file system. +* `backup_policy` - (Required) A file system backup_policy object (documented below). + +### Backup Policy Arguments +For **backup_policy** the following attributes are supported: + +* `status` - (Required) A status of the backup policy. Valid values: `Enabled`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID that identifies the file system (e.g. fs-ccfc0d65). + +## Import + +The EFS file system backup policies can be imported using the `id`, e.g. + +``` +$ terraform import aws_efs_file_system_backup_policy.foo fs-6fa144c6 +``` From 2f1727597f4790ec812ab716db7d222b44eb9d28 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 22 Jun 2021 12:26:25 -0400 Subject: [PATCH 0681/1208] tfresource: Document RetryConfigContext --- aws/internal/tfresource/retry.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/internal/tfresource/retry.go b/aws/internal/tfresource/retry.go index 2e30512c4321..56b891a42580 100644 --- a/aws/internal/tfresource/retry.go +++ b/aws/internal/tfresource/retry.go @@ -43,6 +43,10 @@ func RetryWhenAwsErrCodeEquals(timeout time.Duration, f func() (interface{}, err return output, nil } +// RetryConfigContext allows configuration of StateChangeConf's various time arguments. +// This is especially useful for AWS services that are prone to throttling, such as Route53, where +// the default durations cause problems. To not use a StateChangeConf argument and revert to the +// default, pass in a zero value (i.e., 0*time.Second). func RetryConfigContext(ctx context.Context, delay time.Duration, delayRand time.Duration, minTimeout time.Duration, pollInterval time.Duration, timeout time.Duration, f resource.RetryFunc) error { // These are used to pull the error out of the function; need a mutex to // avoid a data race. From fb03e541e7df5d97a5c08397951f79788158bd63 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 14:15:36 -0400 Subject: [PATCH 0682/1208] provider: Add new data source --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index d0d6e9b9846d..f8022ea50aea 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -392,6 +392,7 @@ func Provider() *schema.Provider { "aws_secretsmanager_secret_version": dataSourceAwsSecretsManagerSecretVersion(), "aws_servicecatalog_constraint": dataSourceAwsServiceCatalogConstraint(), "aws_servicecatalog_portfolio": dataSourceAwsServiceCatalogPortfolio(), + "aws_servicecatalog_product": dataSourceAwsServiceCatalogProduct(), "aws_servicequotas_service": dataSourceAwsServiceQuotasService(), "aws_servicequotas_service_quota": dataSourceAwsServiceQuotasServiceQuota(), "aws_service_discovery_dns_namespace": dataSourceServiceDiscoveryDnsNamespace(), From 66e3e209710bf19e3d2e73750ef8a5badee7ebc2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 14:16:04 -0400 Subject: [PATCH 0683/1208] ds/servicecat_product: New data source --- aws/data_source_aws_servicecatalog_product.go | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 aws/data_source_aws_servicecatalog_product.go diff --git a/aws/data_source_aws_servicecatalog_product.go b/aws/data_source_aws_servicecatalog_product.go new file mode 100644 index 000000000000..f54a52a60849 --- /dev/null +++ b/aws/data_source_aws_servicecatalog_product.go @@ -0,0 +1,122 @@ +package aws + +import ( + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "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" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" +) + +func dataSourceAwsServiceCatalogProduct() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsServiceCatalogProductRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "accept_language": { + Type: schema.TypeString, + Optional: true, + Default: "en", + ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "distributor": { + Type: schema.TypeString, + Computed: true, + }, + "has_default_path": { + Type: schema.TypeBool, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "owner": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "support_description": { + Type: schema.TypeString, + Computed: true, + }, + "support_email": { + Type: schema.TypeString, + Computed: true, + }, + "support_url": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchemaComputed(), + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceAwsServiceCatalogProductRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + output, err := waiter.ProductReady(conn, d.Get("accept_language").(string), d.Get("id").(string)) + + if err != nil { + return fmt.Errorf("error describing Service Catalog Product: %w", err) + } + + if output == nil || output.ProductViewDetail == nil || output.ProductViewDetail.ProductViewSummary == nil { + return fmt.Errorf("error getting Service Catalog Product: empty response") + } + + pvs := output.ProductViewDetail.ProductViewSummary + + d.Set("arn", output.ProductViewDetail.ProductARN) + if output.ProductViewDetail.CreatedTime != nil { + d.Set("created_time", output.ProductViewDetail.CreatedTime.Format(time.RFC3339)) + } + d.Set("description", pvs.ShortDescription) + d.Set("distributor", pvs.Distributor) + d.Set("has_default_path", pvs.HasDefaultPath) + d.Set("name", pvs.Name) + d.Set("owner", pvs.Owner) + d.Set("status", output.ProductViewDetail.Status) + d.Set("support_description", pvs.SupportDescription) + d.Set("support_email", pvs.SupportEmail) + d.Set("support_url", pvs.SupportUrl) + d.Set("type", pvs.Type) + + d.SetId(aws.StringValue(pvs.ProductId)) + + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + if err := d.Set("tags", keyvaluetags.ServicecatalogKeyValueTags(output.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + + return nil +} From 19cfe9c11294f11fa46f241f5adef282428e6bd3 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 14:16:33 -0400 Subject: [PATCH 0684/1208] tests/ds/servicecat_product: New data source --- ..._source_aws_servicecatalog_product_test.go | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 aws/data_source_aws_servicecatalog_product_test.go diff --git a/aws/data_source_aws_servicecatalog_product_test.go b/aws/data_source_aws_servicecatalog_product_test.go new file mode 100644 index 000000000000..0d83b480da3e --- /dev/null +++ b/aws/data_source_aws_servicecatalog_product_test.go @@ -0,0 +1,93 @@ +package aws + +import ( + "testing" + + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSServiceCatalogProductDataSource_basic(t *testing.T) { + resourceName := "aws_servicecatalog_product.test" + dataSourceName := "data.aws_servicecatalog_product.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProductDataSourceConfig_basic(rName, "beskrivning", "supportbeskrivning"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_time", dataSourceName, "created_time"), + resource.TestCheckResourceAttrPair(resourceName, "description", dataSourceName, "description"), + resource.TestCheckResourceAttrPair(resourceName, "distributor", dataSourceName, "distributor"), + resource.TestCheckResourceAttrPair(resourceName, "has_default_path", dataSourceName, "has_default_path"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "owner", dataSourceName, "owner"), + resource.TestCheckResourceAttrPair(resourceName, "status", dataSourceName, "status"), + resource.TestCheckResourceAttrPair(resourceName, "support_description", dataSourceName, "support_description"), + resource.TestCheckResourceAttrPair(resourceName, "support_email", dataSourceName, "support_email"), + resource.TestCheckResourceAttrPair(resourceName, "support_url", dataSourceName, "support_url"), + resource.TestCheckResourceAttrPair(resourceName, "type", dataSourceName, "type"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), + resource.TestCheckResourceAttrPair(resourceName, "tags.Name", dataSourceName, "tags.Name"), + ), + }, + }, + }) +} + +func TestAccAWSServiceCatalogProductDataSource_physicalID(t *testing.T) { + resourceName := "aws_servicecatalog_product.test" + dataSourceName := "data.aws_servicecatalog_product.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProductDataSourceConfig_physicalID(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_time", dataSourceName, "created_time"), + resource.TestCheckResourceAttrPair(resourceName, "description", dataSourceName, "description"), + resource.TestCheckResourceAttrPair(resourceName, "distributor", dataSourceName, "distributor"), + resource.TestCheckResourceAttrPair(resourceName, "has_default_path", dataSourceName, "has_default_path"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "owner", dataSourceName, "owner"), + resource.TestCheckResourceAttrPair(resourceName, "status", dataSourceName, "status"), + resource.TestCheckResourceAttrPair(resourceName, "support_description", dataSourceName, "support_description"), + resource.TestCheckResourceAttrPair(resourceName, "support_email", dataSourceName, "support_email"), + resource.TestCheckResourceAttrPair(resourceName, "support_url", dataSourceName, "support_url"), + resource.TestCheckResourceAttrPair(resourceName, "type", dataSourceName, "type"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), + resource.TestCheckResourceAttrPair(resourceName, "tags.Name", dataSourceName, "tags.Name"), + ), + }, + }, + }) +} + +func testAccAWSServiceCatalogProductDataSourceConfig_basic(rName, description, supportDescription string) string { + return composeConfig(testAccAWSServiceCatalogProductConfig_basic(rName, description, supportDescription), ` +data "aws_servicecatalog_product" "test" { + id = aws_servicecatalog_product.test.id +} +`) +} + +func testAccAWSServiceCatalogProductDataSourceConfig_physicalID(rName string) string { + return composeConfig(testAccAWSServiceCatalogProductConfig_physicalID(rName), ` +data "aws_servicecatalog_product" "test" { + id = aws_servicecatalog_product.test.id +} +`) +} From c43f688b98a7070fdb38d02a64fa46198cc0cc91 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 14:16:45 -0400 Subject: [PATCH 0685/1208] docs/ds/servicecat_product: New data source --- .../d/servicecatalog_product.html.markdown | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 website/docs/d/servicecatalog_product.html.markdown diff --git a/website/docs/d/servicecatalog_product.html.markdown b/website/docs/d/servicecatalog_product.html.markdown new file mode 100644 index 000000000000..dfde282c810b --- /dev/null +++ b/website/docs/d/servicecatalog_product.html.markdown @@ -0,0 +1,51 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_product" +description: |- + Provides information on a Service Catalog Product +--- + +# Data source: aws_servicecatalog_product + +Provides information on a Service Catalog Product. + +-> **Tip:** A "provisioning artifact" is also referred to as a "version." A "distributor" is also referred to as a "vendor." + +## Example Usage + +### Basic Usage + +```terraform +data "aws_servicecatalog_product" "example" { + id = "prod-dnigbtea24ste" +} +``` + +## Argument Reference + +The following arguments are required: + +* `id` - (Required) Product ID. + +The following arguments are optional: + +* `accept_language` - (Optional) Language code. Valid values: `en` (English), `jp` (Japanese), `zh` (Chinese). Default value is `en`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - ARN of the product. +* `created_time` - Time when the product was created. +* `description` - Description of the product. +* `distributor` - Distributor (i.e., vendor) of the product. +* `has_default_path` - Whether the product has a default path. +* `name` - Name of the product. +* `owner` - Owner of the product. +* `status` - Status of the product. +* `support_description` - Support information about the product. +* `support_email` - Contact email for product support. +* `support_url` - Contact URL for product support. +* `tags` - Tags to apply to the product. +* `type` - Type of product. From da7b4afd07465449aa12a23e640bc2d33448f6cf Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 24 May 2021 14:18:07 -0400 Subject: [PATCH 0686/1208] ds/servicecat_product: Add changelog --- .changelog/19503.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19503.txt diff --git a/.changelog/19503.txt b/.changelog/19503.txt new file mode 100644 index 000000000000..88b7b14cb403 --- /dev/null +++ b/.changelog/19503.txt @@ -0,0 +1,3 @@ +```release-notes:new-data-source + aws_servicecatalog_product + ``` \ No newline at end of file From 36cf3d752370ad747256f8ce3735312936033397 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Tue, 22 Jun 2021 10:04:23 -0700 Subject: [PATCH 0687/1208] Add docs and adjust behavior --- aws/elasticsearch_domain_structure.go | 18 ++-- ...e_aws_elasticsearch_domain_saml_options.go | 41 +++++--- ..._elasticsearch_domain_saml_options_test.go | 93 +++++++++++++++++++ aws/resource_aws_elasticsearch_domain_test.go | 2 +- ...icsearch_domain_saml_options.html.markdown | 76 +++++++++++++++ 5 files changed, 206 insertions(+), 24 deletions(-) create mode 100644 website/docs/r/elasticsearch_domain_saml_options.html.markdown diff --git a/aws/elasticsearch_domain_structure.go b/aws/elasticsearch_domain_structure.go index 28b2c570c798..e6114eceb350 100644 --- a/aws/elasticsearch_domain_structure.go +++ b/aws/elasticsearch_domain_structure.go @@ -45,10 +45,14 @@ func expandAdvancedSecurityOptions(m []interface{}) *elasticsearch.AdvancedSecur } func expandESSAMLOptions(data []interface{}) *elasticsearch.SAMLOptionsInput { - if len(data) == 0 || data[0] == nil { + if len(data) == 0 { return nil } + if data[0] == nil { + return &elasticsearch.SAMLOptionsInput{} + } + options := elasticsearch.SAMLOptionsInput{} group := data[0].(map[string]interface{}) @@ -119,15 +123,9 @@ func flattenESSAMLOptions(d *schema.ResourceData, samlOptions *elasticsearch.SAM "idp": flattenESSAMLIdpOptions(samlOptions.Idp), } - if samlOptions.RolesKey != nil { - m["roles_key"] = aws.StringValue(samlOptions.RolesKey) - } - if samlOptions.SessionTimeoutMinutes != nil { - m["session_timeout_minutes"] = aws.Int64Value(samlOptions.SessionTimeoutMinutes) - } - if samlOptions.SubjectKey != nil { - m["subject_key"] = aws.StringValue(samlOptions.SubjectKey) - } + m["roles_key"] = aws.StringValue(samlOptions.RolesKey) + m["session_timeout_minutes"] = aws.Int64Value(samlOptions.SessionTimeoutMinutes) + m["subject_key"] = aws.StringValue(samlOptions.SubjectKey) // samlOptions.master_backend_role and samlOptions.master_user_name will be added to the // all_access role in kibana's security manager. These values cannot be read or diff --git a/aws/resource_aws_elasticsearch_domain_saml_options.go b/aws/resource_aws_elasticsearch_domain_saml_options.go index b9601a9b2c0a..26179b74999f 100644 --- a/aws/resource_aws_elasticsearch_domain_saml_options.go +++ b/aws/resource_aws_elasticsearch_domain_saml_options.go @@ -19,6 +19,12 @@ func resourceAwsElasticSearchDomainSAMLOptions() *schema.Resource { Read: resourceAwsElasticSearchDomainSAMLOptionsRead, Update: resourceAwsElasticSearchDomainSAMLOptionsPut, Delete: resourceAwsElasticSearchDomainSAMLOptionsDelete, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + d.Set("domain_name", d.Id()) + return []*schema.ResourceData{d}, nil + }, + }, Schema: map[string]*schema.Schema{ "domain_name": { @@ -71,14 +77,17 @@ func resourceAwsElasticSearchDomainSAMLOptions() *schema.Resource { Optional: true, }, "session_timeout_minutes": { - Type: schema.TypeInt, - Optional: true, - Default: 60, - ValidateFunc: validation.IntBetween(1, 1440), + Type: schema.TypeInt, + Optional: true, + Default: 60, + ValidateFunc: validation.IntBetween(1, 1440), + DiffSuppressFunc: elasticsearchDomainSamlOptionsDiffSupress, }, "subject_key": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + Default: "NameID", + DiffSuppressFunc: elasticsearchDomainSamlOptionsDiffSupress, }, }, }, @@ -86,6 +95,14 @@ func resourceAwsElasticSearchDomainSAMLOptions() *schema.Resource { }, } } +func elasticsearchDomainSamlOptionsDiffSupress(k, old, new string, d *schema.ResourceData) bool { + if v, ok := d.Get("saml_options").([]interface{}); ok && len(v) > 0 { + if enabled, ok := v[0].(map[string]interface{})["enabled"].(bool); ok && !enabled { + return true + } + } + return false +} func resourceAwsElasticSearchDomainSAMLOptionsRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).esconn @@ -97,12 +114,10 @@ func resourceAwsElasticSearchDomainSAMLOptionsRead(d *schema.ResourceData, meta domain, err := conn.DescribeElasticsearchDomain(input) if err != nil { - if !d.IsNewResource() { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" { - log.Printf("[WARN] ElasticSearch Domain %q not found, removing from state", d.Id()) - d.SetId("") - return nil - } + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" { + log.Printf("[WARN] ElasticSearch Domain %q not found, removing from state", d.Id()) + d.SetId("") + return nil } return err } @@ -137,7 +152,7 @@ func resourceAwsElasticSearchDomainSAMLOptionsPut(d *schema.ResourceData, meta i return err } - d.SetId("esd-saml-options-" + domainName) + d.SetId(domainName) input := &elasticsearch.DescribeElasticsearchDomainInput{ DomainName: aws.String(d.Get("domain_name").(string)), diff --git a/aws/resource_aws_elasticsearch_domain_saml_options_test.go b/aws/resource_aws_elasticsearch_domain_saml_options_test.go index 9469c3a7a932..abb9ff90ddb4 100644 --- a/aws/resource_aws_elasticsearch_domain_saml_options_test.go +++ b/aws/resource_aws_elasticsearch_domain_saml_options_test.go @@ -32,8 +32,16 @@ func TestAccAWSElasticSearchDomainSAMLOptions_basic(t *testing.T) { testAccCheckESDomainExists(esDomainResourceName, &domain), testAccCheckESDomainSAMLOptions(esDomainResourceName, resourceName), resource.TestCheckResourceAttr(resourceName, "saml_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "saml_options.0.enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "saml_options.0.idp.#", "1"), + resource.TestCheckResourceAttr(resourceName, "saml_options.0.idp.0.entity_id", "https://terraform-dev-ed.my.salesforce.com"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -117,6 +125,38 @@ func TestAccAWSElasticSearchDomainSAMLOptions_Update(t *testing.T) { }) } +func TestAccAWSElasticSearchDomainSAMLOptions_Disabled(t *testing.T) { + rName := acctest.RandomWithPrefix("acc-test") + rUserName := acctest.RandomWithPrefix("es-master-user") + resourceName := "aws_elasticsearch_domain_saml_options.main" + esDomainResourceName := "aws_elasticsearch_domain.example" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, elasticsearch.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckESDomainSAMLOptionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccESDomainSAMLOptionsConfig(rUserName, rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "saml_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "saml_options.0.session_timeout_minutes", "60"), + testAccCheckESDomainSAMLOptions(esDomainResourceName, resourceName), + ), + }, + { + Config: testAccESDomainSAMLOptionsConfigDisabled(rUserName, rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "saml_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "saml_options.0.session_timeout_minutes", "0"), + testAccCheckESDomainSAMLOptions(esDomainResourceName, resourceName), + ), + }, + }, + }) +} + func testAccCheckESDomainSAMLOptionsDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).esconn @@ -285,3 +325,56 @@ resource "aws_elasticsearch_domain_saml_options" "main" { } `, userName, domainName) } + +func testAccESDomainSAMLOptionsConfigDisabled(userName string, domainName string) string { + return fmt.Sprintf(` +resource "aws_iam_user" "es_master_user" { + name = "%s" +} + +resource "aws_elasticsearch_domain" "example" { + domain_name = "%s" + elasticsearch_version = "7.10" + + cluster_config { + instance_type = "r5.large.elasticsearch" + } + + # Advanced security option must be enabled to configure SAML. + advanced_security_options { + enabled = true + internal_user_database_enabled = false + master_user_options { + master_user_arn = aws_iam_user.es_master_user.arn + } + } + + # You must enable node-to-node encryption to use advanced security options. + encrypt_at_rest { + enabled = true + } + + domain_endpoint_options { + enforce_https = true + tls_security_policy = "Policy-Min-TLS-1-2-2019-07" + } + + node_to_node_encryption { + enabled = true + } + + ebs_options { + ebs_enabled = true + volume_size = 10 + } +} + +resource "aws_elasticsearch_domain_saml_options" "main" { + domain_name = aws_elasticsearch_domain.example.domain_name + + saml_options { + enabled = false + } +} +`, userName, domainName) +} diff --git a/aws/resource_aws_elasticsearch_domain_test.go b/aws/resource_aws_elasticsearch_domain_test.go index edb3fbf75d8b..f2baad9c4a94 100644 --- a/aws/resource_aws_elasticsearch_domain_test.go +++ b/aws/resource_aws_elasticsearch_domain_test.go @@ -11,7 +11,7 @@ import ( "github.com/aws/aws-sdk-go/aws/awserr" elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice" "github.com/aws/aws-sdk-go/service/iam" - multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-multierror" "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" diff --git a/website/docs/r/elasticsearch_domain_saml_options.html.markdown b/website/docs/r/elasticsearch_domain_saml_options.html.markdown new file mode 100644 index 000000000000..321dae3e0e55 --- /dev/null +++ b/website/docs/r/elasticsearch_domain_saml_options.html.markdown @@ -0,0 +1,76 @@ +--- +subcategory: "ElasticSearch" +layout: "aws" +page_title: "AWS: aws_elasticsearch_domain_saml_options" +description: |- + Terraform resource for managing SAML authentication options for an AWS Elasticsearch Domain. +--- + +# Resource: aws_elasticsearch_domain_saml_options + +Manages SAML authentication options for an AWS Elasticsearch Domain. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_elasticsearch_domain" "example" { + domain_name = "example" + elasticsearch_version = "1.5" + + cluster_config { + instance_type = "r4.large.elasticsearch" + } + + snapshot_options { + automated_snapshot_start_hour = 23 + } + + tags = { + Domain = "TestDomain" + } +} + +saml_options { + enabled = true + idp { + entity_id = "https://example.com" + metadata_content = file("./saml-metadata.xml") + } +} +``` + +## Argument Reference + +The following arguments are required: + +* `domain_name` - (Required) Name of the domain. + +The following arguments are optional: + +* `saml_options` - (Optional) The SAML authentication options for an AWS Elasticsearch Domain. + +### saml_options + +* `enabled` - (Required) Whether SAML authentication is enabled. +* `idp` - (Optional) Information from your identity provider. +* `master_backend_role` - (Optional) This backend role from the SAML IdP receives full permissions to the cluster, equivalent to a new master user. +* `master_user_name` - (Options) This username from the SAML IdP receives full permissions to the cluster, equivalent to a new master user. +* `roles_key` - (Optional) Element of the SAML assertion to use for backend roles. Default is roles. +* `session_timeout_minutes` - (Optional) Duration of a session in minutes after a user logs in. Default is 60. Maximum value is 1,440. +* `subject_key` - (Optional) Element of the SAML assertion to use for username. Default is NameID. + + +#### idp + +* `entity_id` - (Required) The unique Entity ID of the application in SAML Identity Provider. +* `metadata_content` - (Required) The Metadata of the SAML application in xml format. + +## Import + +Elasticsearch domains can be imported using the `domain_name`, e.g. + +``` +$ terraform import aws_elasticsearch_domain.example domain_name +``` From 21ce53dd7f372e0201778e727164b6010986c000 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 22 Jun 2021 17:09:18 +0000 Subject: [PATCH 0688/1208] Update CHANGELOG.md for #19503 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e135a58b215..eee3341fc893 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,24 @@ ## 3.47.0 (Unreleased) +FEATURES: + +* **New Resource:** `aws_neptune_cluster_endpoint` ([#19898](https://github.com/hashicorp/terraform-provider-aws/issues/19898)) + ENHANCEMENTS: * resource/aws_default_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_default_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_main_route_table_association: Wait for association to reach the required state ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) +* resource/aws_neptune_cluster: Add `copy_snapshot_to_tags` argument ([#19899](https://github.com/hashicorp/terraform-provider-aws/issues/19899)) * resource/aws_route: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_route_table_association: Wait for association to reach the required state ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) +BUG FIXES: + +* resource/aws_glue_catalog_database: Set `location_uri` as compute to prevent drift when `target_table` has `location_uri` set. ([#19743](https://github.com/hashicorp/terraform-provider-aws/issues/19743)) +* resource/aws_glue_catalog_table: Fix updating `schema_reference` when columns are present. ([#19742](https://github.com/hashicorp/terraform-provider-aws/issues/19742)) + ## 3.46.0 (June 17, 2021) FEATURES: From 1894ccf2f1ed79cc5b742a1fe00c71143e0fd431 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Tue, 22 Jun 2021 10:13:20 -0700 Subject: [PATCH 0689/1208] Fix doc formatting --- ..._elasticsearch_domain_saml_options_test.go | 2 +- ...icsearch_domain_saml_options.html.markdown | 25 +++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_elasticsearch_domain_saml_options_test.go b/aws/resource_aws_elasticsearch_domain_saml_options_test.go index abb9ff90ddb4..808a6b78c3c6 100644 --- a/aws/resource_aws_elasticsearch_domain_saml_options_test.go +++ b/aws/resource_aws_elasticsearch_domain_saml_options_test.go @@ -373,7 +373,7 @@ resource "aws_elasticsearch_domain_saml_options" "main" { domain_name = aws_elasticsearch_domain.example.domain_name saml_options { - enabled = false + enabled = false } } `, userName, domainName) diff --git a/website/docs/r/elasticsearch_domain_saml_options.html.markdown b/website/docs/r/elasticsearch_domain_saml_options.html.markdown index 321dae3e0e55..003ef48be727 100644 --- a/website/docs/r/elasticsearch_domain_saml_options.html.markdown +++ b/website/docs/r/elasticsearch_domain_saml_options.html.markdown @@ -32,13 +32,16 @@ resource "aws_elasticsearch_domain" "example" { } } -saml_options { - enabled = true - idp { - entity_id = "https://example.com" - metadata_content = file("./saml-metadata.xml") - } -} +resource "aws_elasticsearch_domain_saml_options" "example" { + domain_name = aws_elasticsearch_domain.example.domain_name + saml_options { + enabled = true + idp { + entity_id = "https://example.com" + metadata_content = file("./saml-metadata.xml") + } + } +} ``` ## Argument Reference @@ -67,10 +70,16 @@ The following arguments are optional: * `entity_id` - (Required) The unique Entity ID of the application in SAML Identity Provider. * `metadata_content` - (Required) The Metadata of the SAML application in xml format. +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The name of the domain the SAML options are associated with. + ## Import Elasticsearch domains can be imported using the `domain_name`, e.g. ``` -$ terraform import aws_elasticsearch_domain.example domain_name +$ terraform import aws_elasticsearch_domain_saml_options.example domain_name ``` From 02a016dd7a15a78ca116e6a7c5a750c0bb4ffcf8 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Tue, 22 Jun 2021 11:23:21 -0700 Subject: [PATCH 0690/1208] Add changelog entry --- .changelog/19497.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19497.txt diff --git a/.changelog/19497.txt b/.changelog/19497.txt new file mode 100644 index 000000000000..4ccd259ca056 --- /dev/null +++ b/.changelog/19497.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_elasticsearch_domain_saml_options +``` From 72c603f4324577bc54d58d1fccc40f9a06a1fb28 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 22 Jun 2021 14:27:51 -0400 Subject: [PATCH 0691/1208] Add CHANGELOG entry for #16874. --- .changelog/16874.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/16874.txt diff --git a/.changelog/16874.txt b/.changelog/16874.txt new file mode 100644 index 000000000000..01da77a8c907 --- /dev/null +++ b/.changelog/16874.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_cloudwatch_event_bus_policy +``` \ No newline at end of file From eec82db1d73a3a7b394fdc0b50274352a6c8d91e Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 22 Jun 2021 18:38:05 +0000 Subject: [PATCH 0692/1208] Update CHANGELOG.md for #19925 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eee3341fc893..dfdf42881acc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ FEATURES: +* **New Resource:** `aws_cloudwatch_event_bus_policy` ([#16874](https://github.com/hashicorp/terraform-provider-aws/issues/16874)) +* **New Resource:** `aws_elasticsearch_domain_saml_options` ([#19497](https://github.com/hashicorp/terraform-provider-aws/issues/19497)) * **New Resource:** `aws_neptune_cluster_endpoint` ([#19898](https://github.com/hashicorp/terraform-provider-aws/issues/19898)) ENHANCEMENTS: From 78f24938ed84fb4eb5fc4c07a4f2dea107e95042 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 22 Jun 2021 16:44:42 -0400 Subject: [PATCH 0693/1208] docs/r/lakeformation_permissions: Clarify docs --- .../docs/r/lakeformation_permissions.html.markdown | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index 391916f2cef8..23e0989b9dc2 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -10,7 +10,15 @@ description: |- Grants permissions to the principal to access metadata in the Data Catalog and data organized in underlying data storage such as Amazon S3. Permissions are granted to a principal, in a Data Catalog, relative to a Lake Formation resource, which includes the Data Catalog, databases, and tables. For more information, see [Security and Access Control to Metadata and Data in Lake Formation](https://docs.aws.amazon.com/lake-formation/latest/dg/security-data-access.html). -~> **NOTE:** Lake Formation grants implicit permissions to data lake administrators, database creators, and table creators. These implicit permissions cannot be revoked _per se_. If this resource reads implicit permissions, it will attempt to revoke them, which causes an error when the resource is destroyed. There are two ways to avoid these errors. First, grant explicit permissions (and `permissions_with_grant_option`) to "overwrite" a principal's implicit permissions, which you can then revoke with this resource. Second, avoid using this resource with principals that have implicit permissions. For more information, see [Implicit Lake Formation Permissions](https://docs.aws.amazon.com/lake-formation/latest/dg/implicit-permissions.html). +~> **NOTE:** In general, the `principal` should _not_ be a Lake Formation administrator or the entity (e.g., IAM role) that is running Terraform. Administrator's have implicit permissions. These should be managed by granting or not granting administrator rights using `aws_lakeformation_data_lake_settings` _not_ with this resource. + +## Using Lake Formation Permissions + +Lake Formation grants implicit permissions to data lake administrators, database creators, and table creators. These implicit permissions cannot be revoked _per se_. If this resource reads implicit permissions, it will attempt to revoke them, which causes an error when the resource is destroyed. + +There are two ways to avoid these errors. First, and the way we recommend, is to avoid using this resource with principals that have implicit permissions. A second, error-prone option, is to grant explicit permissions (and `permissions_with_grant_option`) to "overwrite" a principal's implicit permissions, which you can then revoke with this resource. For more information, see [Implicit Lake Formation Permissions](https://docs.aws.amazon.com/lake-formation/latest/dg/implicit-permissions.html). + +If the `principal` is also a data lake administrator, AWS grants implicit permissions that can cause errors using this resource. For example, AWS implicitly grants a `principal`/administrator `permissions` and `permissions_with_grant_option` of `ALL`, `ALTER`, `DELETE`, `DESCRIBE`, `DROP`, `INSERT`, and `SELECT` on a table. If you use this resource to explicitly grant the `principal`/administrator `permissions` but _not_ `permissions_with_grant_option` of `ALL`, `ALTER`, `DELETE`, `DESCRIBE`, `DROP`, `INSERT`, and `SELECT` on the table, this resource will read the implicit `permissions_with_grant_option` and attempt to revoke them when the resource is destroyed. Doing so will cause an `InvalidInputException: No permissions revoked` error because you cannot revoke implicit permissions _per se_. To workaround this problem, explicitly grant the `principal`/administrator `permissions` _and_ `permissions_with_grant_option`, which can then be revoked. Similarly, granting a `principal`/administrator permissions on a table with columns and providing `column_names`, will result in a `InvalidInputException: Permissions modification is invalid` error because you are narrowing the implicit permissions. Instead, set `wildcard` to `true` and remove the `column_names`. ## Example Usage @@ -48,7 +56,7 @@ The following arguments are required: * `permissions` – (Required) List of permissions granted to the principal. Valid values may include `ALL`, `ALTER`, `CREATE_DATABASE`, `CREATE_TABLE`, `DATA_LOCATION_ACCESS`, `DELETE`, `DESCRIBE`, `DROP`, `INSERT`, and `SELECT`. For details on each permission, see [Lake Formation Permissions Reference](https://docs.aws.amazon.com/lake-formation/latest/dg/lf-permissions-reference.html). * `principal` – (Required) Principal to be granted the permissions on the resource. Supported principals include IAM roles, users, groups, SAML groups and users, QuickSight groups, OUs, and organizations as well as AWS account IDs for cross-account permissions. For more information, see [Lake Formation Permissions Reference](https://docs.aws.amazon.com/lake-formation/latest/dg/lf-permissions-reference.html). -~> **NOTE:** If the `principal` is also a data lake administrator, AWS grants implicit permissions that can cause errors using this resource. For example, AWS implicitly grants a `principal`/administrator `permissions` and `permissions_with_grant_option` of `ALL`, `ALTER`, `DELETE`, `DESCRIBE`, `DROP`, `INSERT`, and `SELECT` on a table. If you use this resource to explicitly grant the `principal`/administrator `permissions` but _not_ `permissions_with_grant_option` of `ALL`, `ALTER`, `DELETE`, `DESCRIBE`, `DROP`, `INSERT`, and `SELECT` on the table, this resource will read the implicit `permissions_with_grant_option` and attempt to revoke them when the resource is destroyed. Doing so will cause an `InvalidInputException: No permissions revoked` error because you cannot revoke implicit permissions _per se_. To workaround this problem, explicitly grant the `principal`/administrator `permissions` _and_ `permissions_with_grant_option`, which can then be revoked. Similarly, granting a `principal`/administrator permissions on a table with columns and providing `column_names`, will result in a `InvalidInputException: Permissions modification is invalid` error because you are narrowing the implicit permissions. Instead, set `wildcard` to `true` and remove the `column_names`. +~> **NOTE:** We highly recommend that the `principal` _NOT_ be a Lake Formation administrator (granted using `aws_lakeformation_data_lake_settings`). The entity (e.g., IAM role) running Terraform will most likely need to be a Lake Formation administrator. As such, the entity will have implicit permissions and does not need permissions granted through this resource. One of the following is required: From 73c85478bb5ea7b01e4cc85d8396dfb67aff2702 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 22 Jun 2021 17:03:59 -0400 Subject: [PATCH 0694/1208] r/aws_efs_file_system_backup_policy: Fix awsproviderlint 'XAT001: missing ErrorCheck' errors. --- aws/resource_aws_efs_file_system_backup_policy_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_efs_file_system_backup_policy_test.go b/aws/resource_aws_efs_file_system_backup_policy_test.go index 6ad5ed7b5bab..a266af9ef599 100644 --- a/aws/resource_aws_efs_file_system_backup_policy_test.go +++ b/aws/resource_aws_efs_file_system_backup_policy_test.go @@ -18,6 +18,7 @@ func TestAccAWSEFSFileSystemBackupPolicy_basic(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, efs.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, Steps: []resource.TestStep{ @@ -45,6 +46,7 @@ func TestAccAWSEFSFileSystemBackupPolicy_disappears(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, efs.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, Steps: []resource.TestStep{ @@ -117,7 +119,7 @@ func testAccCheckEfsFileSystemBackupPolicyDestroy(s *terraform.State) error { func testAccAWSEFSFileSystemBackupPolicyConfig(rName string) string { return fmt.Sprintf(` resource "aws_efs_file_system" "test" { - creation_token = %q + creation_token = %[1]q } resource "aws_efs_file_system_backup_policy" "test" { From 301f5f4ec4093845d441d7345f885d2fcf995e0a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 22 Jun 2021 17:04:31 -0400 Subject: [PATCH 0695/1208] Fix tfproviderdocs linting errors. --- website/docs/r/efs_file_system_backup_policy.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/efs_file_system_backup_policy.html.markdown b/website/docs/r/efs_file_system_backup_policy.html.markdown index 1925b2eb6f71..46687892db58 100644 --- a/website/docs/r/efs_file_system_backup_policy.html.markdown +++ b/website/docs/r/efs_file_system_backup_policy.html.markdown @@ -12,7 +12,7 @@ Provides an Elastic File System (EFS) File System Backup Policy resource. ## Example Usage -```hcl +```terraform resource "aws_efs_file_system" "fs" { creation_token = "my-product" } @@ -49,5 +49,5 @@ In addition to all arguments above, the following attributes are exported: The EFS file system backup policies can be imported using the `id`, e.g. ``` -$ terraform import aws_efs_file_system_backup_policy.foo fs-6fa144c6 +$ terraform import aws_efs_file_system_backup_policy.example fs-6fa144c6 ``` From 07d391cb18fdd5c0a4c23c1c3471604585399e30 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 22 Jun 2021 17:58:17 -0400 Subject: [PATCH 0696/1208] r/aws_efs_file_system_backup_policy: Allow status to be updated. --- aws/internal/service/efs/finder/finder.go | 26 ++- aws/internal/service/efs/waiter/status.go | 16 +- aws/internal/service/efs/waiter/waiter.go | 27 ++-- ...ource_aws_efs_file_system_backup_policy.go | 152 +++++++++++------- ..._aws_efs_file_system_backup_policy_test.go | 65 +++++--- ...fs_file_system_backup_policy.html.markdown | 2 +- 6 files changed, 177 insertions(+), 111 deletions(-) diff --git a/aws/internal/service/efs/finder/finder.go b/aws/internal/service/efs/finder/finder.go index efeb33896e57..244884f792da 100644 --- a/aws/internal/service/efs/finder/finder.go +++ b/aws/internal/service/efs/finder/finder.go @@ -3,21 +3,33 @@ package finder import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/efs" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -// FileSystemBackupPolicyById returns the EFS Backup Policy corresponding to the specified Id. -// Returns nil if no policy is found. -func FileSystemBackupPolicyById(conn *efs.EFS, id string) (*efs.BackupPolicy, error) { - output, err := conn.DescribeBackupPolicy(&efs.DescribeBackupPolicyInput{ +func BackupPolicyByID(conn *efs.EFS, id string) (*efs.BackupPolicy, error) { + input := &efs.DescribeBackupPolicyInput{ FileSystemId: aws.String(id), - }) + } + + output, err := conn.DescribeBackupPolicy(input) + + if tfawserr.ErrCodeEquals(err, efs.ErrCodeFileSystemNotFound) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } if err != nil { return nil, err } - if output == nil { - return nil, nil + if output == nil || output.BackupPolicy == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } } return output.BackupPolicy, nil diff --git a/aws/internal/service/efs/waiter/status.go b/aws/internal/service/efs/waiter/status.go index 27a8d2e28aa6..b539a8be0b52 100644 --- a/aws/internal/service/efs/waiter/status.go +++ b/aws/internal/service/efs/waiter/status.go @@ -5,6 +5,7 @@ import ( "github.com/aws/aws-sdk-go/service/efs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/efs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) // AccessPointLifeCycleState fetches the Access Point and its LifecycleState @@ -30,20 +31,19 @@ func AccessPointLifeCycleState(conn *efs.EFS, accessPointId string) resource.Sta } } -// FileSystemBackupPolicyStatus fetches the EFS Backup Policy status -func FileSystemBackupPolicyStatus(conn *efs.EFS, id string) resource.StateRefreshFunc { +func BackupPolicyStatus(conn *efs.EFS, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - bp, err := finder.FileSystemBackupPolicyById(conn, id) + output, err := finder.BackupPolicyByID(conn, id) - if err != nil { - return nil, "", err + if tfresource.NotFound(err) { + return nil, "", nil } - if bp == nil { - return nil, "", nil + if err != nil { + return nil, "", err } - return bp, aws.StringValue(bp.Status), nil + return output, aws.StringValue(output.Status), nil } } diff --git a/aws/internal/service/efs/waiter/waiter.go b/aws/internal/service/efs/waiter/waiter.go index 47fe932d2a8e..2e18ddccc0ca 100644 --- a/aws/internal/service/efs/waiter/waiter.go +++ b/aws/internal/service/efs/waiter/waiter.go @@ -18,9 +18,8 @@ const ( FileSystemDeletedDelayTimeout = 2 * time.Second FileSystemDeletedMinTimeout = 3 * time.Second - // Maximum amount of time to wait for an EFS Backup policy operation - FileSystemBackupPolicyCreatedTimeout = 10 * time.Minute - FileSystemBackupPolicyDeletedTimeout = 10 * time.Minute + BackupPolicyDisabledTimeout = 10 * time.Minute + BackupPolicyEnabledTimeout = 10 * time.Minute ) // AccessPointCreated waits for an Operation to return Success @@ -99,13 +98,12 @@ func FileSystemDeleted(conn *efs.EFS, fileSystemID string) (*efs.FileSystemDescr return nil, err } -// FileSystemBackupPolicyCreated waits for a EFS Backup Policy creation -func FileSystemBackupPolicyCreated(conn *efs.EFS, id string) (*efs.BackupPolicy, error) { +func BackupPolicyDisabled(conn *efs.EFS, id string) (*efs.BackupPolicy, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{efs.StatusEnabling}, - Target: []string{efs.StatusEnabled}, - Refresh: FileSystemBackupPolicyStatus(conn, id), - Timeout: FileSystemBackupPolicyCreatedTimeout, + Pending: []string{efs.StatusDisabling}, + Target: []string{efs.StatusDisabled}, + Refresh: BackupPolicyStatus(conn, id), + Timeout: BackupPolicyDisabledTimeout, } outputRaw, err := stateConf.WaitForState() @@ -117,13 +115,12 @@ func FileSystemBackupPolicyCreated(conn *efs.EFS, id string) (*efs.BackupPolicy, return nil, err } -// FileSystemBackupPolicyDeleted waits for a EFS Backup Policy deletion -func FileSystemBackupPolicyDeleted(conn *efs.EFS, id string) (*efs.BackupPolicy, error) { +func BackupPolicyEnabled(conn *efs.EFS, id string) (*efs.BackupPolicy, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{efs.StatusDisabling}, - Target: []string{efs.StatusDisabled}, - Refresh: FileSystemBackupPolicyStatus(conn, id), - Timeout: FileSystemBackupPolicyDeletedTimeout, + Pending: []string{efs.StatusEnabling}, + Target: []string{efs.StatusEnabled}, + Refresh: BackupPolicyStatus(conn, id), + Timeout: BackupPolicyEnabledTimeout, } outputRaw, err := stateConf.WaitForState() diff --git a/aws/resource_aws_efs_file_system_backup_policy.go b/aws/resource_aws_efs_file_system_backup_policy.go index f0d8bf63dd71..3a568e6e6760 100644 --- a/aws/resource_aws_efs_file_system_backup_policy.go +++ b/aws/resource_aws_efs_file_system_backup_policy.go @@ -6,32 +6,28 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/efs" + "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/service/efs/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/efs/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsEfsFileSystemBackupPolicy() *schema.Resource { return &schema.Resource{ - Create: resourceAwsEfsFileSystemBackupPolicyPut, + Create: resourceAwsEfsFileSystemBackupPolicyCreate, Read: resourceAwsEfsFileSystemBackupPolicyRead, + Update: resourceAwsEfsFileSystemBackupPolicyUpdate, Delete: resourceAwsEfsFileSystemBackupPolicyDelete, - Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ - "file_system_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, "backup_policy": { Type: schema.TypeList, Required: true, - ForceNew: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -39,39 +35,33 @@ func resourceAwsEfsFileSystemBackupPolicy() *schema.Resource { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ + efs.StatusDisabled, efs.StatusEnabled, }, false), }, }, }, }, + + "file_system_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, }, } } -func resourceAwsEfsFileSystemBackupPolicyPut(d *schema.ResourceData, meta interface{}) error { +func resourceAwsEfsFileSystemBackupPolicyCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).efsconn - fsId := d.Get("file_system_id").(string) - input := &efs.PutBackupPolicyInput{ - FileSystemId: aws.String(fsId), - } + fsID := d.Get("file_system_id").(string) - if v, ok := d.GetOk("backup_policy"); ok { - input.BackupPolicy = expandEfsFileSystemBackupPolicy(v.([]interface{})) + if err := efsBackupPolicyPut(conn, fsID, d.Get("backup_policy").([]interface{})[0].(map[string]interface{})); err != nil { + return err } - log.Printf("[DEBUG] Adding EFS File System Backup Policy: %#v", input) - _, err := conn.PutBackupPolicy(input) - if err != nil { - return fmt.Errorf("error creating EFS File System Backup Policy %q: %s", fsId, err.Error()) - } - - d.SetId(fsId) - - if _, err := waiter.FileSystemBackupPolicyCreated(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for EFS File System Backup Policy (%q) creation : %s", d.Id(), err) - } + d.SetId(fsID) return resourceAwsEfsFileSystemBackupPolicyRead(d, meta) } @@ -79,65 +69,107 @@ func resourceAwsEfsFileSystemBackupPolicyPut(d *schema.ResourceData, meta interf func resourceAwsEfsFileSystemBackupPolicyRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).efsconn - bp, err := finder.FileSystemBackupPolicyById(conn, d.Id()) - if err != nil { - if isAWSErr(err, efs.ErrCodeFileSystemNotFound, "") { - log.Printf("[WARN] EFS File System (%q) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - if isAWSErr(err, efs.ErrCodePolicyNotFound, "") { - log.Printf("[WARN] EFS File System Backup Policy (%q) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - return fmt.Errorf("error describing policy for EFS File System Backup Policy (%q): %s", d.Id(), err) - } + output, err := finder.BackupPolicyByID(conn, d.Id()) - if bp == nil || aws.StringValue(bp.Status) == efs.StatusDisabled { - log.Printf("[WARN] EFS File System Backup Policy (%q) is disabled, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] EFS Backup Policy (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - d.Set("file_system_id", d.Id()) - if err := d.Set("backup_policy", flattenEfsFileSystemBackupPolicy(bp)); err != nil { - return fmt.Errorf("error setting backup_policy: %s", err) + if err != nil { + return fmt.Errorf("error reading EFS Backup Policy (%s): %w", d.Id(), err) + } + + if err := d.Set("backup_policy", []interface{}{flattenEfsBackupPolicy(output)}); err != nil { + return fmt.Errorf("error setting backup_policy: %w", err) } + d.Set("file_system_id", d.Id()) + return nil } +func resourceAwsEfsFileSystemBackupPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).efsconn + + if err := efsBackupPolicyPut(conn, d.Id(), d.Get("backup_policy").([]interface{})[0].(map[string]interface{})); err != nil { + return err + } + + return resourceAwsEfsFileSystemBackupPolicyRead(d, meta) +} + func resourceAwsEfsFileSystemBackupPolicyDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).efsconn - log.Printf("[DEBUG] Deleting EFS File System Backup Policy: %s", d.Id()) - _, err := conn.PutBackupPolicy(&efs.PutBackupPolicyInput{ - FileSystemId: aws.String(d.Id()), - BackupPolicy: &efs.BackupPolicy{ - Status: aws.String(efs.StatusDisabled), - }, + err := efsBackupPolicyPut(conn, d.Id(), map[string]interface{}{ + "status": efs.StatusDisabled, }) + if tfawserr.ErrCodeEquals(err, efs.ErrCodeFileSystemNotFound) { + return nil + } + if err != nil { - return fmt.Errorf("error deleting EFS File System Backup Policy: %s with err %s", d.Id(), err.Error()) + return err + } + + return nil +} + +// efsBackupPolicyPut attempts to update the file system's backup policy. +// Any error is returned. +func efsBackupPolicyPut(conn *efs.EFS, fsID string, tfMap map[string]interface{}) error { + input := &efs.PutBackupPolicyInput{ + BackupPolicy: expandEfsBackupPolicy(tfMap), + FileSystemId: aws.String(fsID), } - if _, err := waiter.FileSystemBackupPolicyDeleted(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for EFS File System Backup Policy (%q) deletion : %s", d.Id(), err) + log.Printf("[DEBUG] Putting EFS Backup Policy: %s", input) + _, err := conn.PutBackupPolicy(input) + + if err != nil { + return fmt.Errorf("error putting EFS Backup Policy (%s): %w", fsID, err) } - log.Printf("[DEBUG] EFS File System Backup Policy %q deleted.", d.Id()) + if aws.StringValue(input.BackupPolicy.Status) == efs.StatusEnabled { + if _, err := waiter.BackupPolicyEnabled(conn, fsID); err != nil { + return fmt.Errorf("error waiting for EFS Backup Policy (%s) to enable: %w", fsID, err) + } + } else { + if _, err := waiter.BackupPolicyDisabled(conn, fsID); err != nil { + return fmt.Errorf("error waiting for EFS Backup Policy (%s) to disable: %w", fsID, err) + } + } return nil } -func expandEfsFileSystemBackupPolicy(tfList []interface{}) *efs.BackupPolicy { - return &efs.BackupPolicy{ - Status: aws.String(tfList[0].(map[string]interface{})["status"].(string)), +func expandEfsBackupPolicy(tfMap map[string]interface{}) *efs.BackupPolicy { + if tfMap == nil { + return nil + } + + apiObject := &efs.BackupPolicy{} + + if v, ok := tfMap["status"].(string); ok && v != "" { + apiObject.Status = aws.String(v) } + + return apiObject } -func flattenEfsFileSystemBackupPolicy(apiObjects *efs.BackupPolicy) []interface{} { - return []interface{}{map[string]interface{}{"status": apiObjects.Status}} +func flattenEfsBackupPolicy(apiObject *efs.BackupPolicy) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Status; v != nil { + tfMap["status"] = aws.StringValue(v) + } + + return tfMap } diff --git a/aws/resource_aws_efs_file_system_backup_policy_test.go b/aws/resource_aws_efs_file_system_backup_policy_test.go index a266af9ef599..27b5842d9319 100644 --- a/aws/resource_aws_efs_file_system_backup_policy_test.go +++ b/aws/resource_aws_efs_file_system_backup_policy_test.go @@ -9,10 +9,12 @@ import ( "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/efs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestAccAWSEFSFileSystemBackupPolicy_basic(t *testing.T) { - var out efs.DescribeBackupPolicyOutput + var v efs.BackupPolicy resourceName := "aws_efs_file_system_backup_policy.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -25,7 +27,7 @@ func TestAccAWSEFSFileSystemBackupPolicy_basic(t *testing.T) { { Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &out), + testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "backup_policy.#", "1"), resource.TestCheckResourceAttr(resourceName, "backup_policy.0.status", "ENABLED"), ), @@ -40,7 +42,7 @@ func TestAccAWSEFSFileSystemBackupPolicy_basic(t *testing.T) { } func TestAccAWSEFSFileSystemBackupPolicy_disappears(t *testing.T) { - var out efs.DescribeBackupPolicyOutput + var v efs.BackupPolicy resourceName := "aws_efs_file_system_backup_policy.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -53,7 +55,7 @@ func TestAccAWSEFSFileSystemBackupPolicy_disappears(t *testing.T) { { Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &out), + testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), testAccCheckResourceDisappears(testAccProvider, resourceAwsEfsFileSystemBackupPolicy(), resourceName), ), ExpectNonEmptyPlan: true, @@ -62,7 +64,31 @@ func TestAccAWSEFSFileSystemBackupPolicy_disappears(t *testing.T) { }) } -func testAccCheckEFSFileSystemBackupPolicyExists(name string, bp *efs.DescribeBackupPolicyOutput) resource.TestCheckFunc { +func TestAccAWSEFSFileSystemBackupPolicy_disappears_fs(t *testing.T) { + var v efs.BackupPolicy + resourceName := "aws_efs_file_system_backup_policy.test" + fsResourceName := "aws_efs_file_system.text" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, efs.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsEfsFileSystem(), fsResourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckEFSFileSystemBackupPolicyExists(name string, v *efs.BackupPolicy) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] if !ok { @@ -74,15 +100,14 @@ func testAccCheckEFSFileSystemBackupPolicyExists(name string, bp *efs.DescribeBa } conn := testAccProvider.Meta().(*AWSClient).efsconn - fs, err := conn.DescribeBackupPolicy(&efs.DescribeBackupPolicyInput{ - FileSystemId: aws.String(rs.Primary.ID), - }) + + output, err := finder.BackupPolicyByID(conn, rs.Primary.ID) if err != nil { return err } - *bp = *fs + *v = *output return nil } @@ -90,27 +115,27 @@ func testAccCheckEFSFileSystemBackupPolicyExists(name string, bp *efs.DescribeBa func testAccCheckEfsFileSystemBackupPolicyDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).efsconn + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_efs_file_system_backup_policy" { continue } - resp, err := conn.DescribeBackupPolicy(&efs.DescribeBackupPolicyInput{ - FileSystemId: aws.String(rs.Primary.ID), - }) + output, err := finder.BackupPolicyByID(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + if err != nil { - if isAWSErr(err, efs.ErrCodeFileSystemNotFound, "") || - isAWSErr(err, efs.ErrCodePolicyNotFound, "") { - return nil - } - return fmt.Errorf("error describing EFS file system backup policy in tests: %s", err) + return err } - if resp == nil || resp.BackupPolicy == nil || aws.StringValue(resp.BackupPolicy.Status) == efs.StatusDisabled { - return nil + if aws.StringValue(output.Status) == efs.StatusDisabled { + continue } - return fmt.Errorf("EFS file system backup policy %q still exists", rs.Primary.ID) + return fmt.Errorf("Transfer Server %s still exists", rs.Primary.ID) } return nil diff --git a/website/docs/r/efs_file_system_backup_policy.html.markdown b/website/docs/r/efs_file_system_backup_policy.html.markdown index 46687892db58..c98df2cb734f 100644 --- a/website/docs/r/efs_file_system_backup_policy.html.markdown +++ b/website/docs/r/efs_file_system_backup_policy.html.markdown @@ -36,7 +36,7 @@ The following arguments are supported: ### Backup Policy Arguments For **backup_policy** the following attributes are supported: -* `status` - (Required) A status of the backup policy. Valid values: `Enabled`. +* `status` - (Required) A status of the backup policy. Valid values: `ENABLED`, `DISABLED`. ## Attributes Reference From ee9678728f4d1baafbe70033b61b614c62eb9fdd Mon Sep 17 00:00:00 2001 From: bill-rich Date: Tue, 22 Jun 2021 15:53:31 -0700 Subject: [PATCH 0697/1208] Rearrange and adjust wording. --- .changelog/18102.txt | 3 + aws/data_source_aws_lb_target_group.go | 5 +- aws/resource_aws_lb_target_group.go | 66 ++++++++++---------- aws/resource_aws_lb_target_group_test.go | 15 +++-- website/docs/r/lb_target_group.html.markdown | 8 +-- 5 files changed, 51 insertions(+), 46 deletions(-) create mode 100644 .changelog/18102.txt diff --git a/.changelog/18102.txt b/.changelog/18102.txt new file mode 100644 index 000000000000..69b792573c66 --- /dev/null +++ b/.changelog/18102.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_lb_target_group: Add support for application cookie stickiness +``` diff --git a/aws/data_source_aws_lb_target_group.go b/aws/data_source_aws_lb_target_group.go index fc550abfb63e..ae8a01cd2376 100644 --- a/aws/data_source_aws_lb_target_group.go +++ b/aws/data_source_aws_lb_target_group.go @@ -36,7 +36,10 @@ func dataSourceAwsLbTargetGroup() *schema.Resource { Type: schema.TypeBool, Computed: true, }, - + "healthy_threshold": { + Type: schema.TypeInt, + Computed: true, + }, "interval": { Type: schema.TypeInt, Computed: true, diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index b1aea82874be..435983a24c42 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -212,6 +212,33 @@ func resourceAwsLbTargetGroup() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "app_cookie": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + switch d.Get("protocol").(string) { + case elbv2.ProtocolEnumTcp, elbv2.ProtocolEnumUdp, elbv2.ProtocolEnumTcpUdp, elbv2.ProtocolEnumTls: + return true + } + return false + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cookie_name": { + Type: schema.TypeString, + Required: true, + }, + "duration_seconds": { + Type: schema.TypeInt, + Optional: true, + Default: 86400, + ValidateFunc: validation.IntBetween(0, 604800), + }, + }, + }, + }, "cookie_duration": { Type: schema.TypeInt, Optional: true, @@ -249,33 +276,6 @@ func resourceAwsLbTargetGroup() *schema.Resource { return false }, }, - "app_cookie": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, - DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - switch d.Get("protocol").(string) { - case elbv2.ProtocolEnumTcp, elbv2.ProtocolEnumUdp, elbv2.ProtocolEnumTcpUdp, elbv2.ProtocolEnumTls: - return true - } - return false - }, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cookie_name": { - Type: schema.TypeString, - Required: true, - }, - "duration_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: 86400, - ValidateFunc: validation.IntBetween(0, 604800), - }, - }, - }, - }, }, }, }, @@ -580,13 +580,14 @@ func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) er switch d.Get("protocol").(string) { case elbv2.ProtocolEnumHttp, elbv2.ProtocolEnumHttps: - if stickiness["type"].(string) == "lb_cookie" { + switch stickiness["type"].(string) { + case "lb_cookie": attrs = append(attrs, &elbv2.TargetGroupAttribute{ Key: aws.String("stickiness.lb_cookie.duration_seconds"), Value: aws.String(fmt.Sprintf("%d", stickiness["cookie_duration"].(int))), }) - } else { + case "app_cookie": appCookieBlocks := stickiness["app_cookie"].([]interface{}) if len(appCookieBlocks) == 1 { appStickiness := appCookieBlocks[0].(map[string]interface{}) @@ -600,8 +601,9 @@ func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) er Value: aws.String(appStickiness["cookie_name"].(string)), }) } + default: + log.Printf("[WARN] Unexpected stickiness type. Expected lb_cookie or app_cookie, got %s", stickiness["type"].(string)) } - } } } else if len(stickinessBlocks) == 0 { @@ -860,9 +862,7 @@ func flattenAwsLbTargetGroupStickiness(attributes []*elbv2.TargetGroupAttribute) appStickinessMap["duration_seconds"] = duration } } - if len(appStickinessMap) > 0 { - m["app_cookie"] = []interface{}{appStickinessMap} - } + m["app_cookie"] = []interface{}{appStickinessMap} return []interface{}{m}, nil } diff --git a/aws/resource_aws_lb_target_group_test.go b/aws/resource_aws_lb_target_group_test.go index d73f4dd12ff0..56fa839a5244 100644 --- a/aws/resource_aws_lb_target_group_test.go +++ b/aws/resource_aws_lb_target_group_test.go @@ -994,11 +994,10 @@ func TestAccAWSLBTargetGroup_updateAppSticknessEnabled(t *testing.T) { resourceName := "aws_lb_target_group.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, elbv2.EndpointsID), - IDRefreshName: resourceName, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSLBTargetGroupDestroy, + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, elbv2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBTargetGroupDestroy, Steps: []resource.TestStep{ { Config: testAccAWSLBTargetGroupConfig_appStickiness(targetGroupName, false, false), @@ -2375,7 +2374,7 @@ func testAccAWSLBTargetGroupConfig_appStickiness(targetGroupName string, addAppS if addAppStickinessBlock { appSstickinessBlock = fmt.Sprintf(` stickiness { - enabled = "%t" + enabled = "%[1]t" type = "app_cookie" app_cookie { cookie_name = "Cookie" @@ -2387,14 +2386,14 @@ stickiness { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { - name = "%s" + name = %[1]q port = 443 protocol = "HTTPS" vpc_id = aws_vpc.test.id deregistration_delay = 200 - %s + %[2]s health_check { path = "/health2" diff --git a/website/docs/r/lb_target_group.html.markdown b/website/docs/r/lb_target_group.html.markdown index 14da2d2d9c2c..8b504187a120 100644 --- a/website/docs/r/lb_target_group.html.markdown +++ b/website/docs/r/lb_target_group.html.markdown @@ -96,13 +96,13 @@ The following arguments are supported: * `cookie_duration` - (Optional) Only used when the type is `lb_cookie`. The time period, in seconds, during which requests from a client should be routed to the same target. After this time period expires, the load balancer-generated cookie is considered stale. The range is 1 second to 1 week (604800 seconds). The default value is 1 day (86400 seconds). * `enabled` - (Optional) Boolean to enable / disable `stickiness`. Default is `true`. -* `type` - (Required) The type of sticky sessions. The only current possible values are `lb_cookie` and `app_cookie` for ALBs and `source_ip` for NLBs. +* `type` - (Required) The type of sticky sessions. The only current possible values are `lb_cookie`, `app_cookie` for ALBs, and `source_ip` for NLBs. * `app_cookie` - (Option) An Application Cookie block. Application Cookie blocks are documented below. -Application Cookie Blocks (`app_coookie`) support the following: +#### app_cookie -* `cookie_name` - (Required). Name of the application based cookie. Name of the cookie should not start with the following names: AWSALB, AWSALBAPP, and AWSALBTG. They're reserved for use by the load balancer. -* `duration_seconds` - (Optional). The time period, in seconds, during which requests from a client should be routed to the same target. The range is 1 second to 1 week (604800 seconds). The default value is 1 day (86400 seconds). +* `cookie_name` - (Required) Name of the application based cookie. AWSALB, AWSALBAPP, and AWSALBTG prefixes are reserved and cannot be used. +* `duration_seconds` - (Optional) The time period, in seconds, during which requests from a client should be routed to the same target. The range is 1 to 604800 seconds. The default value is 86400. ## Attributes Reference From 9d6c61d102a755a8c7cea5576400fedb571135ac Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 28 May 2021 12:23:28 -0400 Subject: [PATCH 0698/1208] i/ds/servicecat_launch_paths: Add statuser --- .../service/servicecatalog/waiter/status.go | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/aws/internal/service/servicecatalog/waiter/status.go b/aws/internal/service/servicecatalog/waiter/status.go index 338e821b70b4..32372929bbbb 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -319,3 +319,40 @@ func PrincipalPortfolioAssociationStatus(conn *servicecatalog.ServiceCatalog, ac return output, servicecatalog.StatusAvailable, err } } + +func LaunchPathsStatus(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &servicecatalog.ListLaunchPathsInput{ + AcceptLanguage: aws.String(acceptLanguage), + ProductId: aws.String(productID), + } + + var summaries []*servicecatalog.LaunchPathSummary + + err := conn.ListLaunchPathsPages(input, func(page *servicecatalog.ListLaunchPathsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, summary := range page.LaunchPathSummaries { + if summary == nil { + continue + } + + summaries = append(summaries, summary) + } + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil, StatusNotFound, err + } + + if err != nil { + return nil, servicecatalog.StatusFailed, err + } + + return summaries, servicecatalog.StatusAvailable, err + } +} From 9db9162ee8733d5f04464bfbd5b74baa0c161674 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 28 May 2021 12:23:46 -0400 Subject: [PATCH 0699/1208] i/ds/servicecat_launch_paths: Add waiter --- .../service/servicecatalog/waiter/waiter.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index b388ff87ff66..18162d265f92 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -41,6 +41,8 @@ const ( PrincipalPortfolioAssociationReadyTimeout = 3 * time.Minute PrincipalPortfolioAssociationDeleteTimeout = 3 * time.Minute + LaunchPathsReadyTimeout = 3 * time.Minute + StatusNotFound = "NOT_FOUND" StatusUnavailable = "UNAVAILABLE" @@ -443,3 +445,20 @@ func PrincipalPortfolioAssociationDeleted(conn *servicecatalog.ServiceCatalog, a return err } + +func LaunchPathsReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID string) ([]*servicecatalog.LaunchPathSummary, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusNotFound}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: LaunchPathsStatus(conn, acceptLanguage, productID), + Timeout: LaunchPathsReadyTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.([]*servicecatalog.LaunchPathSummary); ok { + return output, err + } + + return nil, err +} From 07c9eccea098c3aaaeee268435aa7114f8f055f1 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 28 May 2021 12:24:07 -0400 Subject: [PATCH 0700/1208] ds/servicecat_launch_paths: Add new data source --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index e4a20b39bb8a..2beeae83cbbd 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -391,6 +391,7 @@ func Provider() *schema.Provider { "aws_secretsmanager_secret_rotation": dataSourceAwsSecretsManagerSecretRotation(), "aws_secretsmanager_secret_version": dataSourceAwsSecretsManagerSecretVersion(), "aws_servicecatalog_constraint": dataSourceAwsServiceCatalogConstraint(), + "aws_servicecatalog_launch_paths": dataSourceAwsServiceCatalogLaunchPaths(), "aws_servicecatalog_portfolio": dataSourceAwsServiceCatalogPortfolio(), "aws_servicecatalog_product": dataSourceAwsServiceCatalogProduct(), "aws_servicequotas_service": dataSourceAwsServiceQuotasService(), From 3347feb0594f31904080184f264d1a5693d26086 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 28 May 2021 12:24:34 -0400 Subject: [PATCH 0701/1208] ds/servicecat_launch_paths: Add new data source --- ..._source_aws_servicecatalog_launch_paths.go | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 aws/data_source_aws_servicecatalog_launch_paths.go diff --git a/aws/data_source_aws_servicecatalog_launch_paths.go b/aws/data_source_aws_servicecatalog_launch_paths.go new file mode 100644 index 000000000000..c9482923d9c3 --- /dev/null +++ b/aws/data_source_aws_servicecatalog_launch_paths.go @@ -0,0 +1,164 @@ +package aws + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/servicecatalog" + "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" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" +) + +func dataSourceAwsServiceCatalogLaunchPaths() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsServiceCatalogLaunchPathsRead, + + Schema: map[string]*schema.Schema{ + "accept_language": { + Type: schema.TypeString, + Optional: true, + Default: "en", + ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), + }, + "product_id": { + Type: schema.TypeString, + Required: true, + }, + "summaries": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "constraint_summaries": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "path_id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchemaComputed(), + }, + }, + }, + }, + } +} + +func dataSourceAwsServiceCatalogLaunchPathsRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + summaries, err := waiter.LaunchPathsReady(conn, d.Get("accept_language").(string), d.Get("product_id").(string)) + + if err != nil { + return fmt.Errorf("error describing Service Catalog Launch Paths: %w", err) + } + + if err := d.Set("summaries", flattenServiceCatalogLaunchPathSummaries(summaries, ignoreTagsConfig)); err != nil { + return fmt.Errorf("error setting summaries: %w", err) + } + + d.SetId(d.Get("product_id").(string)) + + return nil +} + +func flattenServiceCatalogLaunchPathSummary(apiObject *servicecatalog.LaunchPathSummary, ignoreTagsConfig *keyvaluetags.IgnoreConfig) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if len(apiObject.ConstraintSummaries) > 0 { + tfMap["constraint_summaries"] = flattenServiceCatalogConstraintSummaries(apiObject.ConstraintSummaries) + } + + if apiObject.Id != nil { + tfMap["path_id"] = aws.StringValue(apiObject.Id) + } + + if apiObject.Name != nil { + tfMap["name"] = aws.StringValue(apiObject.Name) + } + + tags := keyvaluetags.ServicecatalogKeyValueTags(apiObject.Tags) + + tfMap["tags"] = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map() + + return tfMap +} + +func flattenServiceCatalogLaunchPathSummaries(apiObjects []*servicecatalog.LaunchPathSummary, ignoreTagsConfig *keyvaluetags.IgnoreConfig) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var tfList []interface{} + + for _, apiObject := range apiObjects { + if apiObject == nil { + continue + } + + tfList = append(tfList, flattenServiceCatalogLaunchPathSummary(apiObject, ignoreTagsConfig)) + } + + return tfList +} + +func flattenServiceCatalogConstraintSummary(apiObject *servicecatalog.ConstraintSummary) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if apiObject.Description != nil { + tfMap["description"] = aws.StringValue(apiObject.Description) + } + + if apiObject.Type != nil { + tfMap["type"] = aws.StringValue(apiObject.Type) + } + + return tfMap +} + +func flattenServiceCatalogConstraintSummaries(apiObjects []*servicecatalog.ConstraintSummary) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var tfList []interface{} + + for _, apiObject := range apiObjects { + if apiObject == nil { + continue + } + + tfList = append(tfList, flattenServiceCatalogConstraintSummary(apiObject)) + } + + return tfList +} From 2879d055ab8c3a6f2e500665bfe395f1e569ae3d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 28 May 2021 12:25:01 -0400 Subject: [PATCH 0702/1208] tests/ds/servicecat_launch_paths: Add new data source --- ...ce_aws_servicecatalog_launch_paths_test.go | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 aws/data_source_aws_servicecatalog_launch_paths_test.go diff --git a/aws/data_source_aws_servicecatalog_launch_paths_test.go b/aws/data_source_aws_servicecatalog_launch_paths_test.go new file mode 100644 index 000000000000..e78d2bf41b0c --- /dev/null +++ b/aws/data_source_aws_servicecatalog_launch_paths_test.go @@ -0,0 +1,44 @@ +package aws + +import ( + "testing" + + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// THIS IS A HARD CODED TEST TO TEST FUNCTIONALITY WHILE WORKING THROUGH BLOCKED CODE + +// !!FIX THIS!! BEFORE MERGING + +func TestAccAWSServiceCatalogLaunchPathsDataSource_basic(t *testing.T) { + dataSourceName := "data.aws_servicecatalog_launch_paths.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogLaunchPathsDataSourceConfig_basic(rName, rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(dataSourceName, "product_id", "prod-nui42zvkjm52a"), + resource.TestCheckResourceAttr(dataSourceName, "summaries.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "summaries.0.path_id", "lpv2-5aftplaxgosvk"), + resource.TestCheckResourceAttr(dataSourceName, "summaries.0.name", "satsuki-11221122"), + ), + }, + }, + }) +} + +func testAccAWSServiceCatalogLaunchPathsDataSourceConfig_basic(rName, description string) string { + return ` +data "aws_servicecatalog_launch_paths" "test" { + product_id = "prod-nui42zvkjm52a" +} +` +} From 40325c11887b2c469fc8525e47c15ba38b06598e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 28 May 2021 12:25:18 -0400 Subject: [PATCH 0703/1208] docs/ds/servicecat_launch_paths: Add new data source --- .../servicecatalog_launch_paths.html.markdown | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 website/docs/d/servicecatalog_launch_paths.html.markdown diff --git a/website/docs/d/servicecatalog_launch_paths.html.markdown b/website/docs/d/servicecatalog_launch_paths.html.markdown new file mode 100644 index 000000000000..bf69c9b30677 --- /dev/null +++ b/website/docs/d/servicecatalog_launch_paths.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_constraint" +description: |- + Provides information on a Service Catalog Constraint +--- + +# Data source: aws_servicecatalog_constraint + +Provides information on a Service Catalog Constraint. + +## Example Usage + +### Basic Usage + +```terraform +data "aws_servicecatalog_constraint" "example" { + accept_language = "en" + id = "cons-hrvy0335" +} +``` + +## Argument Reference + +The following arguments are required: + +* `id` - Constraint identifier. + +The following arguments are optional: + +* `accept_language` - (Optional) Language code. Valid values: `en` (English), `jp` (Japanese), `zh` (Chinese). Default value is `en`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `description` - Description of the constraint. +* `owner` - Owner of the constraint. +* `parameters` - Constraint parameters in JSON format. +* `portfolio_id` - Portfolio identifier. +* `product_id` - Product identifier. +* `status` - Constraint status. +* `type` - Type of constraint. Valid values are `LAUNCH`, `NOTIFICATION`, `RESOURCE_UPDATE`, `STACKSET`, and `TEMPLATE`. From ada45b128e309dba41bf50e1e973d99c9cd393f5 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 28 May 2021 12:27:18 -0400 Subject: [PATCH 0704/1208] ds/servicecatalog_launch_paths: Add changelog --- .changelog/19572.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19572.txt diff --git a/.changelog/19572.txt b/.changelog/19572.txt new file mode 100644 index 000000000000..2c13789f2181 --- /dev/null +++ b/.changelog/19572.txt @@ -0,0 +1,3 @@ +```release-notes:new-data-source +aws_servicecatalog_launch_paths +``` \ No newline at end of file From d36c0f1186b4a46eb11a3bf66badf4eb8b85c78f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 22 Jun 2021 20:18:03 -0400 Subject: [PATCH 0705/1208] docs/d/servicecat_launch_paths: Fix docs --- .../servicecatalog_launch_paths.html.markdown | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/website/docs/d/servicecatalog_launch_paths.html.markdown b/website/docs/d/servicecatalog_launch_paths.html.markdown index bf69c9b30677..16588cb1b0a0 100644 --- a/website/docs/d/servicecatalog_launch_paths.html.markdown +++ b/website/docs/d/servicecatalog_launch_paths.html.markdown @@ -1,23 +1,22 @@ --- subcategory: "Service Catalog" layout: "aws" -page_title: "AWS: aws_servicecatalog_constraint" +page_title: "AWS: aws_servicecatalog_launch_paths" description: |- - Provides information on a Service Catalog Constraint + Provides information on Service Catalog Launch Paths --- -# Data source: aws_servicecatalog_constraint +# Data Source: aws_servicecatalog_launch_paths -Provides information on a Service Catalog Constraint. +Lists the paths to the specified product. A path is how the user has access to a specified product, and is necessary when provisioning a product. A path also determines the constraints put on the product. ## Example Usage ### Basic Usage ```terraform -data "aws_servicecatalog_constraint" "example" { - accept_language = "en" - id = "cons-hrvy0335" +data "aws_servicecatalog_launch_paths" "example" { + product_id = "prod-yakog5pdriver" } ``` @@ -25,7 +24,7 @@ data "aws_servicecatalog_constraint" "example" { The following arguments are required: -* `id` - Constraint identifier. +* `product_id` - Product identifier. The following arguments are optional: @@ -35,10 +34,16 @@ The following arguments are optional: In addition to all arguments above, the following attributes are exported: +* `summaries` - Block with information about the launch path. See details below. + +### summaries + +* `constraint_summaries` - Block for constraints on the portfolio-product relationship. See details below. +* `path_id` - Identifier of the product path. +* `name` - Name of the portfolio to which the path was assigned. +* `tags` - Tags associated with this product path. + +### constraint_summaries + * `description` - Description of the constraint. -* `owner` - Owner of the constraint. -* `parameters` - Constraint parameters in JSON format. -* `portfolio_id` - Portfolio identifier. -* `product_id` - Product identifier. -* `status` - Constraint status. -* `type` - Type of constraint. Valid values are `LAUNCH`, `NOTIFICATION`, `RESOURCE_UPDATE`, `STACKSET`, and `TEMPLATE`. +* `type` - Type of constraint. Valid values are `LAUNCH`, `NOTIFICATION`, `STACKSET`, and `TEMPLATE`. From 42bd098f3491112d78f75616ed4ee55af479e142 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 22 Jun 2021 20:19:04 -0400 Subject: [PATCH 0706/1208] docs/d/servicecat_launch_paths: Fix docs --- website/docs/d/servicecatalog_launch_paths.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/servicecatalog_launch_paths.html.markdown b/website/docs/d/servicecatalog_launch_paths.html.markdown index 16588cb1b0a0..22ebc62d90bb 100644 --- a/website/docs/d/servicecatalog_launch_paths.html.markdown +++ b/website/docs/d/servicecatalog_launch_paths.html.markdown @@ -24,7 +24,7 @@ data "aws_servicecatalog_launch_paths" "example" { The following arguments are required: -* `product_id` - Product identifier. +* `product_id` - (Required) Product identifier. The following arguments are optional: From 6f09221a66324c202cc879ac256157191a75df0a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 10:13:27 -0400 Subject: [PATCH 0707/1208] r/aws_efs_file_system_backup_policy: Additional acceptance tests. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSEFSFileSystemBackupPolicy_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSEFSFileSystemBackupPolicy_ -timeout 180m === RUN TestAccAWSEFSFileSystemBackupPolicy_basic === PAUSE TestAccAWSEFSFileSystemBackupPolicy_basic === RUN TestAccAWSEFSFileSystemBackupPolicy_disappears_fs === PAUSE TestAccAWSEFSFileSystemBackupPolicy_disappears_fs === RUN TestAccAWSEFSFileSystemBackupPolicy_update === PAUSE TestAccAWSEFSFileSystemBackupPolicy_update === CONT TestAccAWSEFSFileSystemBackupPolicy_basic === CONT TestAccAWSEFSFileSystemBackupPolicy_update === CONT TestAccAWSEFSFileSystemBackupPolicy_disappears_fs --- PASS: TestAccAWSEFSFileSystemBackupPolicy_disappears_fs (21.47s) --- PASS: TestAccAWSEFSFileSystemBackupPolicy_basic (27.28s) --- PASS: TestAccAWSEFSFileSystemBackupPolicy_update (48.63s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 53.197s --- ..._aws_efs_file_system_backup_policy_test.go | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_efs_file_system_backup_policy_test.go b/aws/resource_aws_efs_file_system_backup_policy_test.go index 27b5842d9319..4d08f015ac12 100644 --- a/aws/resource_aws_efs_file_system_backup_policy_test.go +++ b/aws/resource_aws_efs_file_system_backup_policy_test.go @@ -25,7 +25,7 @@ func TestAccAWSEFSFileSystemBackupPolicy_basic(t *testing.T) { CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName), + Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName, "ENABLED"), Check: resource.ComposeTestCheckFunc( testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "backup_policy.#", "1"), @@ -41,9 +41,10 @@ func TestAccAWSEFSFileSystemBackupPolicy_basic(t *testing.T) { }) } -func TestAccAWSEFSFileSystemBackupPolicy_disappears(t *testing.T) { +func TestAccAWSEFSFileSystemBackupPolicy_disappears_fs(t *testing.T) { var v efs.BackupPolicy resourceName := "aws_efs_file_system_backup_policy.test" + fsResourceName := "aws_efs_file_system.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -53,10 +54,10 @@ func TestAccAWSEFSFileSystemBackupPolicy_disappears(t *testing.T) { CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName), + Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName, "ENABLED"), Check: resource.ComposeTestCheckFunc( testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), - testAccCheckResourceDisappears(testAccProvider, resourceAwsEfsFileSystemBackupPolicy(), resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsEfsFileSystem(), fsResourceName), ), ExpectNonEmptyPlan: true, }, @@ -64,10 +65,9 @@ func TestAccAWSEFSFileSystemBackupPolicy_disappears(t *testing.T) { }) } -func TestAccAWSEFSFileSystemBackupPolicy_disappears_fs(t *testing.T) { +func TestAccAWSEFSFileSystemBackupPolicy_update(t *testing.T) { var v efs.BackupPolicy resourceName := "aws_efs_file_system_backup_policy.test" - fsResourceName := "aws_efs_file_system.text" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -77,12 +77,33 @@ func TestAccAWSEFSFileSystemBackupPolicy_disappears_fs(t *testing.T) { CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName), + Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName, "DISABLED"), Check: resource.ComposeTestCheckFunc( testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), - testAccCheckResourceDisappears(testAccProvider, resourceAwsEfsFileSystem(), fsResourceName), + resource.TestCheckResourceAttr(resourceName, "backup_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "backup_policy.0.status", "DISABLED"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName, "ENABLED"), + Check: resource.ComposeTestCheckFunc( + testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "backup_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "backup_policy.0.status", "ENABLED"), + ), + }, + { + Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName, "DISABLED"), + Check: resource.ComposeTestCheckFunc( + testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "backup_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "backup_policy.0.status", "DISABLED"), ), - ExpectNonEmptyPlan: true, }, }, }) @@ -141,7 +162,7 @@ func testAccCheckEfsFileSystemBackupPolicyDestroy(s *terraform.State) error { return nil } -func testAccAWSEFSFileSystemBackupPolicyConfig(rName string) string { +func testAccAWSEFSFileSystemBackupPolicyConfig(rName, status string) string { return fmt.Sprintf(` resource "aws_efs_file_system" "test" { creation_token = %[1]q @@ -151,8 +172,8 @@ resource "aws_efs_file_system_backup_policy" "test" { file_system_id = aws_efs_file_system.test.id backup_policy { - status = "ENABLED" + status = %[2]q } } -`, rName) +`, rName, status) } From ee0ef97ed7f99c1dc0b6022c00e989dc949f7a51 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 10:33:24 -0400 Subject: [PATCH 0708/1208] Rename 'aws_efs_file_system_backup_policy' to 'aws_efs_backup_policy'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSEFSBackupPolicy_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSEFSBackupPolicy_ -timeout 180m === RUN TestAccAWSEFSBackupPolicy_basic === PAUSE TestAccAWSEFSBackupPolicy_basic === RUN TestAccAWSEFSBackupPolicy_disappears_fs === PAUSE TestAccAWSEFSBackupPolicy_disappears_fs === RUN TestAccAWSEFSBackupPolicy_update === PAUSE TestAccAWSEFSBackupPolicy_update === CONT TestAccAWSEFSBackupPolicy_basic === CONT TestAccAWSEFSBackupPolicy_update === CONT TestAccAWSEFSBackupPolicy_disappears_fs --- PASS: TestAccAWSEFSBackupPolicy_disappears_fs (22.38s) --- PASS: TestAccAWSEFSBackupPolicy_basic (28.27s) --- PASS: TestAccAWSEFSBackupPolicy_update (50.06s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 53.142s --- aws/provider.go | 2 +- ...y.go => resource_aws_efs_backup_policy.go} | 22 ++++----- ...=> resource_aws_efs_backup_policy_test.go} | 48 +++++++++---------- ...rkdown => efs_backup_policy.html.markdown} | 13 ++--- 4 files changed, 43 insertions(+), 42 deletions(-) rename aws/{resource_aws_efs_file_system_backup_policy.go => resource_aws_efs_backup_policy.go} (83%) rename aws/{resource_aws_efs_file_system_backup_policy_test.go => resource_aws_efs_backup_policy_test.go} (69%) rename website/docs/r/{efs_file_system_backup_policy.html.markdown => efs_backup_policy.html.markdown} (67%) diff --git a/aws/provider.go b/aws/provider.go index 5d6981bcf751..1954a1bc0ebe 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -713,8 +713,8 @@ func Provider() *schema.Provider { "aws_ecs_service": resourceAwsEcsService(), "aws_ecs_task_definition": resourceAwsEcsTaskDefinition(), "aws_efs_access_point": resourceAwsEfsAccessPoint(), + "aws_efs_backup_policy": resourceAwsEfsBackupPolicy(), "aws_efs_file_system": resourceAwsEfsFileSystem(), - "aws_efs_file_system_backup_policy": resourceAwsEfsFileSystemBackupPolicy(), "aws_efs_file_system_policy": resourceAwsEfsFileSystemPolicy(), "aws_efs_mount_target": resourceAwsEfsMountTarget(), "aws_egress_only_internet_gateway": resourceAwsEgressOnlyInternetGateway(), diff --git a/aws/resource_aws_efs_file_system_backup_policy.go b/aws/resource_aws_efs_backup_policy.go similarity index 83% rename from aws/resource_aws_efs_file_system_backup_policy.go rename to aws/resource_aws_efs_backup_policy.go index 3a568e6e6760..854e74cf4cd3 100644 --- a/aws/resource_aws_efs_file_system_backup_policy.go +++ b/aws/resource_aws_efs_backup_policy.go @@ -14,12 +14,12 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -func resourceAwsEfsFileSystemBackupPolicy() *schema.Resource { +func resourceAwsEfsBackupPolicy() *schema.Resource { return &schema.Resource{ - Create: resourceAwsEfsFileSystemBackupPolicyCreate, - Read: resourceAwsEfsFileSystemBackupPolicyRead, - Update: resourceAwsEfsFileSystemBackupPolicyUpdate, - Delete: resourceAwsEfsFileSystemBackupPolicyDelete, + Create: resourceAwsEfsBackupPolicyCreate, + Read: resourceAwsEfsBackupPolicyRead, + Update: resourceAwsEfsBackupPolicyUpdate, + Delete: resourceAwsEfsBackupPolicyDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, @@ -52,7 +52,7 @@ func resourceAwsEfsFileSystemBackupPolicy() *schema.Resource { } } -func resourceAwsEfsFileSystemBackupPolicyCreate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsEfsBackupPolicyCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).efsconn fsID := d.Get("file_system_id").(string) @@ -63,10 +63,10 @@ func resourceAwsEfsFileSystemBackupPolicyCreate(d *schema.ResourceData, meta int d.SetId(fsID) - return resourceAwsEfsFileSystemBackupPolicyRead(d, meta) + return resourceAwsEfsBackupPolicyRead(d, meta) } -func resourceAwsEfsFileSystemBackupPolicyRead(d *schema.ResourceData, meta interface{}) error { +func resourceAwsEfsBackupPolicyRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).efsconn output, err := finder.BackupPolicyByID(conn, d.Id()) @@ -90,17 +90,17 @@ func resourceAwsEfsFileSystemBackupPolicyRead(d *schema.ResourceData, meta inter return nil } -func resourceAwsEfsFileSystemBackupPolicyUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsEfsBackupPolicyUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).efsconn if err := efsBackupPolicyPut(conn, d.Id(), d.Get("backup_policy").([]interface{})[0].(map[string]interface{})); err != nil { return err } - return resourceAwsEfsFileSystemBackupPolicyRead(d, meta) + return resourceAwsEfsBackupPolicyRead(d, meta) } -func resourceAwsEfsFileSystemBackupPolicyDelete(d *schema.ResourceData, meta interface{}) error { +func resourceAwsEfsBackupPolicyDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).efsconn err := efsBackupPolicyPut(conn, d.Id(), map[string]interface{}{ diff --git a/aws/resource_aws_efs_file_system_backup_policy_test.go b/aws/resource_aws_efs_backup_policy_test.go similarity index 69% rename from aws/resource_aws_efs_file_system_backup_policy_test.go rename to aws/resource_aws_efs_backup_policy_test.go index 4d08f015ac12..b45e1dfef24e 100644 --- a/aws/resource_aws_efs_file_system_backup_policy_test.go +++ b/aws/resource_aws_efs_backup_policy_test.go @@ -13,21 +13,21 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -func TestAccAWSEFSFileSystemBackupPolicy_basic(t *testing.T) { +func TestAccAWSEFSBackupPolicy_basic(t *testing.T) { var v efs.BackupPolicy - resourceName := "aws_efs_file_system_backup_policy.test" + resourceName := "aws_efs_backup_policy.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, efs.EndpointsID), Providers: testAccProviders, - CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, + CheckDestroy: testAccCheckEfsBackupPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName, "ENABLED"), + Config: testAccAWSEFSBackupPolicyConfig(rName, "ENABLED"), Check: resource.ComposeTestCheckFunc( - testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), + testAccCheckEFSBackupPolicyExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "backup_policy.#", "1"), resource.TestCheckResourceAttr(resourceName, "backup_policy.0.status", "ENABLED"), ), @@ -41,9 +41,9 @@ func TestAccAWSEFSFileSystemBackupPolicy_basic(t *testing.T) { }) } -func TestAccAWSEFSFileSystemBackupPolicy_disappears_fs(t *testing.T) { +func TestAccAWSEFSBackupPolicy_disappears_fs(t *testing.T) { var v efs.BackupPolicy - resourceName := "aws_efs_file_system_backup_policy.test" + resourceName := "aws_efs_backup_policy.test" fsResourceName := "aws_efs_file_system.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -51,12 +51,12 @@ func TestAccAWSEFSFileSystemBackupPolicy_disappears_fs(t *testing.T) { PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, efs.EndpointsID), Providers: testAccProviders, - CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, + CheckDestroy: testAccCheckEfsBackupPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName, "ENABLED"), + Config: testAccAWSEFSBackupPolicyConfig(rName, "ENABLED"), Check: resource.ComposeTestCheckFunc( - testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), + testAccCheckEFSBackupPolicyExists(resourceName, &v), testAccCheckResourceDisappears(testAccProvider, resourceAwsEfsFileSystem(), fsResourceName), ), ExpectNonEmptyPlan: true, @@ -65,21 +65,21 @@ func TestAccAWSEFSFileSystemBackupPolicy_disappears_fs(t *testing.T) { }) } -func TestAccAWSEFSFileSystemBackupPolicy_update(t *testing.T) { +func TestAccAWSEFSBackupPolicy_update(t *testing.T) { var v efs.BackupPolicy - resourceName := "aws_efs_file_system_backup_policy.test" + resourceName := "aws_efs_backup_policy.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, efs.EndpointsID), Providers: testAccProviders, - CheckDestroy: testAccCheckEfsFileSystemBackupPolicyDestroy, + CheckDestroy: testAccCheckEfsBackupPolicyDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName, "DISABLED"), + Config: testAccAWSEFSBackupPolicyConfig(rName, "DISABLED"), Check: resource.ComposeTestCheckFunc( - testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), + testAccCheckEFSBackupPolicyExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "backup_policy.#", "1"), resource.TestCheckResourceAttr(resourceName, "backup_policy.0.status", "DISABLED"), ), @@ -90,17 +90,17 @@ func TestAccAWSEFSFileSystemBackupPolicy_update(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName, "ENABLED"), + Config: testAccAWSEFSBackupPolicyConfig(rName, "ENABLED"), Check: resource.ComposeTestCheckFunc( - testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), + testAccCheckEFSBackupPolicyExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "backup_policy.#", "1"), resource.TestCheckResourceAttr(resourceName, "backup_policy.0.status", "ENABLED"), ), }, { - Config: testAccAWSEFSFileSystemBackupPolicyConfig(rName, "DISABLED"), + Config: testAccAWSEFSBackupPolicyConfig(rName, "DISABLED"), Check: resource.ComposeTestCheckFunc( - testAccCheckEFSFileSystemBackupPolicyExists(resourceName, &v), + testAccCheckEFSBackupPolicyExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "backup_policy.#", "1"), resource.TestCheckResourceAttr(resourceName, "backup_policy.0.status", "DISABLED"), ), @@ -109,7 +109,7 @@ func TestAccAWSEFSFileSystemBackupPolicy_update(t *testing.T) { }) } -func testAccCheckEFSFileSystemBackupPolicyExists(name string, v *efs.BackupPolicy) resource.TestCheckFunc { +func testAccCheckEFSBackupPolicyExists(name string, v *efs.BackupPolicy) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] if !ok { @@ -134,11 +134,11 @@ func testAccCheckEFSFileSystemBackupPolicyExists(name string, v *efs.BackupPolic } } -func testAccCheckEfsFileSystemBackupPolicyDestroy(s *terraform.State) error { +func testAccCheckEfsBackupPolicyDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).efsconn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_efs_file_system_backup_policy" { + if rs.Type != "aws_efs_backup_policy" { continue } @@ -162,13 +162,13 @@ func testAccCheckEfsFileSystemBackupPolicyDestroy(s *terraform.State) error { return nil } -func testAccAWSEFSFileSystemBackupPolicyConfig(rName, status string) string { +func testAccAWSEFSBackupPolicyConfig(rName, status string) string { return fmt.Sprintf(` resource "aws_efs_file_system" "test" { creation_token = %[1]q } -resource "aws_efs_file_system_backup_policy" "test" { +resource "aws_efs_backup_policy" "test" { file_system_id = aws_efs_file_system.test.id backup_policy { diff --git a/website/docs/r/efs_file_system_backup_policy.html.markdown b/website/docs/r/efs_backup_policy.html.markdown similarity index 67% rename from website/docs/r/efs_file_system_backup_policy.html.markdown rename to website/docs/r/efs_backup_policy.html.markdown index c98df2cb734f..50a0f45387ab 100644 --- a/website/docs/r/efs_file_system_backup_policy.html.markdown +++ b/website/docs/r/efs_backup_policy.html.markdown @@ -1,14 +1,15 @@ --- subcategory: "EFS" layout: "aws" -page_title: "AWS: aws_efs_file_system_backup_policy" +page_title: "AWS: aws_efs_backup_policy" description: |- - Provides an Elastic File System (EFS) File System Backup Policy resource. + Provides an Elastic File System (EFS) Backup Policy resource. --- # Resource: aws_efs_file_system_backup_policy -Provides an Elastic File System (EFS) File System Backup Policy resource. +Provides an Elastic File System (EFS) Backup Policy resource. +Backup policies turn automatic backups on or off for an existing file system. ## Example Usage @@ -17,7 +18,7 @@ resource "aws_efs_file_system" "fs" { creation_token = "my-product" } -resource "aws_efs_file_system_backup_policy" "policy" { +resource "aws_efs_backup_policy" "policy" { file_system_id = aws_efs_file_system.fs.id backup_policy { @@ -31,7 +32,7 @@ resource "aws_efs_file_system_backup_policy" "policy" { The following arguments are supported: * `file_system_id` - (Required) The ID of the EFS file system. -* `backup_policy` - (Required) A file system backup_policy object (documented below). +* `backup_policy` - (Required) A backup_policy object (documented below). ### Backup Policy Arguments For **backup_policy** the following attributes are supported: @@ -46,7 +47,7 @@ In addition to all arguments above, the following attributes are exported: ## Import -The EFS file system backup policies can be imported using the `id`, e.g. +The EFS backup policies can be imported using the `id`, e.g. ``` $ terraform import aws_efs_file_system_backup_policy.example fs-6fa144c6 From 5f0f1c7eca612ee2dba061079a103d0bb2f383c2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 10:34:39 -0400 Subject: [PATCH 0709/1208] Add CHANGELOG entry. --- .changelog/18006.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/18006.txt diff --git a/.changelog/18006.txt b/.changelog/18006.txt new file mode 100644 index 000000000000..544efe7c5488 --- /dev/null +++ b/.changelog/18006.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_efs_backup_policy +``` \ No newline at end of file From 63ac7cb07ce234dd7f410753743a74d926894e3f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 11:18:53 -0400 Subject: [PATCH 0710/1208] r/aws_backup_vault: Delete any recovery points during sweep. Acceptance test output: % TEST=./aws SWEEP=us-east-1,us-west-2 SWEEPARGS=-sweep-run=aws_backup_vault make sweep WARNING: This will destroy infrastructure. Use only in development accounts. go test ./aws -v -sweep=us-east-1,us-west-2 -sweep-run=aws_backup_vault -timeout 60m 2021/06/23 11:17:07 [DEBUG] Running Sweepers for region (us-east-1): 2021/06/23 11:17:07 [DEBUG] Sweeper (aws_backup_vault) has dependency (aws_backup_vault_notifications), running.. 2021/06/23 11:17:07 [DEBUG] Running Sweeper (aws_backup_vault_notifications) in region (us-east-1) 2021/06/23 11:17:07 [INFO] AWS Auth provider used: "EnvProvider" 2021/06/23 11:17:07 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 11:17:07 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 11:17:10 [DEBUG] Waiting for state to become: [success] 2021/06/23 11:17:10 [DEBUG] Sweeper (aws_backup_vault) has dependency (aws_backup_vault_policy), running.. 2021/06/23 11:17:10 [DEBUG] Running Sweeper (aws_backup_vault_policy) in region (us-east-1) 2021/06/23 11:17:10 [INFO] Deleting Backup Vault Policies Default 2021/06/23 11:17:10 [DEBUG] Running Sweeper (aws_backup_vault) in region (us-east-1) 2021/06/23 11:17:10 [INFO] Skipping Backup Vault: Default 2021/06/23 11:17:10 [DEBUG] Sweeper (aws_backup_vault_notifications) already ran in region (us-east-1) 2021/06/23 11:17:10 [DEBUG] Sweeper (aws_backup_vault_policy) already ran in region (us-east-1) 2021/06/23 11:17:10 Sweeper Tests ran successfully: - aws_backup_vault_notifications - aws_backup_vault_policy - aws_backup_vault 2021/06/23 11:17:10 [DEBUG] Running Sweepers for region (us-west-2): 2021/06/23 11:17:10 [DEBUG] Sweeper (aws_backup_vault) has dependency (aws_backup_vault_notifications), running.. 2021/06/23 11:17:10 [DEBUG] Running Sweeper (aws_backup_vault_notifications) in region (us-west-2) 2021/06/23 11:17:10 [INFO] AWS Auth provider used: "EnvProvider" 2021/06/23 11:17:10 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 11:17:10 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 11:17:11 [DEBUG] Waiting for state to become: [success] 2021/06/23 11:17:11 [DEBUG] Waiting for state to become: [success] 2021/06/23 11:17:12 [DEBUG] Sweeper (aws_backup_vault) has dependency (aws_backup_vault_policy), running.. 2021/06/23 11:17:12 [DEBUG] Running Sweeper (aws_backup_vault_policy) in region (us-west-2) 2021/06/23 11:17:12 [INFO] Deleting Backup Vault Policies Default 2021/06/23 11:17:13 [INFO] Deleting Backup Vault Policies aws/efs/automatic-backup-vault 2021/06/23 11:17:13 [DEBUG] Running Sweeper (aws_backup_vault) in region (us-west-2) 2021/06/23 11:17:14 [INFO] Skipping Backup Vault: Default 2021/06/23 11:17:14 [INFO] Skipping Backup Vault: aws/efs/automatic-backup-vault 2021/06/23 11:17:14 [DEBUG] Sweeper (aws_backup_vault_notifications) already ran in region (us-west-2) 2021/06/23 11:17:14 [DEBUG] Sweeper (aws_backup_vault_policy) already ran in region (us-west-2) 2021/06/23 11:17:14 Sweeper Tests ran successfully: - aws_backup_vault_notifications - aws_backup_vault_policy - aws_backup_vault ok github.com/terraform-providers/terraform-provider-aws/aws 10.782s --- aws/resource_aws_backup_vault.go | 8 ++-- aws/resource_aws_backup_vault_test.go | 65 ++++++++++++++++++--------- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/aws/resource_aws_backup_vault.go b/aws/resource_aws_backup_vault.go index 2b15de218ad1..ec0018f6da80 100644 --- a/aws/resource_aws_backup_vault.go +++ b/aws/resource_aws_backup_vault.go @@ -139,13 +139,13 @@ func resourceAwsBackupVaultUpdate(d *schema.ResourceData, meta interface{}) erro func resourceAwsBackupVaultDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).backupconn - input := &backup.DeleteBackupVaultInput{ + log.Printf("[DEBUG] Deleting Backup Vault: %s", d.Id()) + _, err := conn.DeleteBackupVault(&backup.DeleteBackupVaultInput{ BackupVaultName: aws.String(d.Id()), - } + }) - _, err := conn.DeleteBackupVault(input) if err != nil { - return fmt.Errorf("error deleting Backup Vault (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting Backup Vault (%s): %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_backup_vault_test.go b/aws/resource_aws_backup_vault_test.go index fa9e1f2726ca..5d2ad43ed483 100644 --- a/aws/resource_aws_backup_vault_test.go +++ b/aws/resource_aws_backup_vault_test.go @@ -3,12 +3,11 @@ package aws import ( "fmt" "log" - "strings" "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/backup" - "github.com/hashicorp/go-multierror" + multierror "github.com/hashicorp/go-multierror" "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" @@ -31,12 +30,10 @@ func testSweepBackupVaults(region string) error { if err != nil { return fmt.Errorf("Error getting client: %w", err) } - conn := client.(*AWSClient).backupconn - sweepResources := make([]*testSweepResource, 0) - var errs *multierror.Error - input := &backup.ListBackupVaultsInput{} + var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) err = conn.ListBackupVaultsPages(input, func(page *backup.ListBackupVaultsOutput, lastPage bool) bool { if page == nil { @@ -44,22 +41,48 @@ func testSweepBackupVaults(region string) error { } for _, vault := range page.BackupVaultList { - if vault == nil { - continue + failedToDeleteRecoveryPoint := false + name := aws.StringValue(vault.BackupVaultName) + input := &backup.ListRecoveryPointsByBackupVaultInput{ + BackupVaultName: aws.String(name), } - name := aws.StringValue(vault.BackupVaultName) + err := conn.ListRecoveryPointsByBackupVaultPages(input, func(page *backup.ListRecoveryPointsByBackupVaultOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, recoveryPoint := range page.RecoveryPoints { + arn := aws.StringValue(recoveryPoint.RecoveryPointArn) + + log.Printf("[INFO] Deleting Recovery Point (%s) in Backup Vault (%s)", arn, name) + _, err := conn.DeleteRecoveryPoint(&backup.DeleteRecoveryPointInput{ + BackupVaultName: aws.String(name), + RecoveryPointArn: aws.String(arn), + }) - // Ignore Default Backup Vault in region (cannot be deleted) - // and automated Backups that result in AccessDeniedException when deleted - if name == "Default" || strings.Contains(name, "automatic-backup-vault") { + if err != nil { + log.Printf("[WARN] Failed to delete Recovery Point (%s) in Backup Vault (%s): %s", arn, name, err) + failedToDeleteRecoveryPoint = true + } + } + + return !lastPage + }) + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Reovery Points in Backup Vault (%s) for %s: %w", name, region, err)) + } + + // Ignore Default and Automatic EFS Backup Vaults in region (cannot be deleted) + if name == "Default" || name == "aws/efs/automatic-backup-vault" { log.Printf("[INFO] Skipping Backup Vault: %s", name) continue } // Backup Vault deletion only supported when empty // Reference: https://docs.aws.amazon.com/aws-backup/latest/devguide/API_DeleteBackupVault.html - if aws.Int64Value(vault.NumberOfRecoveryPoints) != 0 { + if failedToDeleteRecoveryPoint { log.Printf("[INFO] Skipping Backup Vault (%s): not empty", name) continue } @@ -74,20 +97,20 @@ func testSweepBackupVaults(region string) error { return !lastPage }) - if err != nil { - errs = multierror.Append(errs, fmt.Errorf("error listing Backup Vaults for %s: %w", region, err)) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Backup Vaults sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() } - if err := testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping Backup Vaults for %s: %w", region, err)) + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Backup Vaults for %s: %w", region, err)) } - if testSweepSkipSweepError(errs.ErrorOrNil()) { - log.Printf("[WARN] Skipping Backup Vaults sweep for %s: %s", region, errs) - return nil + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping Backup Vaults for %s: %w", region, err)) } - return errs.ErrorOrNil() + return sweeperErrs.ErrorOrNil() } func TestAccAwsBackupVault_basic(t *testing.T) { From f7af1ead791c844d7db7e6504a162788793dfb49 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 11:31:19 -0400 Subject: [PATCH 0711/1208] Fix tfproviderdocs error. --- website/docs/r/efs_backup_policy.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/efs_backup_policy.html.markdown b/website/docs/r/efs_backup_policy.html.markdown index 50a0f45387ab..bd10cec39104 100644 --- a/website/docs/r/efs_backup_policy.html.markdown +++ b/website/docs/r/efs_backup_policy.html.markdown @@ -6,7 +6,7 @@ description: |- Provides an Elastic File System (EFS) Backup Policy resource. --- -# Resource: aws_efs_file_system_backup_policy +# Resource: aws_efs_backup_policy Provides an Elastic File System (EFS) Backup Policy resource. Backup policies turn automatic backups on or off for an existing file system. @@ -50,5 +50,5 @@ In addition to all arguments above, the following attributes are exported: The EFS backup policies can be imported using the `id`, e.g. ``` -$ terraform import aws_efs_file_system_backup_policy.example fs-6fa144c6 +$ terraform import aws_efs_backup_policy.example fs-6fa144c6 ``` From 9189ec75d4d86159cc33630c7ea40706855a9866 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 23 Jun 2021 12:29:58 -0400 Subject: [PATCH 0712/1208] tests/servicecat_launch_paths: Fix tests --- ...ce_aws_servicecatalog_launch_paths_test.go | 112 ++++++++++++++++-- 1 file changed, 100 insertions(+), 12 deletions(-) diff --git a/aws/data_source_aws_servicecatalog_launch_paths_test.go b/aws/data_source_aws_servicecatalog_launch_paths_test.go index e78d2bf41b0c..09ca1e09301d 100644 --- a/aws/data_source_aws_servicecatalog_launch_paths_test.go +++ b/aws/data_source_aws_servicecatalog_launch_paths_test.go @@ -1,6 +1,7 @@ package aws import ( + "fmt" "testing" "github.com/aws/aws-sdk-go/service/servicecatalog" @@ -8,12 +9,10 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -// THIS IS A HARD CODED TEST TO TEST FUNCTIONALITY WHILE WORKING THROUGH BLOCKED CODE - -// !!FIX THIS!! BEFORE MERGING - func TestAccAWSServiceCatalogLaunchPathsDataSource_basic(t *testing.T) { dataSourceName := "data.aws_servicecatalog_launch_paths.test" + resourceNameProduct := "aws_servicecatalog_product.test" + resourceNamePortfolio := "aws_servicecatalog_portfolio.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -22,23 +21,112 @@ func TestAccAWSServiceCatalogLaunchPathsDataSource_basic(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccAWSServiceCatalogLaunchPathsDataSourceConfig_basic(rName, rName), + Config: testAccAWSServiceCatalogLaunchPathsDataSourceConfig_basic(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(dataSourceName, "accept_language", "en"), - resource.TestCheckResourceAttr(dataSourceName, "product_id", "prod-nui42zvkjm52a"), + resource.TestCheckResourceAttrPair(dataSourceName, "product_id", resourceNameProduct, "id"), resource.TestCheckResourceAttr(dataSourceName, "summaries.#", "1"), - resource.TestCheckResourceAttr(dataSourceName, "summaries.0.path_id", "lpv2-5aftplaxgosvk"), - resource.TestCheckResourceAttr(dataSourceName, "summaries.0.name", "satsuki-11221122"), + resource.TestCheckResourceAttrPair(dataSourceName, "summaries.0.name", resourceNamePortfolio, "name"), + resource.TestCheckResourceAttrSet(dataSourceName, "summaries.0.path_id"), ), }, }, }) } -func testAccAWSServiceCatalogLaunchPathsDataSourceConfig_basic(rName, description string) string { - return ` +func testAccAWSServiceCatalogLaunchPathsDataSourceConfig_base(rName string) string { + return fmt.Sprintf(` +resource "aws_cloudformation_stack" "test" { + name = %[1]q + + template_body = jsonencode({ + AWSTemplateFormatVersion = "2010-09-09" + + Resources = { + MyVPC = { + Type = "AWS::EC2::VPC" + Properties = { + CidrBlock = "10.1.0.0/16" + } + } + } + + Outputs = { + VpcID = { + Description = "VPC ID" + Value = { + Ref = "MyVPC" + } + } + } + }) +} + +resource "aws_servicecatalog_product" "test" { + description = "beskrivning" + distributor = "distributör" + name = %[1]q + owner = "ägare" + type = "CLOUD_FORMATION_TEMPLATE" + support_description = "supportbeskrivning" + support_email = "support@example.com" + support_url = "http://example.com" + + provisioning_artifact_parameters { + description = "artefaktbeskrivning" + name = %[1]q + template_physical_id = aws_cloudformation_stack.test.id + type = "CLOUD_FORMATION_TEMPLATE" + } + + tags = { + Name = %[1]q + } +} + +resource "aws_servicecatalog_portfolio" "test" { + name = %[1]q + provider_name = %[1]q +} + +resource "aws_servicecatalog_product_portfolio_association" "test" { + portfolio_id = aws_servicecatalog_portfolio.test.id + product_id = aws_servicecatalog_product.test.id +} + +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "servicecatalog.${data.aws_partition.current.dns_suffix}" + } + Sid = "" + }] + }) +} + +data "aws_caller_identity" "current" {} + +resource "aws_servicecatalog_principal_portfolio_association" "test" { + portfolio_id = aws_servicecatalog_portfolio.test.id + principal_arn = data.aws_caller_identity.current.arn +} +`, rName) +} + +func testAccAWSServiceCatalogLaunchPathsDataSourceConfig_basic(rName string) string { + return composeConfig(testAccAWSServiceCatalogLaunchPathsDataSourceConfig_base(rName), ` data "aws_servicecatalog_launch_paths" "test" { - product_id = "prod-nui42zvkjm52a" + product_id = aws_servicecatalog_product_portfolio_association.test.product_id + + depends_on = [aws_servicecatalog_principal_portfolio_association.test] } -` +`) } From b3fb2215bdf68c136bdb5ffed11148894e7d2aeb Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 23 Jun 2021 12:30:34 -0400 Subject: [PATCH 0713/1208] i/servicecat_launch_paths: Fix waiter --- aws/internal/service/servicecatalog/waiter/status.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/internal/service/servicecatalog/waiter/status.go b/aws/internal/service/servicecatalog/waiter/status.go index 32372929bbbb..f68a028e0a52 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -346,7 +346,7 @@ func LaunchPathsStatus(conn *servicecatalog.ServiceCatalog, acceptLanguage, prod }) if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { - return nil, StatusNotFound, err + return nil, StatusNotFound, nil } if err != nil { From 5283db312638030102a33d5245f90af1f084b933 Mon Sep 17 00:00:00 2001 From: Gavin Date: Thu, 17 Jun 2021 21:54:34 +0800 Subject: [PATCH 0714/1208] r/aws_backup_vault_policy: warn access denied when destroy policy --- aws/resource_aws_backup_vault_policy.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_backup_vault_policy.go b/aws/resource_aws_backup_vault_policy.go index b382caf340a7..2211d5c654e8 100644 --- a/aws/resource_aws_backup_vault_policy.go +++ b/aws/resource_aws_backup_vault_policy.go @@ -91,7 +91,10 @@ func resourceAwsBackupVaultPolicyDelete(d *schema.ResourceData, meta interface{} _, err := conn.DeleteBackupVaultAccessPolicy(input) if err != nil { - if isAWSErr(err, backup.ErrCodeResourceNotFoundException, "") { + if isAWSErr(err, backup.ErrCodeResourceNotFoundException, "") || + isAWSErr(err, "AccessDeniedException", "") { + log.Printf("[WARN] Backup Vault Policy (%s) not found, removing from state", d.Id()) + d.SetId("") return nil } return fmt.Errorf("error deleting Backup Vault Policy (%s): %w", d.Id(), err) From d02df6fda78dc63af08f1cdfcd679c90cf6462ed Mon Sep 17 00:00:00 2001 From: "Sascha (Oleksandr) Fedorenko" Date: Thu, 10 Jun 2021 10:45:02 +0200 Subject: [PATCH 0715/1208] handing access denied when reading vault policy when vault has been deleted --- aws/resource_aws_backup_vault_policy.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_backup_vault_policy.go b/aws/resource_aws_backup_vault_policy.go index 2211d5c654e8..de6265b998f8 100644 --- a/aws/resource_aws_backup_vault_policy.go +++ b/aws/resource_aws_backup_vault_policy.go @@ -73,8 +73,24 @@ func resourceAwsBackupVaultPolicyRead(d *schema.ResourceData, meta interface{}) } if err != nil { - return fmt.Errorf("error reading Backup Vault Policy (%s): %w", d.Id(), err) + listInput := &backup.ListBackupVaultsInput{} + resp, errList := conn.ListBackupVaults(listInput) + + if errList != nil { + return fmt.Errorf("error reading Backup Vault Policy (%s): %w and could not list Backup Vaults (%s)", d.Id(), err, errList) + } + + for _, el := range resp.BackupVaultList { + if *el.BackupVaultName == d.Id() { + return fmt.Errorf("error reading Backup Vault Policy (%s): %w", d.Id(), err) + } + } + + log.Printf("[WARN] Backup Vault Policy %s not found, removing from state", d.Id()) + d.SetId("") + return nil } + d.Set("backup_vault_name", resp.BackupVaultName) d.Set("policy", resp.Policy) d.Set("backup_vault_arn", resp.BackupVaultArn) From c6c9f76f8eaa4bf59388a756aaba8d39b04f0863 Mon Sep 17 00:00:00 2001 From: "Sascha (Oleksandr) Fedorenko" Date: Thu, 10 Jun 2021 11:51:44 +0200 Subject: [PATCH 0716/1208] calling a function to dereference a pointer --- aws/resource_aws_backup_vault_policy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_backup_vault_policy.go b/aws/resource_aws_backup_vault_policy.go index de6265b998f8..dc2997602975 100644 --- a/aws/resource_aws_backup_vault_policy.go +++ b/aws/resource_aws_backup_vault_policy.go @@ -81,7 +81,7 @@ func resourceAwsBackupVaultPolicyRead(d *schema.ResourceData, meta interface{}) } for _, el := range resp.BackupVaultList { - if *el.BackupVaultName == d.Id() { + if aws.StringValue(el.BackupVaultName) == d.Id() { return fmt.Errorf("error reading Backup Vault Policy (%s): %w", d.Id(), err) } } From 85ad09ac439db0a3a2754f04852c785dba243259 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 12:37:00 -0400 Subject: [PATCH 0717/1208] r/aws_backup_vault_policy: 'AccessDeniedException' => Backup Vault has been deleted. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAwsBackupVaultPolicy_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAwsBackupVaultPolicy_ -timeout 180m === RUN TestAccAwsBackupVaultPolicy_basic === PAUSE TestAccAwsBackupVaultPolicy_basic === RUN TestAccAwsBackupVaultPolicy_disappears === PAUSE TestAccAwsBackupVaultPolicy_disappears === CONT TestAccAwsBackupVaultPolicy_basic === CONT TestAccAwsBackupVaultPolicy_disappears --- PASS: TestAccAwsBackupVaultPolicy_disappears (12.99s) --- PASS: TestAccAwsBackupVaultPolicy_basic (25.17s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 28.498s --- aws/internal/service/backup/errors.go | 5 ++ aws/internal/service/backup/finder/finder.go | 37 +++++++++++ aws/resource_aws_backup_vault_policy.go | 66 ++++++++------------ aws/resource_aws_backup_vault_policy_test.go | 36 ++++++----- 4 files changed, 89 insertions(+), 55 deletions(-) create mode 100644 aws/internal/service/backup/errors.go create mode 100644 aws/internal/service/backup/finder/finder.go diff --git a/aws/internal/service/backup/errors.go b/aws/internal/service/backup/errors.go new file mode 100644 index 000000000000..b07811ea2474 --- /dev/null +++ b/aws/internal/service/backup/errors.go @@ -0,0 +1,5 @@ +package backup + +const ( + ErrCodeAccessDeniedException = "AccessDeniedException" +) diff --git a/aws/internal/service/backup/finder/finder.go b/aws/internal/service/backup/finder/finder.go new file mode 100644 index 000000000000..5541d757a306 --- /dev/null +++ b/aws/internal/service/backup/finder/finder.go @@ -0,0 +1,37 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/backup" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + tfbackup "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/backup" +) + +func BackupVaultAccessPolicyByName(conn *backup.Backup, name string) (*backup.GetBackupVaultAccessPolicyOutput, error) { + input := &backup.GetBackupVaultAccessPolicyInput{ + BackupVaultName: aws.String(name), + } + + output, err := conn.GetBackupVaultAccessPolicy(input) + + if tfawserr.ErrCodeEquals(err, backup.ErrCodeResourceNotFoundException) || tfawserr.ErrCodeEquals(err, tfbackup.ErrCodeAccessDeniedException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output, nil +} diff --git a/aws/resource_aws_backup_vault_policy.go b/aws/resource_aws_backup_vault_policy.go index dc2997602975..670e124fc446 100644 --- a/aws/resource_aws_backup_vault_policy.go +++ b/aws/resource_aws_backup_vault_policy.go @@ -6,8 +6,12 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/backup" + "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" + tfbackup "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/backup" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/backup/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsBackupVaultPolicy() *schema.Resource { @@ -21,6 +25,10 @@ func resourceAwsBackupVaultPolicy() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "backup_vault_arn": { + Type: schema.TypeString, + Computed: true, + }, "backup_vault_name": { Type: schema.TypeString, Required: true, @@ -32,10 +40,6 @@ func resourceAwsBackupVaultPolicy() *schema.Resource { ValidateFunc: validation.StringIsJSON, DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs, }, - "backup_vault_arn": { - Type: schema.TypeString, - Computed: true, - }, }, } } @@ -43,17 +47,19 @@ func resourceAwsBackupVaultPolicy() *schema.Resource { func resourceAwsBackupVaultPolicyPut(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).backupconn + name := d.Get("backup_vault_name").(string) input := &backup.PutBackupVaultAccessPolicyInput{ - BackupVaultName: aws.String(d.Get("backup_vault_name").(string)), + BackupVaultName: aws.String(name), Policy: aws.String(d.Get("policy").(string)), } _, err := conn.PutBackupVaultAccessPolicy(input) + if err != nil { - return fmt.Errorf("error creating Backup Vault Policy (%s): %w", d.Id(), err) + return fmt.Errorf("error creating Backup Vault Policy (%s): %w", name, err) } - d.SetId(d.Get("backup_vault_name").(string)) + d.SetId(name) return resourceAwsBackupVaultPolicyRead(d, meta) } @@ -61,39 +67,21 @@ func resourceAwsBackupVaultPolicyPut(d *schema.ResourceData, meta interface{}) e func resourceAwsBackupVaultPolicyRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).backupconn - input := &backup.GetBackupVaultAccessPolicyInput{ - BackupVaultName: aws.String(d.Id()), - } + output, err := finder.BackupVaultAccessPolicyByName(conn, d.Id()) - resp, err := conn.GetBackupVaultAccessPolicy(input) - if isAWSErr(err, backup.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] Backup Vault Policy %s not found, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Backup Vault Policy (%s) not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - listInput := &backup.ListBackupVaultsInput{} - resp, errList := conn.ListBackupVaults(listInput) - - if errList != nil { - return fmt.Errorf("error reading Backup Vault Policy (%s): %w and could not list Backup Vaults (%s)", d.Id(), err, errList) - } - - for _, el := range resp.BackupVaultList { - if aws.StringValue(el.BackupVaultName) == d.Id() { - return fmt.Errorf("error reading Backup Vault Policy (%s): %w", d.Id(), err) - } - } - - log.Printf("[WARN] Backup Vault Policy %s not found, removing from state", d.Id()) - d.SetId("") - return nil + return fmt.Errorf("error reading Backup Vault Policy (%s): %w", d.Id(), err) } - d.Set("backup_vault_name", resp.BackupVaultName) - d.Set("policy", resp.Policy) - d.Set("backup_vault_arn", resp.BackupVaultArn) + d.Set("backup_vault_arn", output.BackupVaultArn) + d.Set("backup_vault_name", output.BackupVaultName) + d.Set("policy", output.Policy) return nil } @@ -101,18 +89,16 @@ func resourceAwsBackupVaultPolicyRead(d *schema.ResourceData, meta interface{}) func resourceAwsBackupVaultPolicyDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).backupconn - input := &backup.DeleteBackupVaultAccessPolicyInput{ + log.Printf("[DEBUG] Deleting Backup Vault Policy (%s)", d.Id()) + _, err := conn.DeleteBackupVaultAccessPolicy(&backup.DeleteBackupVaultAccessPolicyInput{ BackupVaultName: aws.String(d.Id()), + }) + + if tfawserr.ErrCodeEquals(err, backup.ErrCodeResourceNotFoundException) || tfawserr.ErrCodeEquals(err, tfbackup.ErrCodeAccessDeniedException) { + return nil } - _, err := conn.DeleteBackupVaultAccessPolicy(input) if err != nil { - if isAWSErr(err, backup.ErrCodeResourceNotFoundException, "") || - isAWSErr(err, "AccessDeniedException", "") { - log.Printf("[WARN] Backup Vault Policy (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } return fmt.Errorf("error deleting Backup Vault Policy (%s): %w", d.Id(), err) } diff --git a/aws/resource_aws_backup_vault_policy_test.go b/aws/resource_aws_backup_vault_policy_test.go index 4185e4834d7d..24622c1f566a 100644 --- a/aws/resource_aws_backup_vault_policy_test.go +++ b/aws/resource_aws_backup_vault_policy_test.go @@ -12,6 +12,8 @@ import ( "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/backup/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -73,9 +75,9 @@ func testSweepBackupVaultPolicies(region string) error { func TestAccAwsBackupVaultPolicy_basic(t *testing.T) { var vault backup.GetBackupVaultAccessPolicyOutput - rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_backup_vault_policy.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSBackup(t) }, ErrorCheck: testAccErrorCheck(t, backup.EndpointsID), @@ -107,9 +109,9 @@ func TestAccAwsBackupVaultPolicy_basic(t *testing.T) { func TestAccAwsBackupVaultPolicy_disappears(t *testing.T) { var vault backup.GetBackupVaultAccessPolicyOutput - rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_backup_vault_policy.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSBackup(t) }, ErrorCheck: testAccErrorCheck(t, backup.EndpointsID), @@ -130,22 +132,23 @@ func TestAccAwsBackupVaultPolicy_disappears(t *testing.T) { func testAccCheckAwsBackupVaultPolicyDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).backupconn + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_backup_vault_policy" { continue } - input := &backup.GetBackupVaultAccessPolicyInput{ - BackupVaultName: aws.String(rs.Primary.ID), - } + _, err := finder.BackupVaultAccessPolicyByName(conn, rs.Primary.ID) - resp, err := conn.GetBackupVaultAccessPolicy(input) + if tfresource.NotFound(err) { + continue + } - if err == nil { - if aws.StringValue(resp.BackupVaultName) == rs.Primary.ID { - return fmt.Errorf("Backup Plan Policies '%s' was not deleted properly", rs.Primary.ID) - } + if err != nil { + return err } + + return fmt.Errorf("Backup Vault Policy %s still exists", rs.Primary.ID) } return nil @@ -158,16 +161,19 @@ func testAccCheckAwsBackupVaultPolicyExists(name string, vault *backup.GetBackup return fmt.Errorf("Not found: %s", name) } - conn := testAccProvider.Meta().(*AWSClient).backupconn - params := &backup.GetBackupVaultAccessPolicyInput{ - BackupVaultName: aws.String(rs.Primary.ID), + if rs.Primary.ID == "" { + return fmt.Errorf("No Backup Vault Policy ID is set") } - resp, err := conn.GetBackupVaultAccessPolicy(params) + + conn := testAccProvider.Meta().(*AWSClient).backupconn + + output, err := finder.BackupVaultAccessPolicyByName(conn, rs.Primary.ID) + if err != nil { return err } - *vault = *resp + *vault = *output return nil } From 003214e29897821caf3d0cadfe3172f8c597f555 Mon Sep 17 00:00:00 2001 From: Dirk Avery <31492422+YakDriver@users.noreply.github.com> Date: Wed, 23 Jun 2021 13:05:20 -0400 Subject: [PATCH 0718/1208] Update website/docs/r/lakeformation_permissions.html.markdown Co-authored-by: Kit Ewbank --- website/docs/r/lakeformation_permissions.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index 23e0989b9dc2..9fb3166fe722 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -10,7 +10,7 @@ description: |- Grants permissions to the principal to access metadata in the Data Catalog and data organized in underlying data storage such as Amazon S3. Permissions are granted to a principal, in a Data Catalog, relative to a Lake Formation resource, which includes the Data Catalog, databases, and tables. For more information, see [Security and Access Control to Metadata and Data in Lake Formation](https://docs.aws.amazon.com/lake-formation/latest/dg/security-data-access.html). -~> **NOTE:** In general, the `principal` should _not_ be a Lake Formation administrator or the entity (e.g., IAM role) that is running Terraform. Administrator's have implicit permissions. These should be managed by granting or not granting administrator rights using `aws_lakeformation_data_lake_settings` _not_ with this resource. +~> **NOTE:** In general, the `principal` should _NOT_ be a Lake Formation administrator or the entity (e.g., IAM role) that is running Terraform. Administrators have implicit permissions. These should be managed by granting or not granting administrator rights using `aws_lakeformation_data_lake_settings`, _not_ with this resource. ## Using Lake Formation Permissions From a713fd828b243cfe93615ad0b3821e5eb31c65f4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 23 Jun 2021 13:11:11 -0400 Subject: [PATCH 0719/1208] tests/sweeper/route53_zone: Protect domain --- aws/resource_aws_route53_zone_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index 122667dd79a2..fe1bdb6c28ef 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -98,6 +98,7 @@ func hostedZonesToPreserve() []string { "tfacc.hashicorptest.com", "aws.tfacc.hashicorptest.com", "hashicorp.com", + "terraformtest.com", } } From e20f36149f2d861f581652316f8e5865b1fd82e9 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 23 Jun 2021 17:38:45 +0000 Subject: [PATCH 0720/1208] Update CHANGELOG.md for #19934 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfdf42881acc..ef68fb9e294b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ FEATURES: * **New Resource:** `aws_cloudwatch_event_bus_policy` ([#16874](https://github.com/hashicorp/terraform-provider-aws/issues/16874)) +* **New Resource:** `aws_efs_backup_policy` ([#18006](https://github.com/hashicorp/terraform-provider-aws/issues/18006)) * **New Resource:** `aws_elasticsearch_domain_saml_options` ([#19497](https://github.com/hashicorp/terraform-provider-aws/issues/19497)) * **New Resource:** `aws_neptune_cluster_endpoint` ([#19898](https://github.com/hashicorp/terraform-provider-aws/issues/19898)) @@ -10,6 +11,8 @@ ENHANCEMENTS: * resource/aws_default_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_default_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) +* resource/aws_eks_cluster: Allow updates to `encryption_config` ([#19144](https://github.com/hashicorp/terraform-provider-aws/issues/19144)) +* resource/aws_lb_target_group: Add support for application cookie stickiness ([#18102](https://github.com/hashicorp/terraform-provider-aws/issues/18102)) * resource/aws_main_route_table_association: Wait for association to reach the required state ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_neptune_cluster: Add `copy_snapshot_to_tags` argument ([#19899](https://github.com/hashicorp/terraform-provider-aws/issues/19899)) * resource/aws_route: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) From 56210ad4b6043fe689e0952baf718f59e29fd850 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 13:45:00 -0400 Subject: [PATCH 0721/1208] r/aws_backup_vault_policy: Add test for deleted vault plus modernize sweeper. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAwsBackupVaultPolicy_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAwsBackupVaultPolicy_ -timeout 180m === RUN TestAccAwsBackupVaultPolicy_basic === PAUSE TestAccAwsBackupVaultPolicy_basic === RUN TestAccAwsBackupVaultPolicy_disappears === PAUSE TestAccAwsBackupVaultPolicy_disappears === RUN TestAccAwsBackupVaultPolicy_disappears_vault === PAUSE TestAccAwsBackupVaultPolicy_disappears_vault === CONT TestAccAwsBackupVaultPolicy_basic === CONT TestAccAwsBackupVaultPolicy_disappears_vault === CONT TestAccAwsBackupVaultPolicy_disappears --- PASS: TestAccAwsBackupVaultPolicy_disappears_vault (12.00s) --- PASS: TestAccAwsBackupVaultPolicy_disappears (13.96s) --- PASS: TestAccAwsBackupVaultPolicy_basic (25.44s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 28.825s % TEST=./aws SWEEP=us-east-1,us-east-2,us-west-1,us-west-2 SWEEPARGS=-sweep-run=aws_backup_vault_policy make sweep WARNING: This will destroy infrastructure. Use only in development accounts. go test ./aws -v -sweep=us-east-1,us-east-2,us-west-1,us-west-2 -sweep-run=aws_backup_vault_policy -timeout 60m 2021/06/23 13:43:16 [DEBUG] Running Sweepers for region (us-east-1): 2021/06/23 13:43:16 [DEBUG] Running Sweeper (aws_backup_vault_policy) in region (us-east-1) 2021/06/23 13:43:16 [INFO] AWS Auth provider used: "EnvProvider" 2021/06/23 13:43:16 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 13:43:16 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 13:43:17 [DEBUG] Waiting for state to become: [success] 2021/06/23 13:43:17 [DEBUG] Deleting Backup Vault Policy (Default) 2021/06/23 13:43:17 Sweeper Tests ran successfully: - aws_backup_vault_policy 2021/06/23 13:43:17 [DEBUG] Running Sweepers for region (us-east-2): 2021/06/23 13:43:17 [DEBUG] Running Sweeper (aws_backup_vault_policy) in region (us-east-2) 2021/06/23 13:43:17 [INFO] AWS Auth provider used: "EnvProvider" 2021/06/23 13:43:17 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 13:43:17 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 13:43:17 Sweeper Tests ran successfully: - aws_backup_vault_policy 2021/06/23 13:43:17 [DEBUG] Running Sweepers for region (us-west-1): 2021/06/23 13:43:17 [DEBUG] Running Sweeper (aws_backup_vault_policy) in region (us-west-1) 2021/06/23 13:43:17 [INFO] AWS Auth provider used: "EnvProvider" 2021/06/23 13:43:17 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 13:43:17 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 13:43:18 Sweeper Tests ran successfully: - aws_backup_vault_policy 2021/06/23 13:43:18 [DEBUG] Running Sweepers for region (us-west-2): 2021/06/23 13:43:18 [DEBUG] Running Sweeper (aws_backup_vault_policy) in region (us-west-2) 2021/06/23 13:43:18 [INFO] AWS Auth provider used: "EnvProvider" 2021/06/23 13:43:18 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 13:43:19 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/23 13:43:19 [DEBUG] Waiting for state to become: [success] 2021/06/23 13:43:19 [DEBUG] Waiting for state to become: [success] 2021/06/23 13:43:19 [DEBUG] Deleting Backup Vault Policy (Default) 2021/06/23 13:43:19 [DEBUG] Deleting Backup Vault Policy (aws/efs/automatic-backup-vault) 2021/06/23 13:43:20 Sweeper Tests ran successfully: - aws_backup_vault_policy ok github.com/terraform-providers/terraform-provider-aws/aws 7.233s --- aws/resource_aws_backup_vault_policy_test.go | 82 ++++++++++++-------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/aws/resource_aws_backup_vault_policy_test.go b/aws/resource_aws_backup_vault_policy_test.go index 24622c1f566a..b574690a616b 100644 --- a/aws/resource_aws_backup_vault_policy_test.go +++ b/aws/resource_aws_backup_vault_policy_test.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/backup" - "github.com/hashicorp/go-multierror" + multierror "github.com/hashicorp/go-multierror" "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" @@ -29,45 +29,37 @@ func testSweepBackupVaultPolicies(region string) error { return fmt.Errorf("Error getting client: %w", err) } conn := client.(*AWSClient).backupconn - var sweeperErrs *multierror.Error - input := &backup.ListBackupVaultsInput{} + var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) - for { - output, err := conn.ListBackupVaults(input) - if err != nil { - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping Backup Vault Policies sweep for %s: %s", region, err) - return nil - } - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving Backup Vault Policies: %w", err)) - return sweeperErrs.ErrorOrNil() + err = conn.ListBackupVaultsPages(input, func(page *backup.ListBackupVaultsOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - if len(output.BackupVaultList) == 0 { - log.Print("[DEBUG] No Backup Vault Policies to sweep") - return nil - } + for _, vault := range page.BackupVaultList { + r := resourceAwsBackupVaultPolicy() + d := r.Data(nil) + d.SetId(aws.StringValue(vault.BackupVaultName)) - for _, rule := range output.BackupVaultList { - name := aws.StringValue(rule.BackupVaultName) - - log.Printf("[INFO] Deleting Backup Vault Policies %s", name) - _, err := conn.DeleteBackupVaultAccessPolicy(&backup.DeleteBackupVaultAccessPolicyInput{ - BackupVaultName: aws.String(name), - }) - if err != nil { - sweeperErr := fmt.Errorf("error deleting Backup Vault Policies %s: %w", name, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - if output.NextToken == nil { - break - } - input.NextToken = output.NextToken + return !lastPage + }) + + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Backup Vault Policies sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() + } + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Backup Vaults for %s: %w", region, err)) + } + + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping Backup Vault Policies for %s: %w", region, err)) } return sweeperErrs.ErrorOrNil() @@ -130,6 +122,30 @@ func TestAccAwsBackupVaultPolicy_disappears(t *testing.T) { }) } +func TestAccAwsBackupVaultPolicy_disappears_vault(t *testing.T) { + var vault backup.GetBackupVaultAccessPolicyOutput + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_backup_vault_policy.test" + vaultResourceName := "aws_backup_vault.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSBackup(t) }, + ErrorCheck: testAccErrorCheck(t, backup.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsBackupVaultPolicyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccBackupVaultPolicyConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsBackupVaultPolicyExists(resourceName, &vault), + testAccCheckResourceDisappears(testAccProvider, resourceAwsBackupVault(), vaultResourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAwsBackupVaultPolicyDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).backupconn From 4875d0d221878138091d141a7ffcacdef0be676e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 13:48:12 -0400 Subject: [PATCH 0722/1208] Add CHANGELOG entries. --- .changelog/19749.txt | 3 +++ .changelog/19854.txt | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 .changelog/19749.txt create mode 100644 .changelog/19854.txt diff --git a/.changelog/19749.txt b/.changelog/19749.txt new file mode 100644 index 000000000000..6eb11135d139 --- /dev/null +++ b/.changelog/19749.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_backup_vault_policy: Correctly handle reading policy of deleted vault +``` \ No newline at end of file diff --git a/.changelog/19854.txt b/.changelog/19854.txt new file mode 100644 index 000000000000..6e8f01e19ca9 --- /dev/null +++ b/.changelog/19854.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_backup_vault_policy: Correctly handle deleting policy of deleted vault +``` \ No newline at end of file From 30a0e4501228aaf9d0d46a9b70ac408682e67b20 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 23 Jun 2021 18:54:03 +0000 Subject: [PATCH 0723/1208] Update CHANGELOG.md for #19927 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef68fb9e294b..b11d4a27a086 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ ENHANCEMENTS: BUG FIXES: +* resource/aws_backup_vault_policy: Correctly handle deleting policy of deleted vault ([#19854](https://github.com/hashicorp/terraform-provider-aws/issues/19854)) +* resource/aws_backup_vault_policy: Correctly handle reading policy of deleted vault ([#19749](https://github.com/hashicorp/terraform-provider-aws/issues/19749)) * resource/aws_glue_catalog_database: Set `location_uri` as compute to prevent drift when `target_table` has `location_uri` set. ([#19743](https://github.com/hashicorp/terraform-provider-aws/issues/19743)) * resource/aws_glue_catalog_table: Fix updating `schema_reference` when columns are present. ([#19742](https://github.com/hashicorp/terraform-provider-aws/issues/19742)) From d5e2ae22e509ad832d6a95851ff0d0329e421863 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 23 Jun 2021 15:54:54 -0400 Subject: [PATCH 0724/1208] r/route53_zone: Add a new protected TLD --- aws/resource_aws_route53_zone_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index fe1bdb6c28ef..8e39e13afb7c 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -99,6 +99,7 @@ func hostedZonesToPreserve() []string { "aws.tfacc.hashicorptest.com", "hashicorp.com", "terraformtest.com", + "terraform-provider-aws-acctest-acm.com", } } From 13d6a44eb1a3fae899ea4692ea28dc9132cb4f8e Mon Sep 17 00:00:00 2001 From: shuheiktgw Date: Fri, 19 Feb 2021 07:45:21 +0900 Subject: [PATCH 0725/1208] Add support for ECS capacity provider update --- aws/internal/service/ecs/waiter/status.go | 22 ++++ aws/internal/service/ecs/waiter/waiter.go | 21 +++ aws/resource_aws_ecs_capacity_provider.go | 123 +++++++++++++----- ...resource_aws_ecs_capacity_provider_test.go | 38 ++++-- 4 files changed, 160 insertions(+), 44 deletions(-) diff --git a/aws/internal/service/ecs/waiter/status.go b/aws/internal/service/ecs/waiter/status.go index 14d54c83e191..d4e569815854 100644 --- a/aws/internal/service/ecs/waiter/status.go +++ b/aws/internal/service/ecs/waiter/status.go @@ -1,6 +1,7 @@ package waiter import ( + "fmt" "log" "github.com/aws/aws-sdk-go/aws" @@ -95,3 +96,24 @@ func ClusterStatus(conn *ecs.ECS, arn string) resource.StateRefreshFunc { return output, aws.StringValue(output.Clusters[0].Status), err } } + +// CapacityProviderUpdateStatus fetches the Capacity Provider and its Update Status +func CapacityProviderUpdateStatus(conn *ecs.ECS, capacityProvider string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := conn.DescribeCapacityProviders(&ecs.DescribeCapacityProvidersInput{ + CapacityProviders: []*string{aws.String(capacityProvider)}, + }) + + if err != nil { + return nil, "", err + } + + if len(output.CapacityProviders) == 0 { + return nil, "", fmt.Errorf("ECS Capacity Provider %q missing", capacityProvider) + } + + c := output.CapacityProviders[0] + + return c, aws.StringValue(c.UpdateStatus), nil + } +} diff --git a/aws/internal/service/ecs/waiter/waiter.go b/aws/internal/service/ecs/waiter/waiter.go index a7135e7b3faf..6048ed4d2ff3 100644 --- a/aws/internal/service/ecs/waiter/waiter.go +++ b/aws/internal/service/ecs/waiter/waiter.go @@ -12,6 +12,9 @@ const ( // Maximum amount of time to wait for a Capacity Provider to return INACTIVE CapacityProviderInactiveTimeout = 20 * time.Minute + // Maximum amount of time to wait for a Capacity Provider to return UPDATE_COMPLETE or UPDATE_FAILED + CapacityProviderUpdateTimeout = 10 * time.Minute + ServiceCreateTimeout = 2 * time.Minute ServiceInactiveTimeout = 10 * time.Minute ServiceInactiveTimeoutMin = 1 * time.Second @@ -137,3 +140,21 @@ func ClusterDeleted(conn *ecs.ECS, arn string) (*ecs.Cluster, error) { return nil, err } + +// CapacityProviderUpdate waits for a Capacity Provider to return UPDATE_COMPLETE or UPDATE_FAILED +func CapacityProviderUpdate(conn *ecs.ECS, capacityProvider string) (*ecs.CapacityProvider, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ecs.CapacityProviderUpdateStatusUpdateInProgress}, + Target: []string{ecs.CapacityProviderUpdateStatusUpdateComplete}, + Refresh: CapacityProviderUpdateStatus(conn, capacityProvider), + Timeout: CapacityProviderUpdateTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*ecs.CapacityProvider); ok { + return v, err + } + + return nil, err +} diff --git a/aws/resource_aws_ecs_capacity_provider.go b/aws/resource_aws_ecs_capacity_provider.go index 0e63f6aeb3b9..8bd6f84f3652 100644 --- a/aws/resource_aws_ecs_capacity_provider.go +++ b/aws/resource_aws_ecs_capacity_provider.go @@ -3,16 +3,22 @@ package aws import ( "fmt" "log" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ecs" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/waiter" ) +const ( + ecsCapacityProviderTimeoutUpdate = 10 * time.Minute +) + func resourceAwsEcsCapacityProvider() *schema.Resource { return &schema.Resource{ Create: resourceAwsEcsCapacityProviderCreate, @@ -51,7 +57,6 @@ func resourceAwsEcsCapacityProvider() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ ecs.ManagedTerminationProtectionEnabled, ecs.ManagedTerminationProtectionDisabled, @@ -62,35 +67,30 @@ func resourceAwsEcsCapacityProvider() *schema.Resource { MaxItems: 1, Optional: true, Computed: true, - ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "instance_warmup_period": { Type: schema.TypeInt, Optional: true, Computed: true, - ForceNew: true, ValidateFunc: validation.IntBetween(1, 10000), }, "maximum_scaling_step_size": { Type: schema.TypeInt, Optional: true, Computed: true, - ForceNew: true, ValidateFunc: validation.IntBetween(1, 10000), }, "minimum_scaling_step_size": { Type: schema.TypeInt, Optional: true, Computed: true, - ForceNew: true, ValidateFunc: validation.IntBetween(1, 10000), }, "status": { Type: schema.TypeString, Optional: true, Computed: true, - ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ ecs.ManagedScalingStatusEnabled, ecs.ManagedScalingStatusDisabled, @@ -99,7 +99,6 @@ func resourceAwsEcsCapacityProvider() *schema.Resource { Type: schema.TypeInt, Optional: true, Computed: true, - ForceNew: true, ValidateFunc: validation.IntBetween(1, 100), }, }, @@ -121,7 +120,7 @@ func resourceAwsEcsCapacityProviderCreate(d *schema.ResourceData, meta interface input := ecs.CreateCapacityProviderInput{ Name: aws.String(d.Get("name").(string)), - AutoScalingGroupProvider: expandAutoScalingGroupProvider(d.Get("auto_scaling_group_provider")), + AutoScalingGroupProvider: expandAutoScalingGroupProviderCreate(d.Get("auto_scaling_group_provider")), } // `CreateCapacityProviderInput` does not accept an empty array of tags @@ -132,7 +131,7 @@ func resourceAwsEcsCapacityProviderCreate(d *schema.ResourceData, meta interface out, err := conn.CreateCapacityProvider(&input) if err != nil { - return fmt.Errorf("error creating capacity provider: %s", err) + return fmt.Errorf("error creating ECS Capacity Provider: %s", err) } provider := *out.CapacityProvider @@ -203,15 +202,44 @@ func resourceAwsEcsCapacityProviderRead(d *schema.ResourceData, meta interface{} func resourceAwsEcsCapacityProviderUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ecsconn + input := &ecs.UpdateCapacityProviderInput{ + Name: aws.String(d.Get("name").(string)), + } + + if d.HasChange("auto_scaling_group_provider") { + input.AutoScalingGroupProvider = expandAutoScalingGroupProviderUpdate(d.Get("auto_scaling_group_provider")) + + err := resource.Retry(ecsCapacityProviderTimeoutUpdate, func() *resource.RetryError { + _, err := conn.UpdateCapacityProvider(input) + if err != nil { + if isAWSErr(err, ecs.ErrCodeUpdateInProgressException, "") { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + if isResourceTimeoutError(err) { + _, err = conn.UpdateCapacityProvider(input) + } + if err != nil { + return fmt.Errorf("error updating ECS Capacity Provider (%s): %s", d.Id(), err) + } + + if _, err = waiter.CapacityProviderUpdate(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for ECS Capacity Provider (%s) update: %s", d.Id(), err) + } + } + if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") if err := keyvaluetags.EcsUpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating ECS Cluster (%s) tags: %s", d.Id(), err) + return fmt.Errorf("error updating ECS Capacity Provider (%s) tags: %s", d.Id(), err) } } - return nil + return resourceAwsEcsCapacityProviderRead(d, meta) } func resourceAwsEcsCapacityProviderDelete(d *schema.ResourceData, meta interface{}) error { @@ -246,7 +274,7 @@ func resourceAwsEcsCapacityProviderImport(d *schema.ResourceData, meta interface return []*schema.ResourceData{d}, nil } -func expandAutoScalingGroupProvider(configured interface{}) *ecs.AutoScalingGroupProvider { +func expandAutoScalingGroupProviderCreate(configured interface{}) *ecs.AutoScalingGroupProvider { if configured == nil { return nil } @@ -264,31 +292,64 @@ func expandAutoScalingGroupProvider(configured interface{}) *ecs.AutoScalingGrou prov.ManagedTerminationProtection = aws.String(mtp) } - if v := p["managed_scaling"].([]interface{}); len(v) > 0 && v[0].(map[string]interface{}) != nil { - ms := v[0].(map[string]interface{}) - managedScaling := ecs.ManagedScaling{} + prov.ManagedScaling = expandManagedScaling(p["managed_scaling"]) - if val, ok := ms["instance_warmup_period"].(int); ok && val != 0 { - managedScaling.InstanceWarmupPeriod = aws.Int64(int64(val)) - } - if val, ok := ms["maximum_scaling_step_size"].(int); ok && val != 0 { - managedScaling.MaximumScalingStepSize = aws.Int64(int64(val)) - } - if val, ok := ms["minimum_scaling_step_size"].(int); ok && val != 0 { - managedScaling.MinimumScalingStepSize = aws.Int64(int64(val)) - } - if val, ok := ms["status"].(string); ok && len(val) > 0 { - managedScaling.Status = aws.String(val) - } - if val, ok := ms["target_capacity"].(int); ok && val != 0 { - managedScaling.TargetCapacity = aws.Int64(int64(val)) - } - prov.ManagedScaling = &managedScaling + return &prov +} + +func expandAutoScalingGroupProviderUpdate(configured interface{}) *ecs.AutoScalingGroupProviderUpdate { + if configured == nil { + return nil + } + + if configured.([]interface{}) == nil || len(configured.([]interface{})) == 0 { + return nil } + prov := ecs.AutoScalingGroupProviderUpdate{} + p := configured.([]interface{})[0].(map[string]interface{}) + + if mtp := p["managed_termination_protection"].(string); len(mtp) > 0 { + prov.ManagedTerminationProtection = aws.String(mtp) + } + + prov.ManagedScaling = expandManagedScaling(p["managed_scaling"]) + return &prov } +func expandManagedScaling(configured interface{}) *ecs.ManagedScaling { + if configured == nil { + return nil + } + + if configured.([]interface{}) == nil || len(configured.([]interface{})) == 0 { + return nil + } + + p := configured.([]interface{})[0].(map[string]interface{}) + + managedScaling := ecs.ManagedScaling{} + + if val, ok := p["instance_warmup_period"].(int); ok && val != 0 { + managedScaling.InstanceWarmupPeriod = aws.Int64(int64(val)) + } + if val, ok := p["maximum_scaling_step_size"].(int); ok && val != 0 { + managedScaling.MaximumScalingStepSize = aws.Int64(int64(val)) + } + if val, ok := p["minimum_scaling_step_size"].(int); ok && val != 0 { + managedScaling.MinimumScalingStepSize = aws.Int64(int64(val)) + } + if val, ok := p["status"].(string); ok && len(val) > 0 { + managedScaling.Status = aws.String(val) + } + if val, ok := p["target_capacity"].(int); ok && val != 0 { + managedScaling.TargetCapacity = aws.Int64(int64(val)) + } + + return &managedScaling +} + func flattenAutoScalingGroupProvider(provider *ecs.AutoScalingGroupProvider) []map[string]interface{} { if provider == nil { return nil diff --git a/aws/resource_aws_ecs_capacity_provider_test.go b/aws/resource_aws_ecs_capacity_provider_test.go index baea10c40277..bf740f330a72 100644 --- a/aws/resource_aws_ecs_capacity_provider_test.go +++ b/aws/resource_aws_ecs_capacity_provider_test.go @@ -170,14 +170,14 @@ func TestAccAWSEcsCapacityProvider_ManagedScaling(t *testing.T) { CheckDestroy: testAccCheckAWSEcsCapacityProviderDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEcsCapacityProviderConfigManagedScaling(rName), + Config: testAccAWSEcsCapacityProviderConfigManagedScaling(rName, ecs.ManagedScalingStatusEnabled, 300, 10, 1, 50), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEcsCapacityProviderExists(resourceName, &provider), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttrPair(resourceName, "auto_scaling_group_provider.0.auto_scaling_group_arn", "aws_autoscaling_group.test", "arn"), resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_termination_protection", "DISABLED"), - resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.instance_warmup_period", "400"), - resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.minimum_scaling_step_size", "2"), + resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.instance_warmup_period", "300"), + resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.minimum_scaling_step_size", "1"), resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.maximum_scaling_step_size", "10"), resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.status", "ENABLED"), resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.target_capacity", "50"), @@ -189,6 +189,20 @@ func TestAccAWSEcsCapacityProvider_ManagedScaling(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccAWSEcsCapacityProviderConfigManagedScaling(rName, ecs.ManagedScalingStatusDisabled, 400, 100, 10, 100), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcsCapacityProviderExists(resourceName, &provider), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "auto_scaling_group_provider.0.auto_scaling_group_arn", "aws_autoscaling_group.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_termination_protection", "DISABLED"), + resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.instance_warmup_period", "400"), + resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.minimum_scaling_step_size", "10"), + resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.maximum_scaling_step_size", "100"), + resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.status", "DISABLED"), + resource.TestCheckResourceAttr(resourceName, "auto_scaling_group_provider.0.managed_scaling.0.target_capacity", "100"), + ), + }, }, }) } @@ -274,8 +288,6 @@ func TestAccAWSEcsCapacityProvider_Tags(t *testing.T) { }) } -// TODO add an update test config - Reference: https://github.com/aws/containers-roadmap/issues/633 - func testAccCheckAWSEcsCapacityProviderDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ecsconn @@ -396,24 +408,24 @@ resource "aws_ecs_capacity_provider" "test" { `, rName) } -func testAccAWSEcsCapacityProviderConfigManagedScaling(rName string) string { +func testAccAWSEcsCapacityProviderConfigManagedScaling(rName, status string, warmup, max, min, cap int) string { return testAccAWSEcsCapacityProviderConfigBase(rName) + fmt.Sprintf(` resource "aws_ecs_capacity_provider" "test" { name = %q auto_scaling_group_provider { - auto_scaling_group_arn = aws_autoscaling_group.test.arn + auto_scaling_group_arn = aws_autoscaling_group.test.arn managed_scaling { - instance_warmup_period = 400 - maximum_scaling_step_size = 10 - minimum_scaling_step_size = 2 - status = "ENABLED" - target_capacity = 50 + instance_warmup_period = %v + maximum_scaling_step_size = %v + minimum_scaling_step_size = %v + status = %q + target_capacity = %v } } } -`, rName) +`, rName, warmup, max, min, status, cap) } func testAccAWSEcsCapacityProviderConfigManagedScalingPartial(rName string) string { From 7b87837f1e026b458d0227c387f8e9252821d10a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 24 Feb 2021 18:40:22 -0500 Subject: [PATCH 0726/1208] github: Add labels, colors --- infrastructure/repository/labels-partition.tf | 2 +- infrastructure/repository/labels-service.tf | 2 +- infrastructure/repository/labels-workflow.tf | 55 +++++++++++++++---- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/infrastructure/repository/labels-partition.tf b/infrastructure/repository/labels-partition.tf index 30fa3d006b32..2f31d3436fcb 100644 --- a/infrastructure/repository/labels-partition.tf +++ b/infrastructure/repository/labels-partition.tf @@ -14,5 +14,5 @@ resource "github_issue_label" "partition" { repository = "terraform-provider-aws" name = "partition/${each.value}" - color = "bfd4f2" + color = "491dd7" } diff --git a/infrastructure/repository/labels-service.tf b/infrastructure/repository/labels-service.tf index b63fdee1ee28..2874cbf526c0 100644 --- a/infrastructure/repository/labels-service.tf +++ b/infrastructure/repository/labels-service.tf @@ -220,5 +220,5 @@ resource "github_issue_label" "service" { repository = "terraform-provider-aws" name = "service/${each.value}" - color = "bfd4f2" + color = "623ce4" } diff --git a/infrastructure/repository/labels-workflow.tf b/infrastructure/repository/labels-workflow.tf index 3c62ae2a6b58..0df190371919 100644 --- a/infrastructure/repository/labels-workflow.tf +++ b/infrastructure/repository/labels-workflow.tf @@ -1,15 +1,50 @@ variable "workflow_labels" { default = { - "examples" = "fef2c0", - "hacktoberfest" = "2c0fad", - "linter" = "cccccc", - "needs-triage" = "e236d7", - "terraform-plugin-sdk-migration" = "fad8c7", - "terraform-plugin-sdk-v1" = "fad8c7", - "terraform-0.11" = "cccccc", - "terraform-0.12" = "cccccc", - "terraform-0.13" = "cccccc", - "terraform-0.14" = "cccccc", + "provider" = "623ce4", + "needs-triage" = "ca2171", + "enhancement" = "962fab", + "new-resource" = "962fab", + "new-data-source" = "962fab", + "bug" = "f04e54", + "crash" = "f04e54", + "breaking-change" = "f04e54", + "regression" = "f04e54", + "waiting-response" = "ef4349", + "tests" = "00bc7f", + "terraform-0.11" = "00bc7f", + "terraform-0.12" = "00bc7f", + "terraform-0.13" = "00bc7f", + "terraform-0.14" = "00bc7f", + "terraform-0.15" = "00bc7f", + "alpha-testing" = "00bc7f", + "documentation" = "b0288e", + "technical-debt" = "b0288e", + "proposal" = "b0288e", + "thinking" = "b0288e", + "question" = "b0288e", + "linter" = "b0288e", + "size/XS" = "14c6cb", + "size/S" = "12b4ba", + "size/M" = "11a2a7", + "size/L" = "0f9095", + "size/XL" = "0d7e82", + "size/XXL" = "0b6c6f", + "upstream-terraform" = "1563ff", + "upstream" = "1563ff", + "go" = "1563ff", + "dependencies" = "1563ff", + "good first issue" = "00acff", + "help wanted" = "00acff", + "examples" = "00acff", + "hacktoberfest" = "828a90", + "stale" = "828a90", + "hashibot/ignore" = "828a90", + "new" = "828a90", + "windows" = "828a90", + "reinvent" = "828a90", + "github_actions" = "828a90", + "terraform-plugin-sdk-migration" = "828a90", + "terraform-plugin-sdk-v1" = "828a90", } description = "Name-color mapping of workflow issues" type = map(string) From 47652d5c0c200ac7f80f48fa58c321af430721c3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 16:58:30 -0400 Subject: [PATCH 0727/1208] r/aws_ecs_capacity_provider: Use internal finder package. --- aws/internal/service/ecs/finder/finder.go | 31 +++++ aws/internal/service/ecs/lister/list.go | 3 + .../service/ecs/lister/list_pages_gen.go | 31 +++++ aws/internal/service/ecs/waiter/status.go | 60 ++++------ aws/internal/service/ecs/waiter/waiter.go | 48 ++++---- aws/resource_aws_ecs_capacity_provider.go | 108 ++++++++---------- ...resource_aws_ecs_capacity_provider_test.go | 107 ++++++----------- 7 files changed, 196 insertions(+), 192 deletions(-) create mode 100644 aws/internal/service/ecs/lister/list.go create mode 100644 aws/internal/service/ecs/lister/list_pages_gen.go diff --git a/aws/internal/service/ecs/finder/finder.go b/aws/internal/service/ecs/finder/finder.go index cfb22460a008..987d2c732c3b 100644 --- a/aws/internal/service/ecs/finder/finder.go +++ b/aws/internal/service/ecs/finder/finder.go @@ -6,6 +6,37 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) +func CapacityProviderByARN(conn *ecs.ECS, arn string) (*ecs.CapacityProvider, error) { + input := &ecs.DescribeCapacityProvidersInput{ + CapacityProviders: aws.StringSlice([]string{arn}), + Include: aws.StringSlice([]string{ecs.CapacityProviderFieldTags}), + } + + output, err := conn.DescribeCapacityProviders(input) + + if err != nil { + return nil, err + } + + if output == nil || len(output.CapacityProviders) == 0 || output.CapacityProviders[0] == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + capacityProvider := output.CapacityProviders[0] + + if status := aws.StringValue(capacityProvider.Status); status == ecs.CapacityProviderStatusInactive { + return nil, &resource.NotFoundError{ + Message: status, + LastRequest: input, + } + } + + return capacityProvider, nil +} + func ClusterByARN(conn *ecs.ECS, arn string) (*ecs.DescribeClustersOutput, error) { input := &ecs.DescribeClustersInput{ Clusters: []*string{aws.String(arn)}, diff --git a/aws/internal/service/ecs/lister/list.go b/aws/internal/service/ecs/lister/list.go new file mode 100644 index 000000000000..d57d33e2bde6 --- /dev/null +++ b/aws/internal/service/ecs/lister/list.go @@ -0,0 +1,3 @@ +//go:generate go run ../../../generators/listpages/main.go -function=DescribeCapacityProviders -paginator=NextToken github.com/aws/aws-sdk-go/service/ecs + +package lister diff --git a/aws/internal/service/ecs/lister/list_pages_gen.go b/aws/internal/service/ecs/lister/list_pages_gen.go new file mode 100644 index 000000000000..60deeacadad9 --- /dev/null +++ b/aws/internal/service/ecs/lister/list_pages_gen.go @@ -0,0 +1,31 @@ +// Code generated by "aws/internal/generators/listpages/main.go -function=DescribeCapacityProviders -paginator=NextToken github.com/aws/aws-sdk-go/service/ecs"; DO NOT EDIT. + +package lister + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ecs" +) + +func DescribeCapacityProvidersPages(conn *ecs.ECS, input *ecs.DescribeCapacityProvidersInput, fn func(*ecs.DescribeCapacityProvidersOutput, bool) bool) error { + return DescribeCapacityProvidersPagesWithContext(context.Background(), conn, input, fn) +} + +func DescribeCapacityProvidersPagesWithContext(ctx context.Context, conn *ecs.ECS, input *ecs.DescribeCapacityProvidersInput, fn func(*ecs.DescribeCapacityProvidersOutput, bool) bool) error { + for { + output, err := conn.DescribeCapacityProvidersWithContext(ctx, input) + if err != nil { + return err + } + + lastPage := aws.StringValue(output.NextToken) == "" + if !fn(output, lastPage) || lastPage { + break + } + + input.NextToken = output.NextToken + } + return nil +} diff --git a/aws/internal/service/ecs/waiter/status.go b/aws/internal/service/ecs/waiter/status.go index d4e569815854..db1dd693756e 100644 --- a/aws/internal/service/ecs/waiter/status.go +++ b/aws/internal/service/ecs/waiter/status.go @@ -9,15 +9,10 @@ import ( "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( - // EventSubscription NotFound - CapacityProviderStatusNotFound = "NotFound" - - // EventSubscription Unknown - CapacityProviderStatusUnknown = "Unknown" - // AWS will likely add consts for these at some point ServiceStatusInactive = "INACTIVE" ServiceStatusActive = "ACTIVE" @@ -30,24 +25,40 @@ const ( ClusterStatusNone = "NONE" ) -// CapacityProviderStatus fetches the Capacity Provider and its Status -func CapacityProviderStatus(conn *ecs.ECS, capacityProvider string) resource.StateRefreshFunc { +func CapacityProviderStatus(conn *ecs.ECS, arn string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - input := &ecs.DescribeCapacityProvidersInput{ - CapacityProviders: aws.StringSlice([]string{capacityProvider}), + output, err := finder.CapacityProviderByARN(conn, arn) + + if tfresource.NotFound(err) { + return nil, "", nil } - output, err := conn.DescribeCapacityProviders(input) + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} + +// CapacityProviderUpdateStatus fetches the Capacity Provider and its Update Status +func CapacityProviderUpdateStatus(conn *ecs.ECS, capacityProvider string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := conn.DescribeCapacityProviders(&ecs.DescribeCapacityProvidersInput{ + CapacityProviders: []*string{aws.String(capacityProvider)}, + }) if err != nil { - return nil, CapacityProviderStatusUnknown, err + return nil, "", err } if len(output.CapacityProviders) == 0 { - return nil, CapacityProviderStatusNotFound, nil + return nil, "", fmt.Errorf("ECS Capacity Provider %q missing", capacityProvider) } - return output.CapacityProviders[0], aws.StringValue(output.CapacityProviders[0].Status), nil + c := output.CapacityProviders[0] + + return c, aws.StringValue(c.UpdateStatus), nil } } @@ -96,24 +107,3 @@ func ClusterStatus(conn *ecs.ECS, arn string) resource.StateRefreshFunc { return output, aws.StringValue(output.Clusters[0].Status), err } } - -// CapacityProviderUpdateStatus fetches the Capacity Provider and its Update Status -func CapacityProviderUpdateStatus(conn *ecs.ECS, capacityProvider string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - output, err := conn.DescribeCapacityProviders(&ecs.DescribeCapacityProvidersInput{ - CapacityProviders: []*string{aws.String(capacityProvider)}, - }) - - if err != nil { - return nil, "", err - } - - if len(output.CapacityProviders) == 0 { - return nil, "", fmt.Errorf("ECS Capacity Provider %q missing", capacityProvider) - } - - c := output.CapacityProviders[0] - - return c, aws.StringValue(c.UpdateStatus), nil - } -} diff --git a/aws/internal/service/ecs/waiter/waiter.go b/aws/internal/service/ecs/waiter/waiter.go index 6048ed4d2ff3..d4ceb98e29ea 100644 --- a/aws/internal/service/ecs/waiter/waiter.go +++ b/aws/internal/service/ecs/waiter/waiter.go @@ -9,8 +9,7 @@ import ( ) const ( - // Maximum amount of time to wait for a Capacity Provider to return INACTIVE - CapacityProviderInactiveTimeout = 20 * time.Minute + CapacityProviderDeleteTimeout = 20 * time.Minute // Maximum amount of time to wait for a Capacity Provider to return UPDATE_COMPLETE or UPDATE_FAILED CapacityProviderUpdateTimeout = 10 * time.Minute @@ -26,13 +25,30 @@ const ( ClusterAvailableDelay = 10 * time.Second ) -// CapacityProviderInactive waits for a Capacity Provider to return INACTIVE -func CapacityProviderInactive(conn *ecs.ECS, capacityProvider string) (*ecs.CapacityProvider, error) { +func CapacityProviderDeleted(conn *ecs.ECS, arn string) (*ecs.CapacityProvider, error) { stateConf := &resource.StateChangeConf{ Pending: []string{ecs.CapacityProviderStatusActive}, - Target: []string{ecs.CapacityProviderStatusInactive}, - Refresh: CapacityProviderStatus(conn, capacityProvider), - Timeout: CapacityProviderInactiveTimeout, + Target: []string{""}, + Refresh: CapacityProviderStatus(conn, arn), + Timeout: CapacityProviderDeleteTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if v, ok := outputRaw.(*ecs.CapacityProvider); ok { + return v, err + } + + return nil, err +} + +// CapacityProviderUpdate waits for a Capacity Provider to return UPDATE_COMPLETE or UPDATE_FAILED +func CapacityProviderUpdate(conn *ecs.ECS, capacityProvider string) (*ecs.CapacityProvider, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{ecs.CapacityProviderUpdateStatusUpdateInProgress}, + Target: []string{ecs.CapacityProviderUpdateStatusUpdateComplete}, + Refresh: CapacityProviderUpdateStatus(conn, capacityProvider), + Timeout: CapacityProviderUpdateTimeout, } outputRaw, err := stateConf.WaitForState() @@ -140,21 +156,3 @@ func ClusterDeleted(conn *ecs.ECS, arn string) (*ecs.Cluster, error) { return nil, err } - -// CapacityProviderUpdate waits for a Capacity Provider to return UPDATE_COMPLETE or UPDATE_FAILED -func CapacityProviderUpdate(conn *ecs.ECS, capacityProvider string) (*ecs.CapacityProvider, error) { - stateConf := &resource.StateChangeConf{ - Pending: []string{ecs.CapacityProviderUpdateStatusUpdateInProgress}, - Target: []string{ecs.CapacityProviderUpdateStatusUpdateComplete}, - Refresh: CapacityProviderUpdateStatus(conn, capacityProvider), - Timeout: CapacityProviderUpdateTimeout, - } - - outputRaw, err := stateConf.WaitForState() - - if v, ok := outputRaw.(*ecs.CapacityProvider); ok { - return v, err - } - - return nil, err -} diff --git a/aws/resource_aws_ecs_capacity_provider.go b/aws/resource_aws_ecs_capacity_provider.go index 8bd6f84f3652..96ea38cae031 100644 --- a/aws/resource_aws_ecs_capacity_provider.go +++ b/aws/resource_aws_ecs_capacity_provider.go @@ -8,11 +8,14 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ecs" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -30,12 +33,8 @@ func resourceAwsEcsCapacityProvider() *schema.Resource { }, CustomizeDiff: SetTagsDiff, + Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, "arn": { Type: schema.TypeString, Computed: true, @@ -50,17 +49,8 @@ func resourceAwsEcsCapacityProvider() *schema.Resource { "auto_scaling_group_arn": { Type: schema.TypeString, Required: true, - ValidateFunc: validateArn, ForceNew: true, - }, - "managed_termination_protection": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.ManagedTerminationProtectionEnabled, - ecs.ManagedTerminationProtectionDisabled, - }, false), + ValidateFunc: validateArn, }, "managed_scaling": { Type: schema.TypeList, @@ -88,13 +78,10 @@ func resourceAwsEcsCapacityProvider() *schema.Resource { ValidateFunc: validation.IntBetween(1, 10000), }, "status": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice([]string{ - ecs.ManagedScalingStatusEnabled, - ecs.ManagedScalingStatusDisabled, - }, false)}, + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(ecs.ManagedScalingStatus_Values(), false)}, "target_capacity": { Type: schema.TypeInt, Optional: true, @@ -104,9 +91,20 @@ func resourceAwsEcsCapacityProvider() *schema.Resource { }, }, }, + "managed_termination_protection": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(ecs.ManagedTerminationProtection_Values(), false), + }, }, }, }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), }, @@ -118,8 +116,9 @@ func resourceAwsEcsCapacityProviderCreate(d *schema.ResourceData, meta interface defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) + name := d.Get("name").(string) input := ecs.CreateCapacityProviderInput{ - Name: aws.String(d.Get("name").(string)), + Name: aws.String(name), AutoScalingGroupProvider: expandAutoScalingGroupProviderCreate(d.Get("auto_scaling_group_provider")), } @@ -128,16 +127,13 @@ func resourceAwsEcsCapacityProviderCreate(d *schema.ResourceData, meta interface input.Tags = tags.IgnoreAws().EcsTags() } - out, err := conn.CreateCapacityProvider(&input) + output, err := conn.CreateCapacityProvider(&input) if err != nil { - return fmt.Errorf("error creating ECS Capacity Provider: %s", err) + return fmt.Errorf("error creating ECS Capacity Provider (%s): %w", name, err) } - provider := *out.CapacityProvider - - log.Printf("[DEBUG] ECS Capacity Provider created: %s", aws.StringValue(provider.CapacityProviderArn)) - d.SetId(aws.StringValue(provider.CapacityProviderArn)) + d.SetId(aws.StringValue(output.CapacityProvider.CapacityProviderArn)) return resourceAwsEcsCapacityProviderRead(d, meta) } @@ -147,41 +143,27 @@ func resourceAwsEcsCapacityProviderRead(d *schema.ResourceData, meta interface{} defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - input := &ecs.DescribeCapacityProvidersInput{ - CapacityProviders: []*string{aws.String(d.Id())}, - Include: []*string{aws.String(ecs.CapacityProviderFieldTags)}, - } - - output, err := conn.DescribeCapacityProviders(input) - - if err != nil { - return fmt.Errorf("error reading ECS Capacity Provider (%s): %s", d.Id(), err) - } + output, err := finder.CapacityProviderByARN(conn, d.Id()) - var provider *ecs.CapacityProvider - for _, cp := range output.CapacityProviders { - if aws.StringValue(cp.CapacityProviderArn) == d.Id() { - provider = cp - break - } - } - - if provider == nil { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] ECS Capacity Provider (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - if aws.StringValue(provider.Status) == ecs.CapacityProviderStatusInactive { - log.Printf("[WARN] ECS Capacity Provider (%s) is INACTIVE, removing from state", d.Id()) - d.SetId("") - return nil + if err != nil { + return fmt.Errorf("error reading ECS Capacity Provider (%s): %w", d.Id(), err) + } + + d.Set("arn", output.CapacityProviderArn) + + if err := d.Set("auto_scaling_group_provider", flattenAutoScalingGroupProvider(output.AutoScalingGroupProvider)); err != nil { + return fmt.Errorf("error setting auto_scaling_group_provider: %w", err) } - d.Set("arn", provider.CapacityProviderArn) - d.Set("name", provider.Name) + d.Set("name", output.Name) - tags := keyvaluetags.EcsKeyValueTags(provider.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + tags := keyvaluetags.EcsKeyValueTags(output.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { @@ -192,10 +174,6 @@ func resourceAwsEcsCapacityProviderRead(d *schema.ResourceData, meta interface{} return fmt.Errorf("error setting tags_all: %w", err) } - if err := d.Set("auto_scaling_group_provider", flattenAutoScalingGroupProvider(provider.AutoScalingGroupProvider)); err != nil { - return fmt.Errorf("error setting autoscaling group provider: %s", err) - } - return nil } @@ -245,17 +223,21 @@ func resourceAwsEcsCapacityProviderUpdate(d *schema.ResourceData, meta interface func resourceAwsEcsCapacityProviderDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ecsconn - input := &ecs.DeleteCapacityProviderInput{ + log.Printf("[DEBUG] Deleting ECS Capacity Provider (%s)", d.Id()) + _, err := conn.DeleteCapacityProvider(&ecs.DeleteCapacityProviderInput{ CapacityProvider: aws.String(d.Id()), - } + }) - _, err := conn.DeleteCapacityProvider(input) + // "An error occurred (ClientException) when calling the DeleteCapacityProvider operation: The specified capacity provider does not exist. Specify a valid name or ARN and try again." + if tfawserr.ErrMessageContains(err, ecs.ErrCodeClientException, "capacity provider does not exist") { + return nil + } if err != nil { return fmt.Errorf("error deleting ECS Capacity Provider (%s): %w", d.Id(), err) } - if _, err := waiter.CapacityProviderInactive(conn, d.Id()); err != nil { + if _, err := waiter.CapacityProviderDeleted(conn, d.Id()); err != nil { return fmt.Errorf("error waiting for ECS Capacity Provider (%s) to delete: %w", d.Id(), err) } diff --git a/aws/resource_aws_ecs_capacity_provider_test.go b/aws/resource_aws_ecs_capacity_provider_test.go index bf740f330a72..c0146e78d275 100644 --- a/aws/resource_aws_ecs_capacity_provider_test.go +++ b/aws/resource_aws_ecs_capacity_provider_test.go @@ -11,7 +11,9 @@ import ( "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" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/lister" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -27,71 +29,48 @@ func init() { func testSweepEcsCapacityProviders(region string) error { client, err := sharedClientForRegion(region) - if err != nil { return fmt.Errorf("error getting client: %w", err) } - conn := client.(*AWSClient).ecsconn input := &ecs.DescribeCapacityProvidersInput{} var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) - for { - output, err := conn.DescribeCapacityProviders(input) - - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping ECS Capacity Provider sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() + err = lister.DescribeCapacityProvidersPages(conn, input, func(page *ecs.DescribeCapacityProvidersOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving ECS Capacity Provider: %w", err)) - return sweeperErrs - } - - for _, capacityProvider := range output.CapacityProviders { - if capacityProvider == nil { - continue - } - + for _, capacityProvider := range page.CapacityProviders { arn := aws.StringValue(capacityProvider.CapacityProviderArn) - input := &ecs.DeleteCapacityProviderInput{ - CapacityProvider: capacityProvider.CapacityProviderArn, - } - if aws.StringValue(capacityProvider.Name) == "FARGATE" || aws.StringValue(capacityProvider.Name) == "FARGATE_SPOT" { + if name := aws.StringValue(capacityProvider.Name); name == "FARGATE" || name == "FARGATE_SPOT" { log.Printf("[INFO] Skipping AWS managed ECS Capacity Provider: %s", arn) continue } - if aws.StringValue(capacityProvider.Status) == ecs.CapacityProviderStatusInactive { - log.Printf("[INFO] Skipping ECS Capacity Provider with INACTIVE status: %s", arn) - continue - } + r := resourceAwsEcsCapacityProvider() + d := r.Data(nil) + d.SetId(arn) - log.Printf("[INFO] Deleting ECS Capacity Provider: %s", arn) - _, err := conn.DeleteCapacityProvider(input) + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } - if err != nil { - sweeperErr := fmt.Errorf("error deleting ECS Capacity Provider (%s): %w", arn, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } + return !lastPage + }) - if _, err := waiter.CapacityProviderInactive(conn, arn); err != nil { - sweeperErr := fmt.Errorf("error waiting for ECS Capacity Provider (%s) to delete: %w", arn, err) - log.Printf("[ERROR] %s", sweeperErr) - sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) - continue - } - } + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping ECS Capacity Providers sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() + } - if aws.StringValue(output.NextToken) == "" { - break - } + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing ECS Capacity Providers for %s: %w", region, err)) + } - input.NextToken = output.NextToken + if err := testSweepResourceOrchestrator(sweepResources); err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping ECS Capacity Providers for %s: %w", region, err)) } return sweeperErrs.ErrorOrNil() @@ -296,21 +275,17 @@ func testAccCheckAWSEcsCapacityProviderDestroy(s *terraform.State) error { continue } - input := &ecs.DescribeCapacityProvidersInput{ - CapacityProviders: aws.StringSlice([]string{rs.Primary.ID}), - } + _, err := finder.CapacityProviderByARN(conn, rs.Primary.ID) - output, err := conn.DescribeCapacityProviders(input) + if tfresource.NotFound(err) { + continue + } if err != nil { return err } - for _, capacityProvider := range output.CapacityProviders { - if aws.StringValue(capacityProvider.CapacityProviderArn) == rs.Primary.ID && aws.StringValue(capacityProvider.Status) != ecs.CapacityProviderStatusInactive { - return fmt.Errorf("ECS Capacity Provider (%s) still exists", rs.Primary.ID) - } - } + return fmt.Errorf("ECS Capacity Provider ID %s still exists", rs.Primary.ID) } return nil @@ -323,27 +298,21 @@ func testAccCheckAWSEcsCapacityProviderExists(resourceName string, provider *ecs return fmt.Errorf("Not found: %s", resourceName) } - conn := testAccProvider.Meta().(*AWSClient).ecsconn - - input := &ecs.DescribeCapacityProvidersInput{ - CapacityProviders: []*string{aws.String(rs.Primary.ID)}, - Include: []*string{aws.String(ecs.CapacityProviderFieldTags)}, + if rs.Primary.ID == "" { + return fmt.Errorf("No ECS Capacity Provider ID is set") } - output, err := conn.DescribeCapacityProviders(input) + conn := testAccProvider.Meta().(*AWSClient).ecsconn + + output, err := finder.CapacityProviderByARN(conn, rs.Primary.ID) if err != nil { - return fmt.Errorf("error reading ECS Capacity Provider (%s): %s", rs.Primary.ID, err) + return err } - for _, cp := range output.CapacityProviders { - if aws.StringValue(cp.CapacityProviderArn) == rs.Primary.ID { - *provider = *cp - return nil - } - } + *provider = *output - return fmt.Errorf("ECS Capacity Provider (%s) not found", rs.Primary.ID) + return nil } } From 341a912fae2c72cd888dce5bfacff7944f8896aa Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 17:25:42 -0400 Subject: [PATCH 0728/1208] r/aws_ecs_capacity_provider: Simplify waiting for update. --- aws/internal/service/ecs/waiter/status.go | 20 ++++----- aws/internal/service/ecs/waiter/waiter.go | 9 ++-- aws/resource_aws_ecs_capacity_provider.go | 42 +++++++++---------- ...resource_aws_ecs_capacity_provider_test.go | 22 +++++----- 4 files changed, 42 insertions(+), 51 deletions(-) diff --git a/aws/internal/service/ecs/waiter/status.go b/aws/internal/service/ecs/waiter/status.go index db1dd693756e..2572a04dca1c 100644 --- a/aws/internal/service/ecs/waiter/status.go +++ b/aws/internal/service/ecs/waiter/status.go @@ -1,7 +1,6 @@ package waiter import ( - "fmt" "log" "github.com/aws/aws-sdk-go/aws" @@ -41,24 +40,19 @@ func CapacityProviderStatus(conn *ecs.ECS, arn string) resource.StateRefreshFunc } } -// CapacityProviderUpdateStatus fetches the Capacity Provider and its Update Status -func CapacityProviderUpdateStatus(conn *ecs.ECS, capacityProvider string) resource.StateRefreshFunc { +func CapacityProviderUpdateStatus(conn *ecs.ECS, arn string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := conn.DescribeCapacityProviders(&ecs.DescribeCapacityProvidersInput{ - CapacityProviders: []*string{aws.String(capacityProvider)}, - }) + output, err := finder.CapacityProviderByARN(conn, arn) - if err != nil { - return nil, "", err + if tfresource.NotFound(err) { + return nil, "", nil } - if len(output.CapacityProviders) == 0 { - return nil, "", fmt.Errorf("ECS Capacity Provider %q missing", capacityProvider) + if err != nil { + return nil, "", err } - c := output.CapacityProviders[0] - - return c, aws.StringValue(c.UpdateStatus), nil + return output, aws.StringValue(output.UpdateStatus), nil } } diff --git a/aws/internal/service/ecs/waiter/waiter.go b/aws/internal/service/ecs/waiter/waiter.go index d4ceb98e29ea..8c4a462047d4 100644 --- a/aws/internal/service/ecs/waiter/waiter.go +++ b/aws/internal/service/ecs/waiter/waiter.go @@ -10,8 +10,6 @@ import ( const ( CapacityProviderDeleteTimeout = 20 * time.Minute - - // Maximum amount of time to wait for a Capacity Provider to return UPDATE_COMPLETE or UPDATE_FAILED CapacityProviderUpdateTimeout = 10 * time.Minute ServiceCreateTimeout = 2 * time.Minute @@ -28,7 +26,7 @@ const ( func CapacityProviderDeleted(conn *ecs.ECS, arn string) (*ecs.CapacityProvider, error) { stateConf := &resource.StateChangeConf{ Pending: []string{ecs.CapacityProviderStatusActive}, - Target: []string{""}, + Target: []string{}, Refresh: CapacityProviderStatus(conn, arn), Timeout: CapacityProviderDeleteTimeout, } @@ -42,12 +40,11 @@ func CapacityProviderDeleted(conn *ecs.ECS, arn string) (*ecs.CapacityProvider, return nil, err } -// CapacityProviderUpdate waits for a Capacity Provider to return UPDATE_COMPLETE or UPDATE_FAILED -func CapacityProviderUpdate(conn *ecs.ECS, capacityProvider string) (*ecs.CapacityProvider, error) { +func CapacityProviderUpdated(conn *ecs.ECS, arn string) (*ecs.CapacityProvider, error) { stateConf := &resource.StateChangeConf{ Pending: []string{ecs.CapacityProviderUpdateStatusUpdateInProgress}, Target: []string{ecs.CapacityProviderUpdateStatusUpdateComplete}, - Refresh: CapacityProviderUpdateStatus(conn, capacityProvider), + Refresh: CapacityProviderUpdateStatus(conn, arn), Timeout: CapacityProviderUpdateTimeout, } diff --git a/aws/resource_aws_ecs_capacity_provider.go b/aws/resource_aws_ecs_capacity_provider.go index 96ea38cae031..244bcab916ad 100644 --- a/aws/resource_aws_ecs_capacity_provider.go +++ b/aws/resource_aws_ecs_capacity_provider.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" @@ -18,10 +17,6 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -const ( - ecsCapacityProviderTimeoutUpdate = 10 * time.Minute -) - func resourceAwsEcsCapacityProvider() *schema.Resource { return &schema.Resource{ Create: resourceAwsEcsCapacityProviderCreate, @@ -127,6 +122,7 @@ func resourceAwsEcsCapacityProviderCreate(d *schema.ResourceData, meta interface input.Tags = tags.IgnoreAws().EcsTags() } + log.Printf("[DEBUG] Creating ECS Capacity Provider: %s", input) output, err := conn.CreateCapacityProvider(&input) if err != nil { @@ -180,40 +176,44 @@ func resourceAwsEcsCapacityProviderRead(d *schema.ResourceData, meta interface{} func resourceAwsEcsCapacityProviderUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ecsconn - input := &ecs.UpdateCapacityProviderInput{ - Name: aws.String(d.Get("name").(string)), - } - - if d.HasChange("auto_scaling_group_provider") { - input.AutoScalingGroupProvider = expandAutoScalingGroupProviderUpdate(d.Get("auto_scaling_group_provider")) + if d.HasChangesExcept("tags", "tags_all") { + input := &ecs.UpdateCapacityProviderInput{ + AutoScalingGroupProvider: expandAutoScalingGroupProviderUpdate(d.Get("auto_scaling_group_provider")), + Name: aws.String(d.Get("name").(string)), + } - err := resource.Retry(ecsCapacityProviderTimeoutUpdate, func() *resource.RetryError { + log.Printf("[DEBUG] Updating ECS Capacity Provider: %s", input) + err := resource.Retry(waiter.CapacityProviderUpdateTimeout, func() *resource.RetryError { _, err := conn.UpdateCapacityProvider(input) + + if tfawserr.ErrCodeEquals(err, ecs.ErrCodeUpdateInProgressException) { + return resource.RetryableError(err) + } + if err != nil { - if isAWSErr(err, ecs.ErrCodeUpdateInProgressException, "") { - return resource.RetryableError(err) - } return resource.NonRetryableError(err) } + return nil }) - if isResourceTimeoutError(err) { + + if tfresource.TimedOut(err) { _, err = conn.UpdateCapacityProvider(input) } + if err != nil { - return fmt.Errorf("error updating ECS Capacity Provider (%s): %s", d.Id(), err) + return fmt.Errorf("error updating ECS Capacity Provider (%s): %w", d.Id(), err) } - if _, err = waiter.CapacityProviderUpdate(conn, d.Id()); err != nil { - return fmt.Errorf("error waiting for ECS Capacity Provider (%s) update: %s", d.Id(), err) + if _, err = waiter.CapacityProviderUpdated(conn, d.Id()); err != nil { + return fmt.Errorf("error waiting for ECS Capacity Provider (%s) to update: %w", d.Id(), err) } } if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") - if err := keyvaluetags.EcsUpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating ECS Capacity Provider (%s) tags: %s", d.Id(), err) + return fmt.Errorf("error updating ECS Capacity Provider (%s) tags: %w", d.Id(), err) } } diff --git a/aws/resource_aws_ecs_capacity_provider_test.go b/aws/resource_aws_ecs_capacity_provider_test.go index c0146e78d275..ff206af8d733 100644 --- a/aws/resource_aws_ecs_capacity_provider_test.go +++ b/aws/resource_aws_ecs_capacity_provider_test.go @@ -380,17 +380,17 @@ resource "aws_ecs_capacity_provider" "test" { func testAccAWSEcsCapacityProviderConfigManagedScaling(rName, status string, warmup, max, min, cap int) string { return testAccAWSEcsCapacityProviderConfigBase(rName) + fmt.Sprintf(` resource "aws_ecs_capacity_provider" "test" { - name = %q + name = %[1]q auto_scaling_group_provider { auto_scaling_group_arn = aws_autoscaling_group.test.arn managed_scaling { - instance_warmup_period = %v - maximum_scaling_step_size = %v - minimum_scaling_step_size = %v - status = %q - target_capacity = %v + instance_warmup_period = %[2]d + maximum_scaling_step_size = %[3]d + minimum_scaling_step_size = %[4]d + status = %[5]q + target_capacity = %[6]d } } } @@ -400,7 +400,7 @@ resource "aws_ecs_capacity_provider" "test" { func testAccAWSEcsCapacityProviderConfigManagedScalingPartial(rName string) string { return testAccAWSEcsCapacityProviderConfigBase(rName) + fmt.Sprintf(` resource "aws_ecs_capacity_provider" "test" { - name = %q + name = %[1]q auto_scaling_group_provider { auto_scaling_group_arn = aws_autoscaling_group.test.arn @@ -420,7 +420,7 @@ resource "aws_ecs_capacity_provider" "test" { name = %[1]q tags = { - %[2]q = %[3]q, + %[2]q = %[3]q } auto_scaling_group_provider { @@ -433,11 +433,11 @@ resource "aws_ecs_capacity_provider" "test" { func testAccAWSEcsCapacityProviderConfigTags2(rName, tag1Key, tag1Value, tag2Key, tag2Value string) string { return testAccAWSEcsCapacityProviderConfigBase(rName) + fmt.Sprintf(` resource "aws_ecs_capacity_provider" "test" { - name = %q + name = %[1]q tags = { - %q = %q, - %q = %q, + %[2]q = %[3]q + %[4]q = %[5]q } auto_scaling_group_provider { From 81edd552bbb9508f449509e3f9381ff036f4ecbd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 23 Jun 2021 17:27:41 -0400 Subject: [PATCH 0729/1208] Add CHANGELOG entry. --- .changelog/16942.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/16942.txt diff --git a/.changelog/16942.txt b/.changelog/16942.txt new file mode 100644 index 000000000000..c1aba454d3e2 --- /dev/null +++ b/.changelog/16942.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_ecs_capacity_provider: Allow updates to the `auto_scaling_group_provider` argument without recreating the resource +``` \ No newline at end of file From 444c6570735d517659961cbb89e4e0df2e84b51b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 23 Jun 2021 17:35:38 -0400 Subject: [PATCH 0730/1208] infra: Update colors for current HashiCorp --- infrastructure/repository/labels-partition.tf | 2 +- infrastructure/repository/labels-service.tf | 2 +- infrastructure/repository/labels-workflow.tf | 90 +++++++++---------- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/infrastructure/repository/labels-partition.tf b/infrastructure/repository/labels-partition.tf index 2f31d3436fcb..e05db93f9b5f 100644 --- a/infrastructure/repository/labels-partition.tf +++ b/infrastructure/repository/labels-partition.tf @@ -14,5 +14,5 @@ resource "github_issue_label" "partition" { repository = "terraform-provider-aws" name = "partition/${each.value}" - color = "491dd7" + color = "844fba" } diff --git a/infrastructure/repository/labels-service.tf b/infrastructure/repository/labels-service.tf index 2874cbf526c0..7e91d3a12974 100644 --- a/infrastructure/repository/labels-service.tf +++ b/infrastructure/repository/labels-service.tf @@ -220,5 +220,5 @@ resource "github_issue_label" "service" { repository = "terraform-provider-aws" name = "service/${each.value}" - color = "623ce4" + color = "7b42bc" } diff --git a/infrastructure/repository/labels-workflow.tf b/infrastructure/repository/labels-workflow.tf index 0df190371919..9824f161d49c 100644 --- a/infrastructure/repository/labels-workflow.tf +++ b/infrastructure/repository/labels-workflow.tf @@ -1,50 +1,50 @@ variable "workflow_labels" { default = { - "provider" = "623ce4", - "needs-triage" = "ca2171", - "enhancement" = "962fab", - "new-resource" = "962fab", - "new-data-source" = "962fab", - "bug" = "f04e54", - "crash" = "f04e54", - "breaking-change" = "f04e54", - "regression" = "f04e54", - "waiting-response" = "ef4349", - "tests" = "00bc7f", - "terraform-0.11" = "00bc7f", - "terraform-0.12" = "00bc7f", - "terraform-0.13" = "00bc7f", - "terraform-0.14" = "00bc7f", - "terraform-0.15" = "00bc7f", - "alpha-testing" = "00bc7f", - "documentation" = "b0288e", - "technical-debt" = "b0288e", - "proposal" = "b0288e", - "thinking" = "b0288e", - "question" = "b0288e", - "linter" = "b0288e", - "size/XS" = "14c6cb", - "size/S" = "12b4ba", - "size/M" = "11a2a7", - "size/L" = "0f9095", - "size/XL" = "0d7e82", - "size/XXL" = "0b6c6f", - "upstream-terraform" = "1563ff", - "upstream" = "1563ff", - "go" = "1563ff", - "dependencies" = "1563ff", - "good first issue" = "00acff", - "help wanted" = "00acff", - "examples" = "00acff", - "hacktoberfest" = "828a90", - "stale" = "828a90", - "hashibot/ignore" = "828a90", - "new" = "828a90", - "windows" = "828a90", - "reinvent" = "828a90", - "github_actions" = "828a90", - "terraform-plugin-sdk-migration" = "828a90", - "terraform-plugin-sdk-v1" = "828a90", + "provider" = "844fba", # color:terraform (main) + "needs-triage" = "dc477d", # color:consul + "enhancement" = "844fba", # color:terraform (main) + "new-resource" = "8040c9", # color:terraform (link on white) + "new-data-source" = "ac72f0", # color:terraform (link on black) + "bug" = "ec585d", # color:boundary + "crash" = "ec585d", # color:boundary + "breaking-change" = "ec585d", # color:boundary + "regression" = "ec585d", # color:boundary + "waiting-response" = "d3353f", # color:darker boundary + "tests" = "60dea9", # color:nomad + "terraform-0.11" = "60dea9", # color:nomad + "terraform-0.12" = "60dea9", # color:nomad + "terraform-0.13" = "60dea9", # color:nomad + "terraform-0.14" = "60dea9", # color:nomad + "terraform-0.15" = "60dea9", # color:nomad + "alpha-testing" = "60dea9", # color:nomad + "documentation" = "f4ecff", # color:terraform secondary + "technical-debt" = "d1ebff", # color:terraform accent + "proposal" = "d1ebff", # color:terraform accent + "thinking" = "f4ecff", # color:terraform secondary + "question" = "f4ecff", # color:terraform secondary + "linter" = "f4ecff", # color:terraform secondary + "size/XS" = "62d4dc", # color:lightest-darkest waypoint gradient + "size/S" = "4ec3ce", # color:lightest-darkest waypoint gradient + "size/M" = "3bb3c0", # color:lightest-darkest waypoint gradient + "size/L" = "27a2b2", # color:lightest-darkest waypoint gradient + "size/XL" = "1492a4", # color:lightest-darkest waypoint gradient + "size/XXL" = "008196", # color:lightest-darkest waypoint gradient + "upstream-terraform" = "1c7ada", # color:vagrant + "upstream" = "1c7ada", # color:vagrant + "go" = "1c7ada", # color:vagrant + "dependencies" = "1c7ada", # color:vagrant + "good first issue" = "63d0ff", # color:packer + "help wanted" = "63d0ff", # color:packer + "examples" = "63d0ff", # color:packer + "hacktoberfest" = "828a90", # color:stale grey + "stale" = "828a90", # color:stale grey + "hashibot/ignore" = "828a90", # color:stale grey + "new" = "828a90", # color:stale grey + "windows" = "828a90", # color:stale grey + "reinvent" = "828a90", # color:stale grey + "github_actions" = "828a90", # color:stale grey + "terraform-plugin-sdk-migration" = "828a90", # color:stale grey + "terraform-plugin-sdk-v1" = "828a90", # color:stale grey } description = "Name-color mapping of workflow issues" type = map(string) From 73f33aa85875a9a364418413e9ceb86851213c40 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 23 Jun 2021 17:38:34 -0400 Subject: [PATCH 0731/1208] infra: Add comments for colors --- infrastructure/repository/labels-partition.tf | 2 +- infrastructure/repository/labels-service.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/repository/labels-partition.tf b/infrastructure/repository/labels-partition.tf index e05db93f9b5f..740e4c1edf3a 100644 --- a/infrastructure/repository/labels-partition.tf +++ b/infrastructure/repository/labels-partition.tf @@ -14,5 +14,5 @@ resource "github_issue_label" "partition" { repository = "terraform-provider-aws" name = "partition/${each.value}" - color = "844fba" + color = "844fba" # color:terraform (main) } diff --git a/infrastructure/repository/labels-service.tf b/infrastructure/repository/labels-service.tf index 7e91d3a12974..787d22da82f3 100644 --- a/infrastructure/repository/labels-service.tf +++ b/infrastructure/repository/labels-service.tf @@ -220,5 +220,5 @@ resource "github_issue_label" "service" { repository = "terraform-provider-aws" name = "service/${each.value}" - color = "7b42bc" + color = "7b42bc" # color:terraform (logomark) } From 970f6891fefdcd839d2faaa0c027c0256e57d6c1 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 23 Jun 2021 17:42:24 -0400 Subject: [PATCH 0732/1208] infra: Fix alpha-testing label --- infrastructure/repository/labels-workflow.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/repository/labels-workflow.tf b/infrastructure/repository/labels-workflow.tf index 9824f161d49c..59f161cd5db9 100644 --- a/infrastructure/repository/labels-workflow.tf +++ b/infrastructure/repository/labels-workflow.tf @@ -16,7 +16,7 @@ variable "workflow_labels" { "terraform-0.13" = "60dea9", # color:nomad "terraform-0.14" = "60dea9", # color:nomad "terraform-0.15" = "60dea9", # color:nomad - "alpha-testing" = "60dea9", # color:nomad + "prerelease-tf-testing" = "60dea9", # color:nomad "documentation" = "f4ecff", # color:terraform secondary "technical-debt" = "d1ebff", # color:terraform accent "proposal" = "d1ebff", # color:terraform accent From aed3725a6c67be1f9ab0cc163131f1ae155d9162 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jun 2021 06:11:29 +0000 Subject: [PATCH 0733/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.65 to 1.38.66. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.65...v1.38.66) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- .../github.com/aws/aws-sdk-go/private/protocol/rest/build.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 7b7056e0c5dd..828d2b37dd4b 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.65 + github.com/aws/aws-sdk-go v1.38.66 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 07c66db6f178..279e56f85ba6 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.65 h1:umGu5gjIOKxzhi34T0DIA1TWupUDjV2aAW5vK6154Gg= -github.com/aws/aws-sdk-go v1.38.65/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.66 h1:z1nEnVOb0ctiHURel3sFxZdXDrXnG6Fa+Dly3Kb0KVo= +github.com/aws/aws-sdk-go v1.38.66/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index f8acf1cffcb5..0b5f25f0d8b3 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.65" +const SDKVersion = "1.38.66" diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go index 1301b149d35e..fb35fee5fe73 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build.go @@ -98,7 +98,7 @@ func buildLocationElements(r *request.Request, v reflect.Value, buildGETQuery bo // Support the ability to customize values to be marshaled as a // blob even though they were modeled as a string. Required for S3 - // API operations like SSECustomerKey is modeled as stirng but + // API operations like SSECustomerKey is modeled as string but // required to be base64 encoded in request. if field.Tag.Get("marshal-as") == "blob" { m = m.Convert(byteSliceType) diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 083f0bec1577..a64052c03185 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.65 +# github.com/aws/aws-sdk-go v1.38.66 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From d4c46a87988d8a8de84b3702471ed802528a2277 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jun 2021 06:11:48 +0000 Subject: [PATCH 0734/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.65 to 1.38.66 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.65 to 1.38.66. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.65...v1.38.66) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 07a45b70b8ff..c85c5dff518a 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.65 + github.com/aws/aws-sdk-go v1.38.66 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index b5c0cbed582c..0855fca0d69b 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.65 h1:umGu5gjIOKxzhi34T0DIA1TWupUDjV2aAW5vK6154Gg= -github.com/aws/aws-sdk-go v1.38.65/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.66 h1:z1nEnVOb0ctiHURel3sFxZdXDrXnG6Fa+Dly3Kb0KVo= +github.com/aws/aws-sdk-go v1.38.66/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 7e181ed015ce247a4a36e7f28c28a7ee9f2e41fa Mon Sep 17 00:00:00 2001 From: Aidan Coyle Date: Thu, 24 Jun 2021 14:33:59 +0000 Subject: [PATCH 0735/1208] Check target blocks are not nil If nothing is specified for these blocks then they cannot be cast to `map[string]interface`. reproduction: https://github.com/packrat386/tf_sqs_issue_repro --- aws/resource_aws_cloudwatch_event_target.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index 86d18858b5bf..122ffbf7f8a7 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -494,11 +494,11 @@ func buildPutTargetInputStruct(d *schema.ResourceData) *events.PutTargetsInput { e.RoleArn = aws.String(v.(string)) } - if v, ok := d.GetOk("run_command_targets"); ok { + if v, ok := d.GetOk("run_command_targets"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { e.RunCommandParameters = expandAwsCloudWatchEventTargetRunParameters(v.([]interface{})) } - if v, ok := d.GetOk("ecs_target"); ok { + if v, ok := d.GetOk("ecs_target"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { e.EcsParameters = expandAwsCloudWatchEventTargetEcsParameters(v.([]interface{})) } @@ -506,27 +506,27 @@ func buildPutTargetInputStruct(d *schema.ResourceData) *events.PutTargetsInput { e.HttpParameters = expandAwsCloudWatchEventTargetHttpParameters(v.([]interface{})[0].(map[string]interface{})) } - if v, ok := d.GetOk("batch_target"); ok { + if v, ok := d.GetOk("batch_target"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { e.BatchParameters = expandAwsCloudWatchEventTargetBatchParameters(v.([]interface{})) } - if v, ok := d.GetOk("kinesis_target"); ok { + if v, ok := d.GetOk("kinesis_target"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { e.KinesisParameters = expandAwsCloudWatchEventTargetKinesisParameters(v.([]interface{})) } - if v, ok := d.GetOk("sqs_target"); ok { + if v, ok := d.GetOk("sqs_target"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { e.SqsParameters = expandAwsCloudWatchEventTargetSqsParameters(v.([]interface{})) } - if v, ok := d.GetOk("input_transformer"); ok { + if v, ok := d.GetOk("input_transformer"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { e.InputTransformer = expandAwsCloudWatchEventTransformerParameters(v.([]interface{})) } - if v, ok := d.GetOk("retry_policy"); ok { + if v, ok := d.GetOk("retry_policy"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { e.RetryPolicy = expandAwsCloudWatchEventRetryPolicyParameters(v.([]interface{})) } - if v, ok := d.GetOk("dead_letter_config"); ok { + if v, ok := d.GetOk("dead_letter_config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { e.DeadLetterConfig = expandAwsCloudWatchEventDeadLetterConfigParameters(v.([]interface{})) } From 7030e30d666c6e66c2ec93e19c7e5ad7d95dc53f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 24 Jun 2021 13:33:46 -0400 Subject: [PATCH 0736/1208] infrastructure: Fix github config --- infrastructure/repository/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/repository/main.tf b/infrastructure/repository/main.tf index ba3056ebd539..fa2688e230bf 100644 --- a/infrastructure/repository/main.tf +++ b/infrastructure/repository/main.tf @@ -9,7 +9,7 @@ terraform { required_providers { github = { - source = "hashicorp/github" + source = "integrations/github" version = "4.12.0" } } @@ -18,5 +18,5 @@ terraform { } provider "github" { - organization = "hashicorp" + owner = "hashicorp" } From a450d759cdcd5d8c22bb8e507eeeb45c9b373f02 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 24 Jun 2021 17:38:55 +0000 Subject: [PATCH 0737/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b11d4a27a086..3da6a820ca6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ENHANCEMENTS: * resource/aws_default_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_default_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) +* resource/aws_ecs_capacity_provider: Allow updates to the `auto_scaling_group_provider` argument without recreating the resource ([#16942](https://github.com/hashicorp/terraform-provider-aws/issues/16942)) * resource/aws_eks_cluster: Allow updates to `encryption_config` ([#19144](https://github.com/hashicorp/terraform-provider-aws/issues/19144)) * resource/aws_lb_target_group: Add support for application cookie stickiness ([#18102](https://github.com/hashicorp/terraform-provider-aws/issues/18102)) * resource/aws_main_route_table_association: Wait for association to reach the required state ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) From 4f3e6f3e0bfbd1576cb81022fdebf8a214d4c088 Mon Sep 17 00:00:00 2001 From: Tyler Lynch Date: Thu, 24 Jun 2021 13:43:58 -0400 Subject: [PATCH 0738/1208] Added AccTests for MicrosoftAD to StorageGateway --- ...esource_aws_storagegateway_gateway_test.go | 214 ++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/aws/resource_aws_storagegateway_gateway_test.go b/aws/resource_aws_storagegateway_gateway_test.go index 8673a60e86ff..fefdb6fe5442 100644 --- a/aws/resource_aws_storagegateway_gateway_test.go +++ b/aws/resource_aws_storagegateway_gateway_test.go @@ -462,6 +462,67 @@ func TestAccAWSStorageGatewayGateway_SmbActiveDirectorySettings_timeout(t *testi }) } +func TestAccAWSStorageGatewayGateway_SmbMicrosoftActiveDirectorySettings(t *testing.T) { + var gateway storagegateway.DescribeGatewayInformationOutput + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_storagegateway_gateway.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, storagegateway.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSStorageGatewayGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSStorageGatewayGatewayConfig_SmbMicrosoftActiveDirectorySettings(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSStorageGatewayGatewayExists(resourceName, &gateway), + resource.TestCheckResourceAttr(resourceName, "smb_active_directory_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "smb_active_directory_settings.0.domain_name", "terraformtesting.com"), + resource.TestCheckResourceAttr(resourceName, "smb_active_directory_settings.0.username", "Admin"), + resource.TestCheckResourceAttrSet(resourceName, "smb_active_directory_settings.0.active_directory_status"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"activation_key", "gateway_ip_address", "smb_active_directory_settings"}, + }, + }, + }) +} + +func TestAccAWSStorageGatewayGateway_SmbMicrosoftActiveDirectorySettings_timeout(t *testing.T) { + var gateway storagegateway.DescribeGatewayInformationOutput + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_storagegateway_gateway.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, storagegateway.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSStorageGatewayGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSStorageGatewayGatewayConfig_SmbMicrosoftActiveDirectorySettingsTimeout(rName, 50), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSStorageGatewayGatewayExists(resourceName, &gateway), + resource.TestCheckResourceAttr(resourceName, "smb_active_directory_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "smb_active_directory_settings.0.domain_name", "terraformtesting.com"), + resource.TestCheckResourceAttr(resourceName, "smb_active_directory_settings.0.timeout_in_seconds", "50"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"activation_key", "gateway_ip_address", "smb_active_directory_settings"}, + }, + }, + }) +} + func TestAccAWSStorageGatewayGateway_SmbGuestPassword(t *testing.T) { var gateway storagegateway.DescribeGatewayInformationOutput rName := acctest.RandomWithPrefix("tf-acc-test") @@ -1105,6 +1166,120 @@ resource "aws_instance" "test" { `, rName)) } +func testAccAWSStorageGatewayGatewayConfigSmbMicrosoftActiveDirectorySettingsBase(rName string) string { + return composeConfig( + // Reference: https://docs.aws.amazon.com/storagegateway/latest/userguide/Requirements.html + testAccAvailableEc2InstanceTypeForAvailabilityZone("aws_subnet.test[0].availability_zone", "m5.xlarge", "m4.xlarge"), + testAccAvailableAZsNoOptInConfig(), + fmt.Sprintf(` +# Directory Service Directories must be deployed across multiple EC2 Availability Zones +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test" { + count = 2 + + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = "10.0.${count.index}.0/24" + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_internet_gateway" "test" { + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_route" "test" { + destination_cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.test.id + route_table_id = aws_vpc.test.main_route_table_id +} + +resource "aws_security_group" "test" { + vpc_id = aws_vpc.test.id + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = %[1]q + } +} + +resource "aws_directory_service_directory" "test" { + edition = "Standard" + name = "terraformtesting.com" + password = "SuperSecretPassw0rd" + type = "MicrosoftAD" + + vpc_settings { + subnet_ids = aws_subnet.test[*].id + vpc_id = aws_vpc.test.id + } + + tags = { + Name = %[1]q + } +} + +resource "aws_vpc_dhcp_options" "test" { + domain_name = aws_directory_service_directory.test.name + domain_name_servers = aws_directory_service_directory.test.dns_ip_addresses + + tags = { + Name = %[1]q + } +} + +resource "aws_vpc_dhcp_options_association" "test" { + dhcp_options_id = aws_vpc_dhcp_options.test.id + vpc_id = aws_vpc.test.id +} + +# Reference: https://docs.aws.amazon.com/storagegateway/latest/userguide/ec2-gateway-file.html +data "aws_ssm_parameter" "aws_service_storagegateway_ami_FILE_S3_latest" { + name = "/aws/service/storagegateway/ami/FILE_S3/latest" +} + +resource "aws_instance" "test" { + depends_on = [aws_route.test, aws_vpc_dhcp_options_association.test] + + ami = data.aws_ssm_parameter.aws_service_storagegateway_ami_FILE_S3_latest.value + associate_public_ip_address = true + instance_type = data.aws_ec2_instance_type_offering.available.instance_type + vpc_security_group_ids = [aws_security_group.test.id] + subnet_id = aws_subnet.test[0].id + + tags = { + Name = %[1]q + } +} +`, rName)) +} + func testAccAWSStorageGatewayGatewayConfig_SmbActiveDirectorySettings(rName string) string { return composeConfig( testAccAWSStorageGatewayGatewayConfigSmbActiveDirectorySettingsBase(rName), @@ -1144,6 +1319,45 @@ resource "aws_storagegateway_gateway" "test" { `, rName, timeout)) } +func testAccAWSStorageGatewayGatewayConfig_SmbMicrosoftActiveDirectorySettings(rName string) string { + return composeConfig( + testAccAWSStorageGatewayGatewayConfigSmbMicrosoftActiveDirectorySettingsBase(rName), + fmt.Sprintf(` +resource "aws_storagegateway_gateway" "test" { + gateway_ip_address = aws_instance.test.public_ip + gateway_name = %[1]q + gateway_timezone = "GMT" + gateway_type = "FILE_S3" + + smb_active_directory_settings { + domain_name = aws_directory_service_directory.test.name + password = aws_directory_service_directory.test.password + username = "Admin" + } +} +`, rName)) +} + +func testAccAWSStorageGatewayGatewayConfig_SmbMicrosoftActiveDirectorySettingsTimeout(rName string, timeout int) string { + return composeConfig( + testAccAWSStorageGatewayGatewayConfigSmbMicrosoftActiveDirectorySettingsBase(rName), + fmt.Sprintf(` +resource "aws_storagegateway_gateway" "test" { + gateway_ip_address = aws_instance.test.public_ip + gateway_name = %[1]q + gateway_timezone = "GMT" + gateway_type = "FILE_S3" + + smb_active_directory_settings { + domain_name = aws_directory_service_directory.test.name + password = aws_directory_service_directory.test.password + username = "Admin" + timeout_in_seconds = %[2]d + } +} +`, rName, timeout)) +} + func testAccAWSStorageGatewayGatewayConfig_SmbGuestPassword(rName, smbGuestPassword string) string { return testAccAWSStorageGateway_FileGatewayBase(rName) + fmt.Sprintf(` resource "aws_storagegateway_gateway" "test" { From 10dc6f523542b51f698ba50a2af6581b2316f39e Mon Sep 17 00:00:00 2001 From: Farhan Angullia Date: Fri, 25 Jun 2021 02:46:42 +0800 Subject: [PATCH 0739/1208] feat(s3logs): added support for datasources and added acc tests --- aws/resource_aws_guardduty_detector.go | 94 ++++++++++++++++++++- aws/resource_aws_guardduty_detector_test.go | 48 +++++++++++ aws/resource_aws_guardduty_test.go | 9 +- 3 files changed, 146 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_guardduty_detector.go b/aws/resource_aws_guardduty_detector.go index f3cd98b16bd6..cf9b6bd6da4c 100644 --- a/aws/resource_aws_guardduty_detector.go +++ b/aws/resource_aws_guardduty_detector.go @@ -45,6 +45,32 @@ func resourceAwsGuardDutyDetector() *schema.Resource { Optional: true, Computed: true, }, + + "datasources": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "s3_logs": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable": { + Type: schema.TypeBool, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), @@ -67,6 +93,10 @@ func resourceAwsGuardDutyDetectorCreate(d *schema.ResourceData, meta interface{} input.FindingPublishingFrequency = aws.String(v.(string)) } + if v, ok := d.GetOk("datasources"); ok { + input.DataSources = expandDataSourceConfigurations(v.([]interface{})) + } + if len(tags) > 0 { input.Tags = tags.IgnoreAws().GuarddutyTags() } @@ -114,6 +144,10 @@ func resourceAwsGuardDutyDetectorRead(d *schema.ResourceData, meta interface{}) d.Set("enable", *gdo.Status == guardduty.DetectorStatusEnabled) d.Set("finding_publishing_frequency", gdo.FindingPublishingFrequency) + if err := d.Set("datasources", flattenDataSourceConfigurations(gdo.DataSources)); err != nil { + return fmt.Errorf("error setting datasources: %s", err) + } + tags := keyvaluetags.GuarddutyKeyValueTags(gdo.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 @@ -131,13 +165,17 @@ func resourceAwsGuardDutyDetectorRead(d *schema.ResourceData, meta interface{}) func resourceAwsGuardDutyDetectorUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).guarddutyconn - if d.HasChanges("enable", "finding_publishing_frequency") { + if d.HasChanges("enable", "finding_publishing_frequency", "datasources") { input := guardduty.UpdateDetectorInput{ DetectorId: aws.String(d.Id()), Enable: aws.Bool(d.Get("enable").(bool)), FindingPublishingFrequency: aws.String(d.Get("finding_publishing_frequency").(string)), } + if d.HasChange("datasources") { + input.DataSources = expandDataSourceConfigurations(d.Get("datasources").([]interface{})) + } + log.Printf("[DEBUG] Update GuardDuty Detector: %s", input) _, err := conn.UpdateDetector(&input) if err != nil { @@ -187,3 +225,57 @@ func resourceAwsGuardDutyDetectorDelete(d *schema.ResourceData, meta interface{} return nil } + +func expandDataSourceConfigurations(dsc []interface{}) *guardduty.DataSourceConfigurations { + if len(dsc) < 1 || dsc[0] == nil { + return nil + } + + m := dsc[0].(map[string]interface{}) + + dataSourceConfigurations := &guardduty.DataSourceConfigurations{} + + if v, ok := m["s3_logs"]; ok && v != "" && (len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil) { + dataSourceConfigurations.S3Logs = expandS3LogsConfiguration(v.([]interface{})) + } + + return dataSourceConfigurations +} + +func expandS3LogsConfiguration(slc []interface{}) *guardduty.S3LogsConfiguration { + if len(slc) < 1 || slc[0] == nil { + return nil + } + + m := slc[0].(map[string]interface{}) + + s3LogsConfiguration := &guardduty.S3LogsConfiguration{ + Enable: aws.Bool(m["enable"].(bool)), + } + + return s3LogsConfiguration +} + +func flattenDataSourceConfigurations(dsc *guardduty.DataSourceConfigurationsResult) []interface{} { + if dsc == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "s3_logs": flattenS3LogsConfiguration(dsc.S3Logs), + } + + return []interface{}{m} +} + +func flattenS3LogsConfiguration(slc *guardduty.S3LogsConfigurationResult) []interface{} { + if slc == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "enable": aws.StringValue(slc.Status) == guardduty.DataSourceStatusEnabled, + } + + return []interface{}{m} +} diff --git a/aws/resource_aws_guardduty_detector_test.go b/aws/resource_aws_guardduty_detector_test.go index cdb389191266..d51c794d26b7 100644 --- a/aws/resource_aws_guardduty_detector_test.go +++ b/aws/resource_aws_guardduty_detector_test.go @@ -160,6 +160,42 @@ func testAccAwsGuardDutyDetector_tags(t *testing.T) { }) } +func testAccAwsGuardDutyDetector_datasources_s3logs(t *testing.T) { + resourceName := "aws_guardduty_detector.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, guardduty.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsGuardDutyDetectorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccGuardDutyDetectorConfigDatasourcesS3Logs(true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsGuardDutyDetectorExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "datasources.#", "1"), + resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.0.enable", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccGuardDutyDetectorConfigDatasourcesS3Logs(false), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsGuardDutyDetectorExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "datasources.#", "1"), + resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.0.enable", "false"), + ), + }, + }, + }) +} + func testAccCheckAwsGuardDutyDetectorDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).guarddutyconn @@ -239,3 +275,15 @@ resource "aws_guardduty_detector" "test" { } `, tagKey1, tagValue1, tagKey2, tagValue2) } + +func testAccGuardDutyDetectorConfigDatasourcesS3Logs(enable bool) string { + return fmt.Sprintf(` +resource "aws_guardduty_detector" "test" { + datasources { + s3_logs { + enable = %[1]t + } + } +} +`, enable) +} diff --git a/aws/resource_aws_guardduty_test.go b/aws/resource_aws_guardduty_test.go index 596655cb7aaf..9d09d258a174 100644 --- a/aws/resource_aws_guardduty_test.go +++ b/aws/resource_aws_guardduty_test.go @@ -8,10 +8,11 @@ import ( func TestAccAWSGuardDuty_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "Detector": { - "basic": testAccAwsGuardDutyDetector_basic, - "tags": testAccAwsGuardDutyDetector_tags, - "datasource_basic": testAccAWSGuarddutyDetectorDataSource_basic, - "datasource_id": testAccAWSGuarddutyDetectorDataSource_Id, + "basic": testAccAwsGuardDutyDetector_basic, + "datasources_s3logs": testAccAwsGuardDutyDetector_datasources_s3logs, + "tags": testAccAwsGuardDutyDetector_tags, + "datasource_basic": testAccAWSGuarddutyDetectorDataSource_basic, + "datasource_id": testAccAWSGuarddutyDetectorDataSource_Id, }, "Filter": { "basic": testAccAwsGuardDutyFilter_basic, From dd37fee59f777450a7a5c77c02d8512f230ac362 Mon Sep 17 00:00:00 2001 From: Farhan Angullia Date: Fri, 25 Jun 2021 02:47:47 +0800 Subject: [PATCH 0740/1208] docs: updated site for new args --- .../docs/r/guardduty_detector.html.markdown | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/website/docs/r/guardduty_detector.html.markdown b/website/docs/r/guardduty_detector.html.markdown index 8431be3e1b28..f9d5cf5f5bf4 100644 --- a/website/docs/r/guardduty_detector.html.markdown +++ b/website/docs/r/guardduty_detector.html.markdown @@ -17,6 +17,12 @@ Provides a resource to manage a GuardDuty detector. ```terraform resource "aws_guardduty_detector" "MyDetector" { enable = true + + datasources { + s3_logs { + enable = true + } + } } ``` @@ -26,8 +32,21 @@ The following arguments are supported: * `enable` - (Optional) Enable monitoring and feedback reporting. Setting to `false` is equivalent to "suspending" GuardDuty. Defaults to `true`. * `finding_publishing_frequency` - (Optional) Specifies the frequency of notifications sent for subsequent finding occurrences. If the detector is a GuardDuty member account, the value is determined by the GuardDuty primary account and cannot be modified, otherwise defaults to `SIX_HOURS`. For standalone and GuardDuty primary accounts, it must be configured in Terraform to enable drift detection. Valid values for standalone and primary accounts: `FIFTEEN_MINUTES`, `ONE_HOUR`, `SIX_HOURS`. See [AWS Documentation](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_findings_cloudwatch.html#guardduty_findings_cloudwatch_notification_frequency) for more information. +* `datasources` - (Optional) Describes which data sources will be enabled for the detector. See [Data Sources](#data-sources) below for more details. * `tags` - (Optional) Key-value map of resource tags. 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. +### Data Sources + +The `datasources` block supports the following: + +* `s3_logs` - (Optional) Describes whether S3 data event logs are enabled as a data source. See [S3 Logs](#s3-logs) below for more details. + +### S3 Logs + +This `s3_logs` block supports the following: + +* `enable` - (Required) If true, enables [S3 Protection](https://docs.aws.amazon.com/guardduty/latest/ug/s3_detection.html). Defaults to `true`. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From d86a2461ca8ce827229132a9bea81f57662e01e7 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 23 Jun 2021 15:52:28 -0400 Subject: [PATCH 0741/1208] caller_identity: Add source role --- aws/data_source_aws_caller_identity.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/aws/data_source_aws_caller_identity.go b/aws/data_source_aws_caller_identity.go index 04b0b8c52d33..8233b42927d8 100644 --- a/aws/data_source_aws_caller_identity.go +++ b/aws/data_source_aws_caller_identity.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/sts" @@ -24,6 +25,11 @@ func dataSourceAwsCallerIdentity() *schema.Resource { Computed: true, }, + "source_arn": { + Type: schema.TypeString, + Computed: true, + }, + "user_id": { Type: schema.TypeString, Computed: true, @@ -49,5 +55,13 @@ func dataSourceAwsCallerIdentityRead(d *schema.ResourceData, meta interface{}) e d.Set("arn", res.Arn) d.Set("user_id", res.UserId) + sourceARN := aws.StringValue(res.Arn) + + if strings.Contains(aws.StringValue(res.Arn), "assumed-role") { + sourceARN := strings.Replace(sourceARN, "assumed-role", "role", 1) + } + + d.Set("source_arn", sourceARN) + return nil } From c7133ae6ce4a37fe4300cbe48ab63f63126212ff Mon Sep 17 00:00:00 2001 From: Farhan Angullia Date: Fri, 25 Jun 2021 03:26:47 +0800 Subject: [PATCH 0742/1208] fix terrafmt for acc tests --- aws/resource_aws_guardduty_detector_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_guardduty_detector_test.go b/aws/resource_aws_guardduty_detector_test.go index d51c794d26b7..4a3fc48a6505 100644 --- a/aws/resource_aws_guardduty_detector_test.go +++ b/aws/resource_aws_guardduty_detector_test.go @@ -279,11 +279,11 @@ resource "aws_guardduty_detector" "test" { func testAccGuardDutyDetectorConfigDatasourcesS3Logs(enable bool) string { return fmt.Sprintf(` resource "aws_guardduty_detector" "test" { - datasources { - s3_logs { - enable = %[1]t - } - } + datasources { + s3_logs { + enable = %[1]t + } + } } `, enable) } From 39273611e725782d1cfcd70576540ad695bb3b60 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Thu, 24 Jun 2021 12:36:03 -0700 Subject: [PATCH 0743/1208] Fix crash in lb_target_group data source. --- aws/data_source_aws_lb_target_group.go | 4 + aws/data_source_aws_lb_target_group_test.go | 160 +++++++++++++++++++ aws/resource_aws_lb_target_group.go | 77 +++------ aws/resource_aws_lb_target_group_test.go | 16 +- website/docs/r/lb_target_group.html.markdown | 7 +- 5 files changed, 197 insertions(+), 67 deletions(-) diff --git a/aws/data_source_aws_lb_target_group.go b/aws/data_source_aws_lb_target_group.go index ae8a01cd2376..1f19006f5541 100644 --- a/aws/data_source_aws_lb_target_group.go +++ b/aws/data_source_aws_lb_target_group.go @@ -117,6 +117,10 @@ func dataSourceAwsLbTargetGroup() *schema.Resource { Type: schema.TypeInt, Computed: true, }, + "cookie_name": { + Type: schema.TypeString, + Computed: true, + }, "enabled": { Type: schema.TypeBool, Computed: true, diff --git a/aws/data_source_aws_lb_target_group_test.go b/aws/data_source_aws_lb_target_group_test.go index 09300bb7c230..df9a5dc1585d 100644 --- a/aws/data_source_aws_lb_target_group_test.go +++ b/aws/data_source_aws_lb_target_group_test.go @@ -70,6 +70,47 @@ func TestAccDataSourceAWSLBTargetGroup_basic(t *testing.T) { }) } +func TestAccDataSourceAWSLBTargetGroup_appCookie(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceNameArn := "data.aws_lb_target_group.alb_tg_test_with_arn" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, elbv2.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAWSLBTargetGroupConfigAppCookie(rName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceNameArn, "name", rName), + resource.TestCheckResourceAttrSet(resourceNameArn, "arn"), + resource.TestCheckResourceAttrSet(resourceNameArn, "arn_suffix"), + resource.TestCheckResourceAttr(resourceNameArn, "port", "8080"), + resource.TestCheckResourceAttr(resourceNameArn, "protocol", "HTTP"), + resource.TestCheckResourceAttr(resourceNameArn, "protocol_version", "HTTP1"), + resource.TestCheckResourceAttrSet(resourceNameArn, "vpc_id"), + resource.TestCheckResourceAttrSet(resourceNameArn, "load_balancing_algorithm_type"), + resource.TestCheckResourceAttr(resourceNameArn, "deregistration_delay", "300"), + resource.TestCheckResourceAttr(resourceNameArn, "slow_start", "0"), + resource.TestCheckResourceAttr(resourceNameArn, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceNameArn, "tags.TestName", rName), + resource.TestCheckResourceAttr(resourceNameArn, "stickiness.#", "1"), + resource.TestCheckResourceAttr(resourceNameArn, "stickiness.0.cookie_duration", "600"), + resource.TestCheckResourceAttr(resourceNameArn, "stickiness.0.cookie_name", "cookieName"), + resource.TestCheckResourceAttr(resourceNameArn, "health_check.#", "1"), + resource.TestCheckResourceAttr(resourceNameArn, "health_check.0.path", "/health"), + resource.TestCheckResourceAttr(resourceNameArn, "health_check.0.port", "8081"), + resource.TestCheckResourceAttr(resourceNameArn, "health_check.0.protocol", "HTTP"), + resource.TestCheckResourceAttr(resourceNameArn, "health_check.0.timeout", "3"), + resource.TestCheckResourceAttr(resourceNameArn, "health_check.0.healthy_threshold", "3"), + resource.TestCheckResourceAttr(resourceNameArn, "health_check.0.unhealthy_threshold", "3"), + resource.TestCheckResourceAttr(resourceNameArn, "health_check.0.matcher", "200-299"), + ), + }, + }, + }) +} + func TestAccDataSourceAWSLBTargetGroup_BackwardsCompatibility(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceNameArn := "data.aws_alb_target_group.alb_tg_test_with_arn" @@ -246,6 +287,125 @@ data "aws_lb_target_group" "alb_tg_test_with_name" { `, rName) } +func testAccDataSourceAWSLBTargetGroupConfigAppCookie(rName string) string { + return fmt.Sprintf(` +resource "aws_lb_listener" "front_end" { + load_balancer_arn = aws_lb.alb_test.id + protocol = "HTTP" + port = "80" + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } +} + +resource "aws_lb" "alb_test" { + name = %[1]q + internal = true + security_groups = [aws_security_group.alb_test.id] + subnets = aws_subnet.alb_test[*].id + + idle_timeout = 30 + enable_deletion_protection = false + + tags = { + TestName = %[1]q + } +} + +resource "aws_lb_target_group" "test" { + name = %[1]q + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.alb_test.id + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } + + stickiness { + type = "app_cookie" + cookie_name = "cookieName" + cookie_duration = 600 + } + + tags = { + TestName = %[1]q + } +} + +variable "subnets" { + default = ["10.0.1.0/24", "10.0.2.0/24"] + type = list(string) +} + +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +resource "aws_vpc" "alb_test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "alb_test" { + count = 2 + vpc_id = aws_vpc.alb_test.id + cidr_block = element(var.subnets, count.index) + map_public_ip_on_launch = true + availability_zone = element(data.aws_availability_zones.available.names, count.index) + + tags = { + Name = %[1]q + } +} + +resource "aws_security_group" "alb_test" { + name = "allow_all_alb_test" + description = "Used for ALB Testing" + vpc_id = aws_vpc.alb_test.id + + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + TestName = %[1]q + } +} + +data "aws_lb_target_group" "alb_tg_test_with_arn" { + arn = aws_lb_target_group.test.arn +} +`, rName) +} + func testAccDataSourceAWSLBTargetGroupConfigBackwardsCompatibility(rName string) string { return fmt.Sprintf(` resource "aws_alb_listener" "front_end" { diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index cd7bc2878f98..23a5f91b252c 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -216,33 +216,6 @@ func resourceAwsLbTargetGroup() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "app_cookie": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, - DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - switch d.Get("protocol").(string) { - case elbv2.ProtocolEnumTcp, elbv2.ProtocolEnumUdp, elbv2.ProtocolEnumTcpUdp, elbv2.ProtocolEnumTls: - return true - } - return false - }, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cookie_name": { - Type: schema.TypeString, - Required: true, - }, - "duration_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: 86400, - ValidateFunc: validation.IntBetween(0, 604800), - }, - }, - }, - }, "cookie_duration": { Type: schema.TypeInt, Optional: true, @@ -256,6 +229,10 @@ func resourceAwsLbTargetGroup() *schema.Resource { return false }, }, + "cookie_name": { + Type: schema.TypeString, + Optional: true, + }, "enabled": { Type: schema.TypeBool, Optional: true, @@ -589,19 +566,15 @@ func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) er Value: aws.String(fmt.Sprintf("%d", stickiness["cookie_duration"].(int))), }) case "app_cookie": - appCookieBlocks := stickiness["app_cookie"].([]interface{}) - if len(appCookieBlocks) == 1 { - appStickiness := appCookieBlocks[0].(map[string]interface{}) - attrs = append(attrs, - &elbv2.TargetGroupAttribute{ - Key: aws.String("stickiness.app_cookie.duration_seconds"), - Value: aws.String(fmt.Sprintf("%d", appStickiness["duration_seconds"].(int))), - }, - &elbv2.TargetGroupAttribute{ - Key: aws.String("stickiness.app_cookie.cookie_name"), - Value: aws.String(appStickiness["cookie_name"].(string)), - }) - } + attrs = append(attrs, + &elbv2.TargetGroupAttribute{ + Key: aws.String("stickiness.app_cookie.duration_seconds"), + Value: aws.String(fmt.Sprintf("%d", stickiness["cookie_duration"].(int))), + }, + &elbv2.TargetGroupAttribute{ + Key: aws.String("stickiness.app_cookie.cookie_name"), + Value: aws.String(stickiness["cookie_name"].(string)), + }) default: log.Printf("[WARN] Unexpected stickiness type. Expected lb_cookie or app_cookie, got %s", stickiness["type"].(string)) } @@ -838,7 +811,6 @@ func flattenAwsLbTargetGroupResource(d *schema.ResourceData, meta interface{}, t } func flattenAwsLbTargetGroupStickiness(attributes []*elbv2.TargetGroupAttribute) ([]interface{}, error) { - appStickinessMap := map[string]interface{}{} if len(attributes) == 0 { return []interface{}{}, nil } @@ -856,22 +828,25 @@ func flattenAwsLbTargetGroupStickiness(attributes []*elbv2.TargetGroupAttribute) case "stickiness.type": m["type"] = aws.StringValue(attr.Value) case "stickiness.lb_cookie.duration_seconds": - duration, err := strconv.Atoi(aws.StringValue(attr.Value)) - if err != nil { - return nil, fmt.Errorf("error converting stickiness.lb_cookie.duration_seconds to int: %s", aws.StringValue(attr.Value)) + if sType, ok := m["type"].(string); !ok || sType == "lb_cookie" { + duration, err := strconv.Atoi(aws.StringValue(attr.Value)) + if err != nil { + return nil, fmt.Errorf("error converting stickiness.lb_cookie.duration_seconds to int: %s", aws.StringValue(attr.Value)) + } + m["cookie_duration"] = duration } - m["cookie_duration"] = duration case "stickiness.app_cookie.cookie_name": - appStickinessMap["cookie_name"] = aws.StringValue(attr.Value) + m["cookie_name"] = aws.StringValue(attr.Value) case "stickiness.app_cookie.duration_seconds": - duration, err := strconv.Atoi(aws.StringValue(attr.Value)) - if err != nil { - return nil, fmt.Errorf("Error converting stickiness.app_cookie.duration_seconds to int: %s", aws.StringValue(attr.Value)) + if sType, ok := m["type"].(string); !ok || sType == "app_cookie" { + duration, err := strconv.Atoi(aws.StringValue(attr.Value)) + if err != nil { + return nil, fmt.Errorf("Error converting stickiness.app_cookie.duration_seconds to int: %s", aws.StringValue(attr.Value)) + } + m["cookie_duration"] = duration } - appStickinessMap["duration_seconds"] = duration } } - m["app_cookie"] = []interface{}{appStickinessMap} return []interface{}{m}, nil } diff --git a/aws/resource_aws_lb_target_group_test.go b/aws/resource_aws_lb_target_group_test.go index b1cb70349383..2c4345c1f8f6 100644 --- a/aws/resource_aws_lb_target_group_test.go +++ b/aws/resource_aws_lb_target_group_test.go @@ -1013,9 +1013,8 @@ func TestAccAWSLBTargetGroup_updateAppSticknessEnabled(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stickiness.#", "1"), resource.TestCheckResourceAttr(resourceName, "stickiness.0.enabled", "true"), resource.TestCheckResourceAttr(resourceName, "stickiness.0.type", "app_cookie"), - resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.#", "1"), - resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.0.cookie_name", "Cookie"), - resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.0.duration_seconds", "10000"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.cookie_name", "Cookie"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.cookie_duration", "10000"), resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), resource.TestCheckResourceAttr(resourceName, "health_check.0.path", "/health2"), resource.TestCheckResourceAttr(resourceName, "health_check.0.interval", "30"), @@ -1040,9 +1039,8 @@ func TestAccAWSLBTargetGroup_updateAppSticknessEnabled(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "stickiness.#", "1"), resource.TestCheckResourceAttr(resourceName, "stickiness.0.enabled", "false"), resource.TestCheckResourceAttr(resourceName, "stickiness.0.type", "app_cookie"), - resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.#", "1"), - resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.0.cookie_name", "Cookie"), - resource.TestCheckResourceAttr(resourceName, "stickiness.0.app_cookie.0.duration_seconds", "10000"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.cookie_name", "Cookie"), + resource.TestCheckResourceAttr(resourceName, "stickiness.0.cookie_duration", "10000"), resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), resource.TestCheckResourceAttr(resourceName, "health_check.0.path", "/health2"), resource.TestCheckResourceAttr(resourceName, "health_check.0.interval", "30"), @@ -2350,10 +2348,8 @@ func testAccAWSLBTargetGroupConfig_appStickiness(targetGroupName string, addAppS stickiness { enabled = "%[1]t" type = "app_cookie" - app_cookie { - cookie_name = "Cookie" - duration_seconds = 10000 - } + cookie_name = "Cookie" + cookie_duration = 10000 } `, enabled) } diff --git a/website/docs/r/lb_target_group.html.markdown b/website/docs/r/lb_target_group.html.markdown index 41043b979771..1f794451f914 100644 --- a/website/docs/r/lb_target_group.html.markdown +++ b/website/docs/r/lb_target_group.html.markdown @@ -94,14 +94,9 @@ The following arguments are supported: ~> **NOTE:** Currently, an NLB (i.e., protocol of `HTTP` or `HTTPS`) can have an invalid `stickiness` block with `type` set to `lb_cookie` as long as `enabled` is set to `false`. However, please update your configurations to avoid errors in a future version of the provider: either remove the invalid `stickiness` block or set the `type` to `source_ip`. * `cookie_duration` - (Optional) Only used when the type is `lb_cookie`. The time period, in seconds, during which requests from a client should be routed to the same target. After this time period expires, the load balancer-generated cookie is considered stale. The range is 1 second to 1 week (604800 seconds). The default value is 1 day (86400 seconds). +* `cookie_name` - (Optional) Name of the application based cookie. AWSALB, AWSALBAPP, and AWSALBTG prefixes are reserved and cannot be used. Only needed when type is `app_cookie`. * `enabled` - (Optional) Boolean to enable / disable `stickiness`. Default is `true`. * `type` - (Required) The type of sticky sessions. The only current possible values are `lb_cookie`, `app_cookie` for ALBs, and `source_ip` for NLBs. -* `app_cookie` - (Option) An Application Cookie block. Application Cookie blocks are documented below. - -#### app_cookie - -* `cookie_name` - (Required) Name of the application based cookie. AWSALB, AWSALBAPP, and AWSALBTG prefixes are reserved and cannot be used. -* `duration_seconds` - (Optional) The time period, in seconds, during which requests from a client should be routed to the same target. The range is 1 to 604800 seconds. The default value is 86400. ## Attributes Reference From ebb868c8cb5363a616664be0cf1464223d342e67 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Thu, 24 Jun 2021 12:44:54 -0700 Subject: [PATCH 0744/1208] Add changelog entry --- .changelog/19955.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19955.txt diff --git a/.changelog/19955.txt b/.changelog/19955.txt new file mode 100644 index 000000000000..9b6f5b1e8fa8 --- /dev/null +++ b/.changelog/19955.txt @@ -0,0 +1,3 @@ +```release-note:bug +data-source/aws_lb_target_group: Add cookie_name attribute for app_cookie support +``` From da8c58266310b0bf8757570f60e92c4b0b04a9fc Mon Sep 17 00:00:00 2001 From: bill-rich Date: Thu, 24 Jun 2021 12:54:37 -0700 Subject: [PATCH 0745/1208] Fix formatting --- aws/data_source_aws_lb_target_group_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/data_source_aws_lb_target_group_test.go b/aws/data_source_aws_lb_target_group_test.go index df9a5dc1585d..8c1eeabd0c38 100644 --- a/aws/data_source_aws_lb_target_group_test.go +++ b/aws/data_source_aws_lb_target_group_test.go @@ -331,11 +331,11 @@ resource "aws_lb_target_group" "test" { matcher = "200-299" } - stickiness { - type = "app_cookie" - cookie_name = "cookieName" - cookie_duration = 600 - } + stickiness { + type = "app_cookie" + cookie_name = "cookieName" + cookie_duration = 600 + } tags = { TestName = %[1]q From b81de6a5ac35abc6a98a6b2d9112dfb0f2816b65 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 24 Jun 2021 16:58:21 -0400 Subject: [PATCH 0746/1208] d/caller_identity: Add source_arn --- aws/data_source_aws_caller_identity.go | 40 +++++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/aws/data_source_aws_caller_identity.go b/aws/data_source_aws_caller_identity.go index 8233b42927d8..a03fa6382917 100644 --- a/aws/data_source_aws_caller_identity.go +++ b/aws/data_source_aws_caller_identity.go @@ -3,9 +3,11 @@ package aws import ( "fmt" "log" + "regexp" "strings" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/sts" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -45,7 +47,7 @@ func dataSourceAwsCallerIdentityRead(d *schema.ResourceData, meta interface{}) e res, err := client.GetCallerIdentity(&sts.GetCallerIdentityInput{}) if err != nil { - return fmt.Errorf("Error getting Caller Identity: %w", err) + return fmt.Errorf("getting Caller Identity: %w", err) } log.Printf("[DEBUG] Received Caller Identity: %s", res) @@ -54,14 +56,38 @@ func dataSourceAwsCallerIdentityRead(d *schema.ResourceData, meta interface{}) e d.Set("account_id", res.Account) d.Set("arn", res.Arn) d.Set("user_id", res.UserId) + d.Set("source_arn", sourceARN(aws.StringValue(res.Arn))) - sourceARN := aws.StringValue(res.Arn) + return nil +} - if strings.Contains(aws.StringValue(res.Arn), "assumed-role") { - sourceARN := strings.Replace(sourceARN, "assumed-role", "role", 1) - } +// sourceARN returns the same string passed in unless it appears to be an assumed role ARN. +// In that case, it attempts to return the source role ARN associated with an assumed role ARN. +func sourceARN(rawARN string) string { + result := rawARN - d.Set("source_arn", sourceARN) + if strings.Contains(result, ":assumed-role/") && strings.Contains(result, ":sts:") { + parsedARN, err := arn.Parse(result) - return nil + if err != nil { + return result + } + + if parsedARN.Service != "sts" { + // not an assumed role + return result + } + + re := regexp.MustCompile(`^assumed-role/`) + parsedARN.Resource = re.ReplaceAllString(parsedARN.Resource, "role/") + parsedARN.Service = "iam" + + if v := strings.LastIndex(parsedARN.Resource, "/"); v > 0 { + parsedARN.Resource = parsedARN.Resource[0:v] + } + + result = parsedARN.String() + } + + return result } From 11d04ceb643920e95317a4ec870581757452f733 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 24 Jun 2021 16:58:51 -0400 Subject: [PATCH 0747/1208] tests/d/caller_identity: Unit test source_arn --- aws/data_source_aws_caller_identity_test.go | 59 +++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/aws/data_source_aws_caller_identity_test.go b/aws/data_source_aws_caller_identity_test.go index e73435d0ba1a..544879007c82 100644 --- a/aws/data_source_aws_caller_identity_test.go +++ b/aws/data_source_aws_caller_identity_test.go @@ -9,6 +9,65 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) +func TestSourceARN(t *testing.T) { + testCases := []struct { + Name string + ARN string + Expected string + }{ + { + Name: "not an ARN", + ARN: "abcd", + Expected: "abcd", + }, + { + Name: "regular ARN", + ARN: "arn:aws:iam::111122223333:role/role_name", + Expected: "arn:aws:iam::111122223333:role/role_name", + }, + { + Name: "assumed role ARN", + ARN: "arn:aws:sts::444433332222:assumed-role/something_something-admin/sessionIDNotPartOfRoleARN", + Expected: "arn:aws:iam::444433332222:role/something_something-admin", + }, + { + Name: "'assumed-role' part of ARN resource", + ARN: "arn:aws:iam::444433332222:user/assumed-role-but-not-really", + Expected: "arn:aws:iam::444433332222:user/assumed-role-but-not-really", + }, + { + Name: "user ARN", + ARN: "arn:aws:iam::123456789012:user/Bob", + Expected: "arn:aws:iam::123456789012:user/Bob", + }, + { + Name: "assumed role from AWS example", + ARN: "arn:aws:sts::123456789012:assumed-role/example-role/AWSCLI-Session", + Expected: "arn:aws:iam::123456789012:role/example-role", + }, + { + Name: "multiple slashes in resource", // not sure this is even valid + ARN: "arn:aws:sts::123456789012:assumed-role/example-role/also-part-of-role-or-no/AWSCLI-Session", + Expected: "arn:aws:iam::123456789012:role/example-role/also-part-of-role-or-no", + }, + { + Name: "not an sts ARN", + ARN: "arn:aws:iam::123456789012:assumed-role/example-role/AWSCLI-Session", + Expected: "arn:aws:iam::123456789012:assumed-role/example-role/AWSCLI-Session", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + got := sourceARN(testCase.ARN) + + if got != testCase.Expected { + t.Errorf("for %s: got %s, expected %s", testCase.Name, got, testCase.Expected) + } + }) + } +} + func TestAccAWSCallerIdentity_basic(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, From c659b64e1216a4d58ddddfd478f7fea004dd8685 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 24 Jun 2021 16:59:14 -0400 Subject: [PATCH 0748/1208] docs/d/caller_identity: Docs for source_arn --- website/docs/d/caller_identity.html.markdown | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/website/docs/d/caller_identity.html.markdown b/website/docs/d/caller_identity.html.markdown index d349ef137ef2..bb9bfcae5521 100644 --- a/website/docs/d/caller_identity.html.markdown +++ b/website/docs/d/caller_identity.html.markdown @@ -36,7 +36,8 @@ There are no arguments available for this data source. ## Attributes Reference -* `account_id` - The AWS Account ID number of the account that owns or contains the calling entity. -* `arn` - The AWS ARN associated with the calling entity. -* `id` - The AWS Account ID number of the account that owns or contains the calling entity. -* `user_id` - The unique identifier of the calling entity. +* `account_id` - AWS Account ID number of the account that owns or contains the calling entity. +* `arn` - ARN associated with the calling entity. +* `id` - Account ID number of the account that owns or contains the calling entity. +* `source_arn` - Same as `arn` unless `arn` is an assumed role ARN, in which case, `source_arn` is the ARN of source role of the assumed role. +* `user_id` - Unique identifier of the calling entity. From 144947c75c0a8ee79f11911f1454c79ff5a4bd51 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Thu, 24 Jun 2021 14:01:11 -0700 Subject: [PATCH 0749/1208] Fix changelog entry --- .changelog/18102.txt | 2 +- .changelog/19955.txt | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 .changelog/19955.txt diff --git a/.changelog/18102.txt b/.changelog/18102.txt index 69b792573c66..5f780f28d12b 100644 --- a/.changelog/18102.txt +++ b/.changelog/18102.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_lb_target_group: Add support for application cookie stickiness +resource/aws_lb_target_group: Add support for `app_cookie` stickiness type and `cookie_name` argument ``` diff --git a/.changelog/19955.txt b/.changelog/19955.txt deleted file mode 100644 index 9b6f5b1e8fa8..000000000000 --- a/.changelog/19955.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:bug -data-source/aws_lb_target_group: Add cookie_name attribute for app_cookie support -``` From 62d7c93d084b19a45b9c1658f5eed457530c331c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 24 Jun 2021 17:01:27 -0400 Subject: [PATCH 0750/1208] d/caller_identity: Add changelog --- .changelog/19957.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19957.txt diff --git a/.changelog/19957.txt b/.changelog/19957.txt new file mode 100644 index 000000000000..6e25dcaa5e59 --- /dev/null +++ b/.changelog/19957.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +data-source/aws_caller_identity: Add `source_arn` to provide source role when caller is assumed role +``` \ No newline at end of file From 984d0cd22c57b7919f604f14a623e88c95e939a2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 24 Jun 2021 17:06:33 -0400 Subject: [PATCH 0751/1208] docs/d/caller_identity: Add example --- website/docs/d/caller_identity.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/caller_identity.html.markdown b/website/docs/d/caller_identity.html.markdown index bb9bfcae5521..a3edd2497a10 100644 --- a/website/docs/d/caller_identity.html.markdown +++ b/website/docs/d/caller_identity.html.markdown @@ -39,5 +39,5 @@ There are no arguments available for this data source. * `account_id` - AWS Account ID number of the account that owns or contains the calling entity. * `arn` - ARN associated with the calling entity. * `id` - Account ID number of the account that owns or contains the calling entity. -* `source_arn` - Same as `arn` unless `arn` is an assumed role ARN, in which case, `source_arn` is the ARN of source role of the assumed role. +* `source_arn` - Same as `arn` unless `arn` is an assumed role ARN. In that case, `source_arn` is the ARN of the source role of the assumed role. For example, if `arn` is `arn:aws:sts::123456789012:assumed-role/example-role/AWSCLI-Session`, which corresponds to an assumed role, `source_arn` would be `arn:aws:iam::123456789012:role/example-role`. * `user_id` - Unique identifier of the calling entity. From 4ecde63ed9f59e40d0d65237ef39e6fff479c1a9 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 24 Jun 2021 17:13:39 -0400 Subject: [PATCH 0752/1208] tests/d/caller_identity: Appease dear linter --- aws/data_source_aws_caller_identity_test.go | 30 ++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/aws/data_source_aws_caller_identity_test.go b/aws/data_source_aws_caller_identity_test.go index 544879007c82..2d275a2d6cc9 100644 --- a/aws/data_source_aws_caller_identity_test.go +++ b/aws/data_source_aws_caller_identity_test.go @@ -22,38 +22,38 @@ func TestSourceARN(t *testing.T) { }, { Name: "regular ARN", - ARN: "arn:aws:iam::111122223333:role/role_name", - Expected: "arn:aws:iam::111122223333:role/role_name", + ARN: "arn:aws:iam::111122223333:role/role_name", //lintignore:AWSAT005 + Expected: "arn:aws:iam::111122223333:role/role_name", //lintignore:AWSAT005 }, { Name: "assumed role ARN", - ARN: "arn:aws:sts::444433332222:assumed-role/something_something-admin/sessionIDNotPartOfRoleARN", - Expected: "arn:aws:iam::444433332222:role/something_something-admin", + ARN: "arn:aws:sts::444433332222:assumed-role/something_something-admin/sessionIDNotPartOfRoleARN", //lintignore:AWSAT005 + Expected: "arn:aws:iam::444433332222:role/something_something-admin", //lintignore:AWSAT005 }, { Name: "'assumed-role' part of ARN resource", - ARN: "arn:aws:iam::444433332222:user/assumed-role-but-not-really", - Expected: "arn:aws:iam::444433332222:user/assumed-role-but-not-really", + ARN: "arn:aws:iam::444433332222:user/assumed-role-but-not-really", //lintignore:AWSAT005 + Expected: "arn:aws:iam::444433332222:user/assumed-role-but-not-really", //lintignore:AWSAT005 }, { Name: "user ARN", - ARN: "arn:aws:iam::123456789012:user/Bob", - Expected: "arn:aws:iam::123456789012:user/Bob", + ARN: "arn:aws:iam::123456789012:user/Bob", //lintignore:AWSAT005 + Expected: "arn:aws:iam::123456789012:user/Bob", //lintignore:AWSAT005 }, { Name: "assumed role from AWS example", - ARN: "arn:aws:sts::123456789012:assumed-role/example-role/AWSCLI-Session", - Expected: "arn:aws:iam::123456789012:role/example-role", + ARN: "arn:aws:sts::123456789012:assumed-role/example-role/AWSCLI-Session", //lintignore:AWSAT005 + Expected: "arn:aws:iam::123456789012:role/example-role", //lintignore:AWSAT005 }, { - Name: "multiple slashes in resource", // not sure this is even valid - ARN: "arn:aws:sts::123456789012:assumed-role/example-role/also-part-of-role-or-no/AWSCLI-Session", - Expected: "arn:aws:iam::123456789012:role/example-role/also-part-of-role-or-no", + Name: "multiple slashes in resource", // not sure this is even valid + ARN: "arn:aws:sts::123456789012:assumed-role/example-role/also-part-of-role-or-no/AWSCLI-Session", //lintignore:AWSAT005 + Expected: "arn:aws:iam::123456789012:role/example-role/also-part-of-role-or-no", //lintignore:AWSAT005 }, { Name: "not an sts ARN", - ARN: "arn:aws:iam::123456789012:assumed-role/example-role/AWSCLI-Session", - Expected: "arn:aws:iam::123456789012:assumed-role/example-role/AWSCLI-Session", + ARN: "arn:aws:iam::123456789012:assumed-role/example-role/AWSCLI-Session", //lintignore:AWSAT005 + Expected: "arn:aws:iam::123456789012:assumed-role/example-role/AWSCLI-Session", //lintignore:AWSAT005 }, } From cf2a908e98c09b5aeb632020816bf2db175b4271 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 24 Jun 2021 21:23:40 +0000 Subject: [PATCH 0753/1208] Update CHANGELOG.md for #19955 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3da6a820ca6c..e8cc990f5d58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ ENHANCEMENTS: * resource/aws_default_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_ecs_capacity_provider: Allow updates to the `auto_scaling_group_provider` argument without recreating the resource ([#16942](https://github.com/hashicorp/terraform-provider-aws/issues/16942)) * resource/aws_eks_cluster: Allow updates to `encryption_config` ([#19144](https://github.com/hashicorp/terraform-provider-aws/issues/19144)) -* resource/aws_lb_target_group: Add support for application cookie stickiness ([#18102](https://github.com/hashicorp/terraform-provider-aws/issues/18102)) +* resource/aws_lb_target_group: Add support for `app_cookie` stickiness type and `cookie_name` argument ([#18102](https://github.com/hashicorp/terraform-provider-aws/issues/18102)) * resource/aws_main_route_table_association: Wait for association to reach the required state ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_neptune_cluster: Add `copy_snapshot_to_tags` argument ([#19899](https://github.com/hashicorp/terraform-provider-aws/issues/19899)) * resource/aws_route: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) From 7ed5f82d440d8c9ca4f9cb6713e530785f1aab2f Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Thu, 24 Jun 2021 22:35:33 +0000 Subject: [PATCH 0754/1208] v3.47.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8cc990f5d58..5f9c0b1ed806 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 3.47.0 (Unreleased) +## 3.47.0 (June 24, 2021) FEATURES: From 6a22678ab8a63c3615307aab05a0b2b93de3b37a Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 24 Jun 2021 22:53:31 +0000 Subject: [PATCH 0755/1208] Update CHANGELOG.md after v3.47.0 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f9c0b1ed806..9470fd018ef0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## 3.48.0 (Unreleased) ## 3.47.0 (June 24, 2021) FEATURES: From b8d85ff25287b868ea49b85e9c8484080050c36a Mon Sep 17 00:00:00 2001 From: Ben Doyle Date: Fri, 25 Jun 2021 11:41:58 +1000 Subject: [PATCH 0756/1208] Fix typo in aws_autoscaling_attachment target group attachment example. No resource aws_alb_target_group exists, it's simply "lb" not "alb". --- website/docs/r/autoscaling_attachment.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/autoscaling_attachment.html.markdown b/website/docs/r/autoscaling_attachment.html.markdown index 41c5497589fe..cbf329086df9 100644 --- a/website/docs/r/autoscaling_attachment.html.markdown +++ b/website/docs/r/autoscaling_attachment.html.markdown @@ -33,7 +33,7 @@ resource "aws_autoscaling_attachment" "asg_attachment_bar" { # Create a new ALB Target Group attachment resource "aws_autoscaling_attachment" "asg_attachment_bar" { autoscaling_group_name = aws_autoscaling_group.asg.id - alb_target_group_arn = aws_alb_target_group.test.arn + alb_target_group_arn = aws_lb_target_group.test.arn } ``` From 8f8426fcc203480c5f42713d696a20951c793cab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Jun 2021 06:12:14 +0000 Subject: [PATCH 0757/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.66 to 1.38.67. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.66...v1.38.67) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../aws/aws-sdk-go/aws/endpoints/defaults.go | 13 +++++++++++++ .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 828d2b37dd4b..787471d791d4 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.66 + github.com/aws/aws-sdk-go v1.38.67 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 279e56f85ba6..feda3a0b582d 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.66 h1:z1nEnVOb0ctiHURel3sFxZdXDrXnG6Fa+Dly3Kb0KVo= -github.com/aws/aws-sdk-go v1.38.66/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.67 h1:OCeXMKiiM8X7HAKPCE5yD+t+sEsRaj8EwDs2tlgvX2c= +github.com/aws/aws-sdk-go v1.38.67/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index cef754e1ae4b..b5fb6dd0f8f4 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -4891,6 +4891,7 @@ var awsPartition = partition{ "ap-east-1": endpoint{}, "ap-northeast-1": endpoint{}, "ap-northeast-2": endpoint{}, + "ap-northeast-3": endpoint{}, "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, @@ -9626,6 +9627,18 @@ var awsusgovPartition = partition{ "mq": service{ Endpoints: endpoints{ + "fips-us-gov-east-1": endpoint{ + Hostname: "mq-fips.us-gov-east-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-gov-east-1", + }, + }, + "fips-us-gov-west-1": endpoint{ + Hostname: "mq-fips.us-gov-west-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-gov-west-1", + }, + }, "us-gov-east-1": endpoint{}, "us-gov-west-1": endpoint{}, }, diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index 0b5f25f0d8b3..dfd25e923b40 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.66" +const SDKVersion = "1.38.67" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index a64052c03185..5019cdf24bfe 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.66 +# github.com/aws/aws-sdk-go v1.38.67 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From e7f8e461e1c4198e5448640b3ed71de36fc9b8b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Jun 2021 06:12:28 +0000 Subject: [PATCH 0758/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.66 to 1.38.67 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.66 to 1.38.67. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.66...v1.38.67) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c85c5dff518a..d09c1e406419 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.66 + github.com/aws/aws-sdk-go v1.38.67 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index 0855fca0d69b..99d168ccaabf 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.66 h1:z1nEnVOb0ctiHURel3sFxZdXDrXnG6Fa+Dly3Kb0KVo= -github.com/aws/aws-sdk-go v1.38.66/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.67 h1:OCeXMKiiM8X7HAKPCE5yD+t+sEsRaj8EwDs2tlgvX2c= +github.com/aws/aws-sdk-go v1.38.67/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 5d3f9dc1505ae5b763ef3b9e4ad9e5af4844a983 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 25 Jun 2021 15:56:33 +0300 Subject: [PATCH 0759/1208] add `multi_region` --- aws/resource_aws_kms_key.go | 68 +++++++++++++++----------------- aws/resource_aws_kms_key_test.go | 55 +++++++++++++++++++------- 2 files changed, 72 insertions(+), 51 deletions(-) diff --git a/aws/resource_aws_kms_key.go b/aws/resource_aws_kms_key.go index 590a88b4e3b3..37b05687b69a 100644 --- a/aws/resource_aws_kms_key.go +++ b/aws/resource_aws_kms_key.go @@ -6,7 +6,6 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/kms" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -40,35 +39,24 @@ func resourceAwsKmsKey() *schema.Resource { Computed: true, }, "description": { - Type: schema.TypeString, - Optional: true, - Computed: true, + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringLenBetween(0, 8192), }, "key_usage": { - Type: schema.TypeString, - Optional: true, - Default: kms.KeyUsageTypeEncryptDecrypt, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - kms.KeyUsageTypeEncryptDecrypt, - kms.KeyUsageTypeSignVerify, - }, false), + Type: schema.TypeString, + Optional: true, + Default: kms.KeyUsageTypeEncryptDecrypt, + ForceNew: true, + ValidateFunc: validation.StringInSlice(kms.KeyUsageType_Values(), false), }, "customer_master_key_spec": { - Type: schema.TypeString, - Optional: true, - Default: kms.CustomerMasterKeySpecSymmetricDefault, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - kms.CustomerMasterKeySpecSymmetricDefault, - kms.CustomerMasterKeySpecRsa2048, - kms.CustomerMasterKeySpecRsa3072, - kms.CustomerMasterKeySpecRsa4096, - kms.CustomerMasterKeySpecEccNistP256, - kms.CustomerMasterKeySpecEccNistP384, - kms.CustomerMasterKeySpecEccNistP521, - kms.CustomerMasterKeySpecEccSecgP256k1, - }, false), + Type: schema.TypeString, + Optional: true, + Default: kms.CustomerMasterKeySpecSymmetricDefault, + ForceNew: true, + ValidateFunc: validation.StringInSlice(kms.CustomerMasterKeySpec_Values(), false), }, "policy": { Type: schema.TypeString, @@ -82,6 +70,12 @@ func resourceAwsKmsKey() *schema.Resource { Optional: true, Default: true, }, + "multi_region": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Default: false, + }, "enable_key_rotation": { Type: schema.TypeBool, Optional: true, @@ -107,6 +101,7 @@ func resourceAwsKmsKeyCreate(d *schema.ResourceData, meta interface{}) error { req := &kms.CreateKeyInput{ CustomerMasterKeySpec: aws.String(d.Get("customer_master_key_spec").(string)), KeyUsage: aws.String(d.Get("key_usage").(string)), + MultiRegion: aws.Bool(d.Get("multi_region").(bool)), } if v, exists := d.GetOk("description"); exists { req.Description = aws.String(v.(string)) @@ -196,6 +191,7 @@ func resourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error { d.Set("key_usage", metadata.KeyUsage) d.Set("customer_master_key_spec", metadata.CustomerMasterKeySpec) d.Set("is_enabled", metadata.Enabled) + d.Set("multi_region", metadata.MultiRegion) pOut, err := retryOnAwsCode(kms.ErrCodeNotFoundException, func() (interface{}, error) { return conn.GetKeyPolicy(&kms.GetKeyPolicyInput{ @@ -210,7 +206,7 @@ func resourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error { p := pOut.(*kms.GetKeyPolicyOutput) policy, err := structure.NormalizeJsonString(*p.Policy) if err != nil { - return fmt.Errorf("policy contains an invalid JSON: %s", err) + return fmt.Errorf("policy contains an invalid JSON: %w", err) } d.Set("policy", policy) @@ -246,7 +242,7 @@ func resourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error { } if err != nil { - return fmt.Errorf("error listing tags for KMS Key (%s): %s", d.Id(), err) + return fmt.Errorf("error listing tags for KMS Key (%s): %w", d.Id(), err) } tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -302,7 +298,7 @@ func resourceAwsKmsKeyUpdate(d *schema.ResourceData, meta interface{}) error { o, n := d.GetChange("tags_all") if err := keyvaluetags.KmsUpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating KMS Key (%s) tags: %s", d.Id(), err) + return fmt.Errorf("error updating KMS Key (%s) tags: %w", d.Id(), err) } } @@ -327,7 +323,7 @@ func resourceAwsKmsKeyDescriptionUpdate(conn *kms.KMS, d *schema.ResourceData) e func resourceAwsKmsKeyPolicyUpdate(conn *kms.KMS, d *schema.ResourceData) error { policy, err := structure.NormalizeJsonString(d.Get("policy").(string)) if err != nil { - return fmt.Errorf("policy contains an invalid JSON: %s", err) + return fmt.Errorf("policy contains an invalid JSON: %w", err) } keyId := d.Get("key_id").(string) @@ -377,8 +373,7 @@ func updateKmsKeyStatus(conn *kms.KMS, id string, shouldBeEnabled bool) error { KeyId: aws.String(id), }) if err != nil { - awsErr, ok := err.(awserr.Error) - if ok && awsErr.Code() == "NotFoundException" { + if isAWSErr(err, kms.ErrCodeNotFoundException, "") { return nil, fmt.Sprintf("%t", !shouldBeEnabled), nil } return resp, "FAILED", err @@ -392,7 +387,7 @@ func updateKmsKeyStatus(conn *kms.KMS, id string, shouldBeEnabled bool) error { _, err = wait.WaitForState() if err != nil { - return fmt.Errorf("Failed setting KMS key status to %t: %s", shouldBeEnabled, err) + return fmt.Errorf("Failed setting KMS key status to %t: %w", shouldBeEnabled, err) } return nil @@ -405,11 +400,10 @@ func updateKmsKeyRotationStatus(conn *kms.KMS, d *schema.ResourceData) error { err := handleKeyRotation(conn, shouldEnableRotation, aws.String(d.Id())) if err != nil { - awsErr, ok := err.(awserr.Error) - if ok && awsErr.Code() == "DisabledException" { + if isAWSErr(err, kms.ErrCodeDisabledException, "") { return resource.RetryableError(err) } - if ok && awsErr.Code() == "NotFoundException" { + if isAWSErr(err, kms.ErrCodeNotFoundException, "") { return resource.RetryableError(err) } @@ -438,7 +432,7 @@ func updateKmsKeyRotationStatus(conn *kms.KMS, d *schema.ResourceData) error { log.Printf("[DEBUG] Checking if KMS key %s rotation status is %t", d.Id(), shouldEnableRotation) - out, err := retryOnAwsCode("NotFoundException", func() (interface{}, error) { + out, err := retryOnAwsCode(kms.ErrCodeNotFoundException, func() (interface{}, error) { return conn.GetKeyRotationStatus(&kms.GetKeyRotationStatusInput{ KeyId: aws.String(d.Id()), }) diff --git a/aws/resource_aws_kms_key_test.go b/aws/resource_aws_kms_key_test.go index 300f0ffffb26..cd5912940d27 100644 --- a/aws/resource_aws_kms_key_test.go +++ b/aws/resource_aws_kms_key_test.go @@ -84,6 +84,8 @@ func TestAccAWSKmsKey_basic(t *testing.T) { testAccCheckAWSKmsKeyExists(resourceName, &key), resource.TestCheckResourceAttr(resourceName, "customer_master_key_spec", "SYMMETRIC_DEFAULT"), resource.TestCheckResourceAttr(resourceName, "key_usage", "ENCRYPT_DECRYPT"), + resource.TestCheckResourceAttr(resourceName, "multi_region", "false"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -134,7 +136,7 @@ func TestAccAWSKmsKey_disappears(t *testing.T) { Config: testAccAWSKmsKey(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSKmsKeyExists(resourceName, &key), - testAccCheckAWSKmsKeyDisappears(&key), + testAccCheckResourceDisappears(testAccProvider, resourceAwsKmsKey(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -315,6 +317,34 @@ func TestAccAWSKmsKey_tags(t *testing.T) { }) } +func TestAccAWSKmsKey_multiRegion(t *testing.T) { + var key kms.KeyMetadata + rName := fmt.Sprintf("tf-testacc-kms-key-%s", acctest.RandString(13)) + resourceName := "aws_kms_key.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, kms.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSKmsKeyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSKmsKeyMultiRegionConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSKmsKeyExists(resourceName, &key), + resource.TestCheckResourceAttr(resourceName, "multi_region", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_window_in_days"}, + }, + }, + }) +} + func testAccCheckAWSKmsKeyHasPolicy(name string, expectedPolicyText string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] @@ -417,19 +447,6 @@ func testAccCheckAWSKmsKeyIsEnabled(key *kms.KeyMetadata, isEnabled bool) resour } } -func testAccCheckAWSKmsKeyDisappears(key *kms.KeyMetadata) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).kmsconn - - _, err := conn.ScheduleKeyDeletion(&kms.ScheduleKeyDeletionInput{ - KeyId: key.KeyId, - PendingWindowInDays: aws.Int64(int64(7)), - }) - - return err - } -} - func testAccAWSKmsKey(rName string) string { return fmt.Sprintf(` resource "aws_kms_key" "test" { @@ -656,3 +673,13 @@ resource "aws_kms_key" "test" { } `, rName) } + +func testAccAWSKmsKeyMultiRegionConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_kms_key" "test" { + description = %[1]q + deletion_window_in_days = 7 + multi_region = true +} +`, rName) +} From 584f3aacb12b1acbbd56041f2dd1544ab71c609a Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 25 Jun 2021 15:58:07 +0300 Subject: [PATCH 0760/1208] docs --- website/docs/r/kms_key.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/kms_key.html.markdown b/website/docs/r/kms_key.html.markdown index 7248feffd5b2..5dbcbdee834c 100644 --- a/website/docs/r/kms_key.html.markdown +++ b/website/docs/r/kms_key.html.markdown @@ -35,6 +35,7 @@ Valid values: `SYMMETRIC_DEFAULT`, `RSA_2048`, `RSA_3072`, `RSA_4096`, `ECC_NIS * `deletion_window_in_days` - (Optional) Duration in days after which the key is deleted after destruction of the resource, must be between 7 and 30 days. Defaults to 30 days. * `is_enabled` - (Optional) Specifies whether the key is enabled. Defaults to true. * `enable_key_rotation` - (Optional) Specifies whether [key rotation](http://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html) is enabled. Defaults to false. +* `multi_region` - (Optional) Creates a multi-Region primary key that you can replicate into other AWS Regions. You cannot change this value after you create the CMK. Defaults to false. * `tags` - (Optional) A map of tags to assign to the object. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ## Attributes Reference From 6af2e26ebba4ab7b8923f63a176a2cd46b370740 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 25 Jun 2021 16:01:29 +0300 Subject: [PATCH 0761/1208] change log --- .changelog/19967.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/19967.txt diff --git a/.changelog/19967.txt b/.changelog/19967.txt new file mode 100644 index 000000000000..1c64698511d4 --- /dev/null +++ b/.changelog/19967.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_kms_key: Add `multi_region` argument. +``` + +```release-note:enhancement +resource/aws_kms_key: Add plan time validation to `description`. +``` From 490b7400ef89f878e65babc86eaad063da5c73dc Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 25 Jun 2021 16:12:38 +0300 Subject: [PATCH 0762/1208] sweeper --- aws/resource_aws_kms_key_test.go | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/aws/resource_aws_kms_key_test.go b/aws/resource_aws_kms_key_test.go index cd5912940d27..3d33f1acadbe 100644 --- a/aws/resource_aws_kms_key_test.go +++ b/aws/resource_aws_kms_key_test.go @@ -23,34 +23,37 @@ func init() { func testSweepKmsKeys(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } conn := client.(*AWSClient).kmsconn err = conn.ListKeysPages(&kms.ListKeysInput{Limit: aws.Int64(int64(1000))}, func(out *kms.ListKeysOutput, lastPage bool) bool { for _, k := range out.Keys { + kKeyId := aws.StringValue(k.KeyId) kOut, err := conn.DescribeKey(&kms.DescribeKeyInput{ KeyId: k.KeyId, }) if err != nil { - log.Printf("Error: Failed to describe key %q: %s", *k.KeyId, err) + log.Printf("Error: Failed to describe key %q: %s", kKeyId, err) return false } - if *kOut.KeyMetadata.KeyManager == kms.KeyManagerTypeAws { + if aws.StringValue(kOut.KeyMetadata.KeyManager) == kms.KeyManagerTypeAws { // Skip (default) keys which are managed by AWS continue } - if *kOut.KeyMetadata.KeyState == kms.KeyStatePendingDeletion { + if aws.StringValue(kOut.KeyMetadata.KeyState) == kms.KeyStatePendingDeletion { // Skip keys which are already scheduled for deletion continue } - _, err = conn.ScheduleKeyDeletion(&kms.ScheduleKeyDeletionInput{ - KeyId: k.KeyId, - PendingWindowInDays: aws.Int64(int64(7)), - }) + r := resourceAwsKmsKey() + d := r.Data(nil) + d.SetId(kKeyId) + d.Set("key_id", kKeyId) + d.Set("deletion_window_in_days", "7") + err = r.Delete(d, client) if err != nil { - log.Printf("Error: Failed to schedule key %q for deletion: %s", *k.KeyId, err) + log.Printf("Error: Failed to schedule key %q for deletion: %s", kKeyId, err) return false } } @@ -61,7 +64,7 @@ func testSweepKmsKeys(region string) error { log.Printf("[WARN] Skipping KMS Key sweep for %s: %s", region, err) return nil } - return fmt.Errorf("Error describing KMS keys: %s", err) + return fmt.Errorf("Error describing KMS keys: %w", err) } return nil From fb65a7cd1e81a3dbf3eaf1d274d0854033064a45 Mon Sep 17 00:00:00 2001 From: Raid Sulaiman Date: Fri, 25 Jun 2021 14:36:42 +0100 Subject: [PATCH 0763/1208] Correct typo Correct typo in docs for recently added `aws_elasticsearch_domain_saml_options` resource --- website/docs/r/elasticsearch_domain_saml_options.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/elasticsearch_domain_saml_options.html.markdown b/website/docs/r/elasticsearch_domain_saml_options.html.markdown index 003ef48be727..962cd9fbffe3 100644 --- a/website/docs/r/elasticsearch_domain_saml_options.html.markdown +++ b/website/docs/r/elasticsearch_domain_saml_options.html.markdown @@ -59,7 +59,7 @@ The following arguments are optional: * `enabled` - (Required) Whether SAML authentication is enabled. * `idp` - (Optional) Information from your identity provider. * `master_backend_role` - (Optional) This backend role from the SAML IdP receives full permissions to the cluster, equivalent to a new master user. -* `master_user_name` - (Options) This username from the SAML IdP receives full permissions to the cluster, equivalent to a new master user. +* `master_user_name` - (Optional) This username from the SAML IdP receives full permissions to the cluster, equivalent to a new master user. * `roles_key` - (Optional) Element of the SAML assertion to use for backend roles. Default is roles. * `session_timeout_minutes` - (Optional) Duration of a session in minutes after a user logs in. Default is 60. Maximum value is 1,440. * `subject_key` - (Optional) Element of the SAML assertion to use for username. Default is NameID. From f7deab76335ce6b2a89391be2a063867ef585fe5 Mon Sep 17 00:00:00 2001 From: Travis Paul Date: Fri, 25 Jun 2021 11:29:27 -0400 Subject: [PATCH 0764/1208] Fix campaign_hook argument description for the pinpoint_app resource. The current description for this argument appears to be a duplicate of the limits argument. --- website/docs/r/pinpoint_app.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/pinpoint_app.markdown b/website/docs/r/pinpoint_app.markdown index 15159f90db54..e14e31cbc9ba 100644 --- a/website/docs/r/pinpoint_app.markdown +++ b/website/docs/r/pinpoint_app.markdown @@ -34,7 +34,7 @@ The following arguments are supported: * `name` - (Optional) The application name. By default generated by Terraform * `name_prefix` - (Optional) The name of the Pinpoint application. Conflicts with `name` -* `campaign_hook` - (Optional) The default campaign limits for the app. These limits apply to each campaign for the app, unless the campaign overrides the default with limits of its own +* `campaign_hook` - (Optional) Specifies settings for invoking an AWS Lambda function that customizes a segment for a campaign * `limits` - (Optional) The default campaign limits for the app. These limits apply to each campaign for the app, unless the campaign overrides the default with limits of its own * `quiet_time` - (Optional) The default quiet time for the app. Each campaign for this app sends no messages during this time unless the campaign overrides the default with a quiet time of its own * `tags` - (Optional) Key-value map of resource tags. 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. From 8c6b5dab4c96229499fbbc6ec817e5637b416445 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Fri, 25 Jun 2021 12:14:14 -0400 Subject: [PATCH 0765/1208] loop over Firewall Manager WebACLs --- aws/resource_aws_wafv2_web_acl_test.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_wafv2_web_acl_test.go b/aws/resource_aws_wafv2_web_acl_test.go index d0de3847183a..aa59aa5e35ed 100644 --- a/aws/resource_aws_wafv2_web_acl_test.go +++ b/aws/resource_aws_wafv2_web_acl_test.go @@ -4,11 +4,11 @@ import ( "fmt" "log" "regexp" + "strings" "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/wafv2" - "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -48,13 +48,23 @@ func testSweepWafv2WebAcls(region string) error { continue } + name := aws.StringValue(webAcl.Name) + + // Exclude WebACLs managed by Firewall Manager as deletion returns AccessDeniedException. + // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/19149 + // Prefix Reference: https://docs.aws.amazon.com/waf/latest/developerguide/get-started-fms-create-security-policy.html + if strings.HasPrefix(name, "FMManagedWebACLV2") { + log.Printf("[WARN] Skipping WAFv2 Web ACL: %s", name) + continue + } + id := aws.StringValue(webAcl.Id) r := resourceAwsWafv2WebACL() d := r.Data(nil) d.SetId(id) d.Set("lock_token", webAcl.LockToken) - d.Set("name", webAcl.Name) + d.Set("name", name) d.Set("scope", input.Scope) sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) @@ -67,16 +77,7 @@ func testSweepWafv2WebAcls(region string) error { errs = multierror.Append(errs, fmt.Errorf("error describing WAFv2 Web ACLs for %s: %w", region, err)) } - err = testSweepResourceOrchestrator(sweepResources) - - // Since we cannot exclude Firewall Manager WebACLs from the sweepResources var above, - // we instead catch and ignore the following expected AccessDeniedException. - // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/19149 - if tfawserr.ErrMessageContains(err, "AccessDeniedException", "managed by Firewall Manager") { - return errs.ErrorOrNil() - } - - if err != nil { + if err := testSweepResourceOrchestrator(sweepResources); err != nil { errs = multierror.Append(errs, fmt.Errorf("error sweeping WAFv2 Web ACLs for %s: %w", region, err)) } From dceb5a7c2cc875fa2d60680de17538f44ad6959f Mon Sep 17 00:00:00 2001 From: Tyler Lynch Date: Fri, 25 Jun 2021 13:15:40 -0400 Subject: [PATCH 0766/1208] Fixed duplicated code (DRY) --- ...esource_aws_storagegateway_gateway_test.go | 128 +++--------------- 1 file changed, 22 insertions(+), 106 deletions(-) diff --git a/aws/resource_aws_storagegateway_gateway_test.go b/aws/resource_aws_storagegateway_gateway_test.go index fefdb6fe5442..36d46a9ee8b4 100644 --- a/aws/resource_aws_storagegateway_gateway_test.go +++ b/aws/resource_aws_storagegateway_gateway_test.go @@ -1053,73 +1053,33 @@ resource "aws_storagegateway_gateway" "test" { `, rName) } -func testAccAWSStorageGatewayGatewayConfigSmbActiveDirectorySettingsBase(rName string) string { - return composeConfig( - // Reference: https://docs.aws.amazon.com/storagegateway/latest/userguide/Requirements.html - testAccAvailableEc2InstanceTypeForAvailabilityZone("aws_subnet.test[0].availability_zone", "m5.xlarge", "m4.xlarge"), - testAccAvailableAZsNoOptInConfig(), - fmt.Sprintf(` -# Directory Service Directories must be deployed across multiple EC2 Availability Zones -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" +func testAccAWSStorageGatewayGatewayConfig_DirectoryServiceSimpleDirectory(rName string) string { + return fmt.Sprintf(` +resource "aws_directory_service_directory" "test" { + name = "terraformtesting.com" + password = "SuperSecretPassw0rd" + size = "Small" - tags = { - Name = %[1]q + vpc_settings { + subnet_ids = aws_subnet.test[*].id + vpc_id = aws_vpc.test.id } -} - -resource "aws_subnet" "test" { - count = 2 - - availability_zone = data.aws_availability_zones.available.names[count.index] - cidr_block = "10.0.${count.index}.0/24" - vpc_id = aws_vpc.test.id tags = { Name = %[1]q } } -resource "aws_internet_gateway" "test" { - vpc_id = aws_vpc.test.id - - tags = { - Name = %[1]q - } -} - -resource "aws_route" "test" { - destination_cidr_block = "0.0.0.0/0" - gateway_id = aws_internet_gateway.test.id - route_table_id = aws_vpc.test.main_route_table_id -} - -resource "aws_security_group" "test" { - vpc_id = aws_vpc.test.id - - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - } - - ingress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - } - - tags = { - Name = %[1]q - } +`, rName) } +func testAccAWSStorageGatewayGatewayConfig_DirectoryServiceMicrosoftAD(rName string) string { + return fmt.Sprintf(` resource "aws_directory_service_directory" "test" { + edition = "Standard" name = "terraformtesting.com" password = "SuperSecretPassw0rd" - size = "Small" + type = "MicrosoftAD" vpc_settings { subnet_ids = aws_subnet.test[*].id @@ -1131,42 +1091,10 @@ resource "aws_directory_service_directory" "test" { } } -resource "aws_vpc_dhcp_options" "test" { - domain_name = aws_directory_service_directory.test.name - domain_name_servers = aws_directory_service_directory.test.dns_ip_addresses - - tags = { - Name = %[1]q - } -} - -resource "aws_vpc_dhcp_options_association" "test" { - dhcp_options_id = aws_vpc_dhcp_options.test.id - vpc_id = aws_vpc.test.id -} - -# Reference: https://docs.aws.amazon.com/storagegateway/latest/userguide/ec2-gateway-file.html -data "aws_ssm_parameter" "aws_service_storagegateway_ami_FILE_S3_latest" { - name = "/aws/service/storagegateway/ami/FILE_S3/latest" -} - -resource "aws_instance" "test" { - depends_on = [aws_route.test, aws_vpc_dhcp_options_association.test] - - ami = data.aws_ssm_parameter.aws_service_storagegateway_ami_FILE_S3_latest.value - associate_public_ip_address = true - instance_type = data.aws_ec2_instance_type_offering.available.instance_type - vpc_security_group_ids = [aws_security_group.test.id] - subnet_id = aws_subnet.test[0].id - - tags = { - Name = %[1]q - } -} -`, rName)) +`, rName) } -func testAccAWSStorageGatewayGatewayConfigSmbMicrosoftActiveDirectorySettingsBase(rName string) string { +func testAccAWSStorageGatewayGatewayConfigSmbActiveDirectorySettingsBase(rName string) string { return composeConfig( // Reference: https://docs.aws.amazon.com/storagegateway/latest/userguide/Requirements.html testAccAvailableEc2InstanceTypeForAvailabilityZone("aws_subnet.test[0].availability_zone", "m5.xlarge", "m4.xlarge"), @@ -1229,22 +1157,6 @@ resource "aws_security_group" "test" { } } -resource "aws_directory_service_directory" "test" { - edition = "Standard" - name = "terraformtesting.com" - password = "SuperSecretPassw0rd" - type = "MicrosoftAD" - - vpc_settings { - subnet_ids = aws_subnet.test[*].id - vpc_id = aws_vpc.test.id - } - - tags = { - Name = %[1]q - } -} - resource "aws_vpc_dhcp_options" "test" { domain_name = aws_directory_service_directory.test.name domain_name_servers = aws_directory_service_directory.test.dns_ip_addresses @@ -1283,6 +1195,7 @@ resource "aws_instance" "test" { func testAccAWSStorageGatewayGatewayConfig_SmbActiveDirectorySettings(rName string) string { return composeConfig( testAccAWSStorageGatewayGatewayConfigSmbActiveDirectorySettingsBase(rName), + testAccAWSStorageGatewayGatewayConfig_DirectoryServiceSimpleDirectory(rName), fmt.Sprintf(` resource "aws_storagegateway_gateway" "test" { gateway_ip_address = aws_instance.test.public_ip @@ -1302,6 +1215,7 @@ resource "aws_storagegateway_gateway" "test" { func testAccAWSStorageGatewayGatewayConfig_SmbActiveDirectorySettingsTimeout(rName string, timeout int) string { return composeConfig( testAccAWSStorageGatewayGatewayConfigSmbActiveDirectorySettingsBase(rName), + testAccAWSStorageGatewayGatewayConfig_DirectoryServiceSimpleDirectory(rName), fmt.Sprintf(` resource "aws_storagegateway_gateway" "test" { gateway_ip_address = aws_instance.test.public_ip @@ -1321,7 +1235,8 @@ resource "aws_storagegateway_gateway" "test" { func testAccAWSStorageGatewayGatewayConfig_SmbMicrosoftActiveDirectorySettings(rName string) string { return composeConfig( - testAccAWSStorageGatewayGatewayConfigSmbMicrosoftActiveDirectorySettingsBase(rName), + testAccAWSStorageGatewayGatewayConfigSmbActiveDirectorySettingsBase(rName), + testAccAWSStorageGatewayGatewayConfig_DirectoryServiceMicrosoftAD(rName), fmt.Sprintf(` resource "aws_storagegateway_gateway" "test" { gateway_ip_address = aws_instance.test.public_ip @@ -1340,7 +1255,8 @@ resource "aws_storagegateway_gateway" "test" { func testAccAWSStorageGatewayGatewayConfig_SmbMicrosoftActiveDirectorySettingsTimeout(rName string, timeout int) string { return composeConfig( - testAccAWSStorageGatewayGatewayConfigSmbMicrosoftActiveDirectorySettingsBase(rName), + testAccAWSStorageGatewayGatewayConfigSmbActiveDirectorySettingsBase(rName), + testAccAWSStorageGatewayGatewayConfig_DirectoryServiceMicrosoftAD(rName), fmt.Sprintf(` resource "aws_storagegateway_gateway" "test" { gateway_ip_address = aws_instance.test.public_ip From f887951c5be9ab6bbf7c6e37049c7d17240e731d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 25 Jun 2021 17:05:53 -0400 Subject: [PATCH 0767/1208] ds/caller_identity: Revert to previous --- aws/data_source_aws_caller_identity.go | 40 -------------- aws/data_source_aws_caller_identity_test.go | 59 --------------------- 2 files changed, 99 deletions(-) diff --git a/aws/data_source_aws_caller_identity.go b/aws/data_source_aws_caller_identity.go index a03fa6382917..366275518ebd 100644 --- a/aws/data_source_aws_caller_identity.go +++ b/aws/data_source_aws_caller_identity.go @@ -3,11 +3,8 @@ package aws import ( "fmt" "log" - "regexp" - "strings" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/sts" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -27,11 +24,6 @@ func dataSourceAwsCallerIdentity() *schema.Resource { Computed: true, }, - "source_arn": { - Type: schema.TypeString, - Computed: true, - }, - "user_id": { Type: schema.TypeString, Computed: true, @@ -56,38 +48,6 @@ func dataSourceAwsCallerIdentityRead(d *schema.ResourceData, meta interface{}) e d.Set("account_id", res.Account) d.Set("arn", res.Arn) d.Set("user_id", res.UserId) - d.Set("source_arn", sourceARN(aws.StringValue(res.Arn))) return nil } - -// sourceARN returns the same string passed in unless it appears to be an assumed role ARN. -// In that case, it attempts to return the source role ARN associated with an assumed role ARN. -func sourceARN(rawARN string) string { - result := rawARN - - if strings.Contains(result, ":assumed-role/") && strings.Contains(result, ":sts:") { - parsedARN, err := arn.Parse(result) - - if err != nil { - return result - } - - if parsedARN.Service != "sts" { - // not an assumed role - return result - } - - re := regexp.MustCompile(`^assumed-role/`) - parsedARN.Resource = re.ReplaceAllString(parsedARN.Resource, "role/") - parsedARN.Service = "iam" - - if v := strings.LastIndex(parsedARN.Resource, "/"); v > 0 { - parsedARN.Resource = parsedARN.Resource[0:v] - } - - result = parsedARN.String() - } - - return result -} diff --git a/aws/data_source_aws_caller_identity_test.go b/aws/data_source_aws_caller_identity_test.go index 2d275a2d6cc9..e73435d0ba1a 100644 --- a/aws/data_source_aws_caller_identity_test.go +++ b/aws/data_source_aws_caller_identity_test.go @@ -9,65 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func TestSourceARN(t *testing.T) { - testCases := []struct { - Name string - ARN string - Expected string - }{ - { - Name: "not an ARN", - ARN: "abcd", - Expected: "abcd", - }, - { - Name: "regular ARN", - ARN: "arn:aws:iam::111122223333:role/role_name", //lintignore:AWSAT005 - Expected: "arn:aws:iam::111122223333:role/role_name", //lintignore:AWSAT005 - }, - { - Name: "assumed role ARN", - ARN: "arn:aws:sts::444433332222:assumed-role/something_something-admin/sessionIDNotPartOfRoleARN", //lintignore:AWSAT005 - Expected: "arn:aws:iam::444433332222:role/something_something-admin", //lintignore:AWSAT005 - }, - { - Name: "'assumed-role' part of ARN resource", - ARN: "arn:aws:iam::444433332222:user/assumed-role-but-not-really", //lintignore:AWSAT005 - Expected: "arn:aws:iam::444433332222:user/assumed-role-but-not-really", //lintignore:AWSAT005 - }, - { - Name: "user ARN", - ARN: "arn:aws:iam::123456789012:user/Bob", //lintignore:AWSAT005 - Expected: "arn:aws:iam::123456789012:user/Bob", //lintignore:AWSAT005 - }, - { - Name: "assumed role from AWS example", - ARN: "arn:aws:sts::123456789012:assumed-role/example-role/AWSCLI-Session", //lintignore:AWSAT005 - Expected: "arn:aws:iam::123456789012:role/example-role", //lintignore:AWSAT005 - }, - { - Name: "multiple slashes in resource", // not sure this is even valid - ARN: "arn:aws:sts::123456789012:assumed-role/example-role/also-part-of-role-or-no/AWSCLI-Session", //lintignore:AWSAT005 - Expected: "arn:aws:iam::123456789012:role/example-role/also-part-of-role-or-no", //lintignore:AWSAT005 - }, - { - Name: "not an sts ARN", - ARN: "arn:aws:iam::123456789012:assumed-role/example-role/AWSCLI-Session", //lintignore:AWSAT005 - Expected: "arn:aws:iam::123456789012:assumed-role/example-role/AWSCLI-Session", //lintignore:AWSAT005 - }, - } - - for _, testCase := range testCases { - t.Run(testCase.Name, func(t *testing.T) { - got := sourceARN(testCase.ARN) - - if got != testCase.Expected { - t.Errorf("for %s: got %s, expected %s", testCase.Name, got, testCase.Expected) - } - }) - } -} - func TestAccAWSCallerIdentity_basic(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, From ad1f9a3257e0c8f9ab202f456f5cc6ec2f679ef4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 25 Jun 2021 17:06:17 -0400 Subject: [PATCH 0768/1208] ds/iam_assumed_role_source: Update changelog --- .changelog/19957.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changelog/19957.txt b/.changelog/19957.txt index 6e25dcaa5e59..4521f23bd83e 100644 --- a/.changelog/19957.txt +++ b/.changelog/19957.txt @@ -1,3 +1,3 @@ -```release-note:enhancement -data-source/aws_caller_identity: Add `source_arn` to provide source role when caller is assumed role +```release-note:new-data-source +aws_iam_assumed_role_source ``` \ No newline at end of file From ae63556f7f85d840f46c6463d7cbb9fcc99d4ab3 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 25 Jun 2021 17:06:46 -0400 Subject: [PATCH 0769/1208] i/iam_role: Add role finder --- aws/internal/service/iam/finder/finder.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/aws/internal/service/iam/finder/finder.go b/aws/internal/service/iam/finder/finder.go index e9bad76a9fe5..5b9065a6502d 100644 --- a/aws/internal/service/iam/finder/finder.go +++ b/aws/internal/service/iam/finder/finder.go @@ -1,6 +1,8 @@ package finder import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/iam" ) @@ -109,3 +111,22 @@ func Policies(conn *iam.IAM, arn, name, pathPrefix string) ([]*iam.Policy, error return results, err } + +// RoleARNByName returns a role's ARN given the role name +func RoleARNByName(conn *iam.IAM, name string) (*iam.Role, error) { + input := &iam.GetRoleInput{ + RoleName: aws.String(name), + } + + output, err := conn.GetRole(input) + + if err != nil { + return nil, fmt.Errorf("getting IAM Role (%s): %w", name, err) + } + + if output == nil || output.Role == nil { + return nil, fmt.Errorf("getting IAM Role (%s): empty response", name) + } + + return output.Role, nil +} From 11256040069c0479531b9c6f6703610296073958 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 25 Jun 2021 17:07:01 -0400 Subject: [PATCH 0770/1208] provider: Add new data source --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index bb29044942d4..1adb6d59a662 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -298,6 +298,7 @@ func Provider() *schema.Provider { "aws_glue_script": dataSourceAwsGlueScript(), "aws_guardduty_detector": dataSourceAwsGuarddutyDetector(), "aws_iam_account_alias": dataSourceAwsIamAccountAlias(), + "aws_iam_assumed_role_source": dataSourceAwsIAMAssumedRoleSource(), "aws_iam_group": dataSourceAwsIAMGroup(), "aws_iam_instance_profile": dataSourceAwsIAMInstanceProfile(), "aws_iam_policy": dataSourceAwsIAMPolicy(), From 33536361488f6a2ab355a10d3f7aa9facc4ff01b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 25 Jun 2021 17:07:33 -0400 Subject: [PATCH 0771/1208] d/iam_assumed_role_source: New data source --- ...data_source_aws_iam_assumed_role_source.go | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 aws/data_source_aws_iam_assumed_role_source.go diff --git a/aws/data_source_aws_iam_assumed_role_source.go b/aws/data_source_aws_iam_assumed_role_source.go new file mode 100644 index 000000000000..e66db1381cf2 --- /dev/null +++ b/aws/data_source_aws_iam_assumed_role_source.go @@ -0,0 +1,135 @@ +package aws + +import ( + "fmt" + "regexp" + "strings" + + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func dataSourceAwsIAMAssumedRoleSource() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsIAMAssumedRoleSourceRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Required: true, + }, + "role_path": { + Type: schema.TypeString, + Computed: true, + }, + "role_name": { + Type: schema.TypeString, + Computed: true, + }, + "source_arn": { + Type: schema.TypeString, + Computed: true, + }, + "session_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).iamconn + + arn := d.Get("arn").(string) + + d.SetId(arn) + + roleName := "" + sessionName := "" + var err error + + if roleName, sessionName, err = roleSessionNameFromARN(arn); err != nil { + // errors purposely eaten to pass through ARN + d.Set("source_arn", arn) + d.Set("session_name", "") + d.Set("role_name", "") + d.Set("role_path", "") + + return nil + } + + var role *iam.Role + + err = resource.Retry(waiter.PropagationTimeout, func() *resource.RetryError { + var err error + + role, err = finder.RoleARNByName(conn, roleName) + + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + role, err = finder.RoleARNByName(conn, roleName) + } + + if err != nil { + return fmt.Errorf("unable to get role (%s): %w", roleName, err) + } + + d.Set("session_name", sessionName) + d.Set("role_name", roleName) + d.Set("source_arn", role.Arn) + d.Set("role_path", role.Path) + + return nil +} + +func roleSessionNameFromARN(rawARN string) (string, string, error) { + parsedARN, err := arn.Parse(rawARN) + + if err != nil { + return "", "", fmt.Errorf("could not parse ARN (%s)", rawARN) + } + + parts := strings.Split(parsedARN.Resource, "/") + + reAssume := regexp.MustCompile(`^assumed-role/.{1,}/.{2,}`) + reRole := regexp.MustCompile(`^role/.{1,}`) + + if reAssume.MatchString(parsedARN.Resource) && parsedARN.Service != "sts" { + return "", "", fmt.Errorf("assume role service must be STS (%s)", rawARN) + } + + if reRole.MatchString(parsedARN.Resource) && parsedARN.Service != "iam" { + return "", "", fmt.Errorf("role service must be IAM (%s)", rawARN) + } + + if !reAssume.MatchString(parsedARN.Resource) && !reRole.MatchString(parsedARN.Resource) { + return "", "", fmt.Errorf("not a role nor assumed role (%s)", rawARN) + } + + if reRole.MatchString(parsedARN.Resource) && len(parts) > 1 { + return parts[len(parts)-1], "", nil + } + + if len(parts) < 3 { + return "", "", fmt.Errorf("not a valid assumed role (%s)", rawARN) + } + + return parts[len(parts)-2], parts[len(parts)-1], nil +} From 1cdcdf2240bacce0769ff56a4ba0416aeb071e4e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 25 Jun 2021 17:07:52 -0400 Subject: [PATCH 0772/1208] tests/d/iam_assumed_role_source: New data source --- ...source_aws_iam_assumed_role_source_test.go | 312 ++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 aws/data_source_aws_iam_assumed_role_source_test.go diff --git a/aws/data_source_aws_iam_assumed_role_source_test.go b/aws/data_source_aws_iam_assumed_role_source_test.go new file mode 100644 index 000000000000..36f34c2c418a --- /dev/null +++ b/aws/data_source_aws_iam_assumed_role_source_test.go @@ -0,0 +1,312 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/iam" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +/* +arn:aws:iam::123456789012:root +arn:aws:iam::123456789012:user/JohnDoe +arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/JaneDoe +arn:aws:iam::123456789012:group/Developers +arn:aws:iam::123456789012:group/division_abc/subdivision_xyz/product_A/Developers +arn:aws:iam::123456789012:role/S3Access +arn:aws:iam::123456789012:role/application_abc/component_xyz/RDSAccess +arn:aws:iam::123456789012:role/aws-service-role/access-analyzer.amazonaws.com/AWSServiceRoleForAccessAnalyzer +arn:aws:iam::123456789012:role/service-role/QuickSightAction +arn:aws:iam::123456789012:policy/UsersManageOwnCredentials +arn:aws:iam::123456789012:policy/division_abc/subdivision_xyz/UsersManageOwnCredentials +arn:aws:iam::123456789012:instance-profile/Webserver +arn:aws:sts::123456789012:federated-user/JohnDoe +arn:aws:sts::123456789012:assumed-role/Accounting-Role/JaneDoe +arn:aws:iam::123456789012:mfa/JaneDoeMFA +arn:aws:iam::123456789012:u2f/user/JohnDoe/default (U2F security key) +arn:aws:iam::123456789012:server-certificate/ProdServerCert +arn:aws:iam::123456789012:server-certificate/division_abc/subdivision_xyz/ProdServerCert +arn:aws:iam::123456789012:saml-provider/ADFSProvider +arn:aws:iam::123456789012:oidc-provider/GoogleProvider +*/ + +func TestAssumedRoleRoleSessionName(t *testing.T) { + testCases := []struct { + Name string + ARN string + ExpectedRoleName string + ExpectedSessionName string + ExpectedError bool + }{ + { + Name: "not an ARN", + ARN: "abcd", + ExpectedRoleName: "", + ExpectedSessionName: "", + ExpectedError: true, + }, + { + Name: "regular role ARN", + ARN: "arn:aws:iam::111122223333:role/role_name", //lintignore:AWSAT005 + ExpectedRoleName: "role_name", + ExpectedSessionName: "", + ExpectedError: false, + }, + { + Name: "assumed role ARN", + ARN: "arn:aws:sts::444433332222:assumed-role/something_something-admin/sessionIDNotPartOfRoleARN", //lintignore:AWSAT005 + ExpectedRoleName: "something_something-admin", + ExpectedSessionName: "sessionIDNotPartOfRoleARN", + ExpectedError: false, + }, + { + Name: "'assumed-role' part of ARN resource", + ARN: "arn:aws:iam::444433332222:user/assumed-role-but-not-really", //lintignore:AWSAT005 + ExpectedRoleName: "", + ExpectedSessionName: "", + ExpectedError: true, + }, + { + Name: "user ARN", + ARN: "arn:aws:iam::123456789012:user/Bob", //lintignore:AWSAT005 + ExpectedRoleName: "", + ExpectedSessionName: "", + ExpectedError: true, + }, + { + Name: "assumed role from AWS example", + ARN: "arn:aws:sts::123456789012:assumed-role/example-role/AWSCLI-Session", //lintignore:AWSAT005 + ExpectedRoleName: "example-role", + ExpectedSessionName: "AWSCLI-Session", + ExpectedError: false, + }, + { + Name: "multiple slashes in resource", // not sure this is even valid + ARN: "arn:aws:sts::123456789012:assumed-role/path/role-name/AWSCLI-Session", //lintignore:AWSAT005 + ExpectedRoleName: "role-name", + ExpectedSessionName: "AWSCLI-Session", + ExpectedError: false, + }, + { + Name: "not an sts ARN", + ARN: "arn:aws:iam::123456789012:assumed-role/example-role/AWSCLI-Session", //lintignore:AWSAT005 + ExpectedRoleName: "", + ExpectedSessionName: "", + ExpectedError: true, + }, + { + Name: "role with path", + ARN: "arn:aws:iam::123456789012:role/this/is/the/path/role-name", //lintignore:AWSAT005 + ExpectedRoleName: "role-name", + ExpectedSessionName: "", + ExpectedError: false, + }, + { + Name: "wrong service", + ARN: "arn:aws:ec2::123456789012:role/role-name", //lintignore:AWSAT005 + ExpectedRoleName: "", + ExpectedSessionName: "", + ExpectedError: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + role, session, err := roleSessionNameFromARN(testCase.ARN) + + if err != nil && !testCase.ExpectedError { + t.Errorf("for %s: got error (%s), expected none", testCase.ARN, err) + } + + if err == nil && testCase.ExpectedError { + t.Errorf("for %s: got no error, expected an error", testCase.ARN) + } + + if testCase.ExpectedRoleName != role || testCase.ExpectedSessionName != session { + t.Errorf("for %s: got role %s, session %s; expected role %s, session %s", testCase.ARN, role, session, testCase.ExpectedRoleName, testCase.ExpectedSessionName) + } + }) + } +} + +func TestAccAWSDataSourceIAMAssumedRoleSource_basic(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_iam_assumed_role_source.test" + resourceName := "aws_iam_role.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, iam.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAwsIAMAssumedRoleSourceConfig(rName, "/", "session-id"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "role_path", resourceName, "path"), + resource.TestCheckResourceAttr(dataSourceName, "session_name", "session-id"), + ), + }, + }, + }) +} + +func TestAccAWSDataSourceIAMAssumedRoleSource_withPath(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_iam_assumed_role_source.test" + resourceName := "aws_iam_role.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, iam.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAwsIAMAssumedRoleSourceConfig(rName, "/this/is/a/long/path/", "session-id"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "role_path", resourceName, "path"), + resource.TestCheckResourceAttr(dataSourceName, "session_name", "session-id"), + ), + }, + }, + }) +} + +func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRole(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_iam_assumed_role_source.test" + resourceName := "aws_iam_role.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, iam.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAwsIAMAssumedRoleSourceNotAssumedConfig(rName, "/"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "role_path", resourceName, "path"), + resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), + ), + }, + }, + }) +} + +func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRoleWithPath(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_iam_assumed_role_source.test" + resourceName := "aws_iam_role.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, iam.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAwsIAMAssumedRoleSourceNotAssumedConfig(rName, "/this/is/a/long/path/"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "role_path", resourceName, "path"), + resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), + ), + }, + }, + }) +} + +func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRoleUser(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_iam_assumed_role_source.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, iam.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAwsIAMAssumedRoleSourceUserConfig(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckResourceAttrGlobalARN(dataSourceName, "arn", "iam", fmt.Sprintf("user/division/extra-division/not-assumed-role/%[1]s", rName)), + resource.TestCheckResourceAttr(dataSourceName, "role_name", ""), + resource.TestCheckResourceAttr(dataSourceName, "role_path", ""), + resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), + ), + }, + }, + }) +} + +func testAccAwsIAMAssumedRoleSourceConfig(rName, path, sessionID string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "test" { + name = %[1]q + path = %[2]q + + assume_role_policy = jsonencode({ + "Version" = "2012-10-17" + + "Statement" = [{ + "Action" = "sts:AssumeRole" + "Principal" = { + "Service" = "ec2.${data.aws_partition.current.dns_suffix}" + } + "Effect" = "Allow" + }] + }) +} + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} + +data "aws_iam_assumed_role_source" "test" { + arn = "arn:${data.aws_partition.current.partition}:sts::${data.aws_caller_identity.current.account_id}:assumed-role/${aws_iam_role.test.name}/%[3]s" +} +`, rName, path, sessionID) +} + +func testAccAwsIAMAssumedRoleSourceNotAssumedConfig(rName, path string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + path = %[2]q + + assume_role_policy = jsonencode({ + "Version" = "2012-10-17" + + "Statement" = [{ + "Action" = "sts:AssumeRole" + "Principal" = { + "Service" = "ec2.${data.aws_partition.current.dns_suffix}" + } + "Effect" = "Allow" + }] + }) +} + +data "aws_iam_assumed_role_source" "test" { + arn = aws_iam_role.test.arn +} +`, rName, path) +} + +func testAccAwsIAMAssumedRoleSourceUserConfig(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} + +data "aws_iam_assumed_role_source" "test" { + arn = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:user/division/extra-division/not-assumed-role/%[1]s" +} +`, rName) +} From 8394cf06305f67098ac24b31af73e4d15daa1845 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 25 Jun 2021 17:08:12 -0400 Subject: [PATCH 0773/1208] docs/d/iam_assumed_role_source: New data source --- .../docs/d/iam_assumed_role_source.markdown | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 website/docs/d/iam_assumed_role_source.markdown diff --git a/website/docs/d/iam_assumed_role_source.markdown b/website/docs/d/iam_assumed_role_source.markdown new file mode 100644 index 000000000000..4e1ab4a2275a --- /dev/null +++ b/website/docs/d/iam_assumed_role_source.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "IAM" +layout: "aws" +page_title: "AWS: aws_iam_assumed_role_source" +description: |- + Get information on the IAM source role of an STS assumed role +--- + +# Data Source: aws_iam_assumed_role_source + +This data source provides information on the IAM source role of an STS assumed role. For non-role ARNs, this data source simply passes the ARN through. + +For some AWS resources, multiple types of principals are allowed in the same argument (e.g., IAM users and IAM roles). However, these arguments often do not allow assumed-role (i.e., STS, temporary credential) principals. Given an STS ARN, this data source provides the ARN for the source IAM role. + +## Example Usage + +### Basic Example + +```terraform +data "aws_iam_assumed_role_source" "example" { + arn = "arn:aws:sts::123456789012:assumed-role/Audien-Heaven/MatyNoyes" +} +``` + +### Find the Terraform Runner's Source Role + +Combined with `aws_caller_identity`, you can get the current user's IAM role ARN (`source_arn`) even if you're using an assumed role. If you're not using an assumed role, the caller's (e.g., an IAM user's) ARN will simply be passed through. In environments where both IAM users and individuals using assumed roles need to apply the same configurations, this data source enables seamless use. + +```terraform +data "aws_caller_identity" "current" {} + +data "aws_iam_assumed_role_source" "example" { + arn = data.aws_called_identity.current.arn +} +``` + +## Argument Reference + +* `arn` - (Required) ARN for an assumed role. + +~> If `arn` is a non-role ARN (or non-ARN), Terraform gives no error and `source_arn` will be equal to the `arn` value. For IAM role and STS assumed-role ARNs, Terraform gives an error if the identified IAM role does not exist. + +## Attributes Reference + +* `role_path` - Path of the source role. Only available if `arn` corresponds to an IAM role or STS assumed role. +* `role_name` - Name of the source role. Only available if `arn` corresponds to an IAM role or STS assumed role. +* `source_arn` - IAM source role ARN if `arn` corresponds to an STS assumed role. Otherwise, `source_arn` is equal to `arn`. +* `session_name` - Name of the STS session. Only available if `arn` corresponds to an STS assumed role. From 914cd83c8a38f5221384aeeae48740f75d4e9ee4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 25 Jun 2021 17:08:46 -0400 Subject: [PATCH 0774/1208] tests/d/iam_assumed_role_source: Remove comments --- ...source_aws_iam_assumed_role_source_test.go | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/aws/data_source_aws_iam_assumed_role_source_test.go b/aws/data_source_aws_iam_assumed_role_source_test.go index 36f34c2c418a..4b733b185e7c 100644 --- a/aws/data_source_aws_iam_assumed_role_source_test.go +++ b/aws/data_source_aws_iam_assumed_role_source_test.go @@ -9,29 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -/* -arn:aws:iam::123456789012:root -arn:aws:iam::123456789012:user/JohnDoe -arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/JaneDoe -arn:aws:iam::123456789012:group/Developers -arn:aws:iam::123456789012:group/division_abc/subdivision_xyz/product_A/Developers -arn:aws:iam::123456789012:role/S3Access -arn:aws:iam::123456789012:role/application_abc/component_xyz/RDSAccess -arn:aws:iam::123456789012:role/aws-service-role/access-analyzer.amazonaws.com/AWSServiceRoleForAccessAnalyzer -arn:aws:iam::123456789012:role/service-role/QuickSightAction -arn:aws:iam::123456789012:policy/UsersManageOwnCredentials -arn:aws:iam::123456789012:policy/division_abc/subdivision_xyz/UsersManageOwnCredentials -arn:aws:iam::123456789012:instance-profile/Webserver -arn:aws:sts::123456789012:federated-user/JohnDoe -arn:aws:sts::123456789012:assumed-role/Accounting-Role/JaneDoe -arn:aws:iam::123456789012:mfa/JaneDoeMFA -arn:aws:iam::123456789012:u2f/user/JohnDoe/default (U2F security key) -arn:aws:iam::123456789012:server-certificate/ProdServerCert -arn:aws:iam::123456789012:server-certificate/division_abc/subdivision_xyz/ProdServerCert -arn:aws:iam::123456789012:saml-provider/ADFSProvider -arn:aws:iam::123456789012:oidc-provider/GoogleProvider -*/ - func TestAssumedRoleRoleSessionName(t *testing.T) { testCases := []struct { Name string From 39f176a44019ad06afd19cfd0ea21dff29617b5e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 25 Jun 2021 17:21:46 -0400 Subject: [PATCH 0775/1208] docs/d/caller_identity: Remove old attribute --- website/docs/d/caller_identity.html.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/website/docs/d/caller_identity.html.markdown b/website/docs/d/caller_identity.html.markdown index a3edd2497a10..bc5a8e19c321 100644 --- a/website/docs/d/caller_identity.html.markdown +++ b/website/docs/d/caller_identity.html.markdown @@ -39,5 +39,4 @@ There are no arguments available for this data source. * `account_id` - AWS Account ID number of the account that owns or contains the calling entity. * `arn` - ARN associated with the calling entity. * `id` - Account ID number of the account that owns or contains the calling entity. -* `source_arn` - Same as `arn` unless `arn` is an assumed role ARN. In that case, `source_arn` is the ARN of the source role of the assumed role. For example, if `arn` is `arn:aws:sts::123456789012:assumed-role/example-role/AWSCLI-Session`, which corresponds to an assumed role, `source_arn` would be `arn:aws:iam::123456789012:role/example-role`. * `user_id` - Unique identifier of the calling entity. From a4704cc389a28ded207254c0cc20450e3c507726 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 25 Jun 2021 17:23:17 -0400 Subject: [PATCH 0776/1208] docs/d/iam_assumed_role_source: Clarify docs --- website/docs/d/iam_assumed_role_source.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/iam_assumed_role_source.markdown b/website/docs/d/iam_assumed_role_source.markdown index 4e1ab4a2275a..16491196ecd5 100644 --- a/website/docs/d/iam_assumed_role_source.markdown +++ b/website/docs/d/iam_assumed_role_source.markdown @@ -24,7 +24,7 @@ data "aws_iam_assumed_role_source" "example" { ### Find the Terraform Runner's Source Role -Combined with `aws_caller_identity`, you can get the current user's IAM role ARN (`source_arn`) even if you're using an assumed role. If you're not using an assumed role, the caller's (e.g., an IAM user's) ARN will simply be passed through. In environments where both IAM users and individuals using assumed roles need to apply the same configurations, this data source enables seamless use. +Combined with `aws_caller_identity`, you can get the current user's source IAM role ARN (`source_arn`) if you're using an assumed role. If you're not using an assumed role, the caller's (e.g., an IAM user's) ARN will simply be passed through. In environments where both IAM users and individuals using assumed roles need to apply the same configurations, this data source enables seamless use. ```terraform data "aws_caller_identity" "current" {} From 33559d003c3d6d1fef5f02e31ac613ed422de6a3 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 27 Jun 2021 00:37:21 +0300 Subject: [PATCH 0777/1208] fsx windows - audit log config --- .changelog/19970.txt | 3 + aws/resource_aws_fsx_windows_file_system.go | 216 +++++++++++++----- ...source_aws_fsx_windows_file_system_test.go | 72 +++++- .../r/fsx_windows_file_system.html.markdown | 7 + 4 files changed, 234 insertions(+), 64 deletions(-) create mode 100644 .changelog/19970.txt diff --git a/.changelog/19970.txt b/.changelog/19970.txt new file mode 100644 index 000000000000..ceff50805b97 --- /dev/null +++ b/.changelog/19970.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_fsx_windows_file_system: Add `audit_log_configuration` argument. +``` diff --git a/aws/resource_aws_fsx_windows_file_system.go b/aws/resource_aws_fsx_windows_file_system.go index a8d5bdca499c..4670e18b6650 100644 --- a/aws/resource_aws_fsx_windows_file_system.go +++ b/aws/resource_aws_fsx_windows_file_system.go @@ -4,9 +4,11 @@ import ( "fmt" "log" "regexp" + "strings" "time" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/fsx" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -45,6 +47,38 @@ func resourceAwsFsxWindowsFileSystem() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "audit_log_configuration": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "audit_log_destionation": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validateArn, + StateFunc: fsxWindowsAuditLogStateFunc, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return strings.HasPrefix(old, fmt.Sprintf("%s:", new)) + }, + }, + "file_access_audit_log_level": { + Type: schema.TypeString, + Optional: true, + Default: fsx.WindowsAccessAuditLogLevelDisabled, + ValidateFunc: validation.StringInSlice(fsx.WindowsAccessAuditLogLevel_Values(), false), + }, + "file_share_access_audit_log_level": { + Type: schema.TypeString, + Optional: true, + Default: fsx.WindowsAccessAuditLogLevelDisabled, + ValidateFunc: validation.StringInSlice(fsx.WindowsAccessAuditLogLevel_Values(), false), + }, + }, + }, + }, "automatic_backup_retention_days": { Type: schema.TypeInt, Optional: true, @@ -177,15 +211,11 @@ func resourceAwsFsxWindowsFileSystem() *schema.Resource { ), }, "deployment_type": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: fsx.WindowsDeploymentTypeSingleAz1, - ValidateFunc: validation.StringInSlice([]string{ - fsx.WindowsDeploymentTypeMultiAz1, - fsx.WindowsDeploymentTypeSingleAz1, - fsx.WindowsDeploymentTypeSingleAz2, - }, false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: fsx.WindowsDeploymentTypeSingleAz1, + ValidateFunc: validation.StringInSlice(fsx.WindowsDeploymentType_Values(), false), }, "preferred_subnet_id": { Type: schema.TypeString, @@ -202,14 +232,11 @@ func resourceAwsFsxWindowsFileSystem() *schema.Resource { Computed: true, }, "storage_type": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: fsx.StorageTypeSsd, - ValidateFunc: validation.StringInSlice([]string{ - fsx.StorageTypeSsd, - fsx.StorageTypeHdd, - }, false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: fsx.StorageTypeSsd, + ValidateFunc: validation.StringInSlice(fsx.StorageType_Values(), false), }, }, @@ -262,6 +289,10 @@ func resourceAwsFsxWindowsFileSystemCreate(d *schema.ResourceData, meta interfac input.WindowsConfiguration.SelfManagedActiveDirectoryConfiguration = expandFsxSelfManagedActiveDirectoryConfigurationCreate(v.([]interface{})) } + if v, ok := d.GetOk("audit_log_configuration"); ok && len(v.([]interface{})) > 0 { + input.WindowsConfiguration.AuditLogConfiguration = expandFsxWindowsAuditLogCreateConfiguration(v.([]interface{})) + } + if len(tags) > 0 { input.Tags = tags.IgnoreAws().FsxTags() } @@ -276,7 +307,7 @@ func resourceAwsFsxWindowsFileSystemCreate(d *schema.ResourceData, meta interfac result, err := conn.CreateFileSystem(input) if err != nil { - return fmt.Errorf("Error creating FSx filesystem: %s", err) + return fmt.Errorf("Error creating FSx filesystem: %w", err) } d.SetId(aws.StringValue(result.FileSystem.FileSystemId)) @@ -284,7 +315,7 @@ func resourceAwsFsxWindowsFileSystemCreate(d *schema.ResourceData, meta interfac log.Println("[DEBUG] Waiting for filesystem to become available") if err := waitForFsxFileSystemCreation(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { - return fmt.Errorf("Error waiting for filesystem (%s) to become available: %s", d.Id(), err) + return fmt.Errorf("Error waiting for filesystem (%s) to become available: %w", d.Id(), err) } return resourceAwsFsxWindowsFileSystemRead(d, meta) @@ -297,48 +328,45 @@ func resourceAwsFsxWindowsFileSystemUpdate(d *schema.ResourceData, meta interfac o, n := d.GetChange("tags_all") if err := keyvaluetags.FsxUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating FSx Windows File System (%s) tags: %s", d.Get("arn").(string), err) + return fmt.Errorf("error updating FSx Windows File System (%s) tags: %w", d.Get("arn").(string), err) } } - requestUpdate := false - input := &fsx.UpdateFileSystemInput{ - ClientRequestToken: aws.String(resource.UniqueId()), - FileSystemId: aws.String(d.Id()), - WindowsConfiguration: &fsx.UpdateFileSystemWindowsConfiguration{}, - } + if d.HasChangeExcept("tags_all") { + input := &fsx.UpdateFileSystemInput{ + ClientRequestToken: aws.String(resource.UniqueId()), + FileSystemId: aws.String(d.Id()), + WindowsConfiguration: &fsx.UpdateFileSystemWindowsConfiguration{}, + } - if d.HasChange("automatic_backup_retention_days") { - input.WindowsConfiguration.AutomaticBackupRetentionDays = aws.Int64(int64(d.Get("automatic_backup_retention_days").(int))) - requestUpdate = true - } + if d.HasChange("automatic_backup_retention_days") { + input.WindowsConfiguration.AutomaticBackupRetentionDays = aws.Int64(int64(d.Get("automatic_backup_retention_days").(int))) + } - if d.HasChange("throughput_capacity") { - input.WindowsConfiguration.ThroughputCapacity = aws.Int64(int64(d.Get("throughput_capacity").(int))) - requestUpdate = true - } + if d.HasChange("throughput_capacity") { + input.WindowsConfiguration.ThroughputCapacity = aws.Int64(int64(d.Get("throughput_capacity").(int))) + } - if d.HasChange("storage_capacity") { - input.StorageCapacity = aws.Int64(int64(d.Get("storage_capacity").(int))) - requestUpdate = true - } + if d.HasChange("storage_capacity") { + input.StorageCapacity = aws.Int64(int64(d.Get("storage_capacity").(int))) + } - if d.HasChange("daily_automatic_backup_start_time") { - input.WindowsConfiguration.DailyAutomaticBackupStartTime = aws.String(d.Get("daily_automatic_backup_start_time").(string)) - requestUpdate = true - } + if d.HasChange("daily_automatic_backup_start_time") { + input.WindowsConfiguration.DailyAutomaticBackupStartTime = aws.String(d.Get("daily_automatic_backup_start_time").(string)) + } - if d.HasChange("self_managed_active_directory") { - input.WindowsConfiguration.SelfManagedActiveDirectoryConfiguration = expandFsxSelfManagedActiveDirectoryConfigurationUpdate(d.Get("self_managed_active_directory").([]interface{})) - requestUpdate = true - } + if d.HasChange("self_managed_active_directory") { + input.WindowsConfiguration.SelfManagedActiveDirectoryConfiguration = expandFsxSelfManagedActiveDirectoryConfigurationUpdate(d.Get("self_managed_active_directory").([]interface{})) + } - if d.HasChange("weekly_maintenance_start_time") { - input.WindowsConfiguration.WeeklyMaintenanceStartTime = aws.String(d.Get("weekly_maintenance_start_time").(string)) - requestUpdate = true - } + if d.HasChange("weekly_maintenance_start_time") { + input.WindowsConfiguration.WeeklyMaintenanceStartTime = aws.String(d.Get("weekly_maintenance_start_time").(string)) + } + + if d.HasChange("audit_log_configuration") { + input.WindowsConfiguration.AuditLogConfiguration = expandFsxWindowsAuditLogCreateConfiguration(d.Get("audit_log_configuration").([]interface{})) + } - if requestUpdate { _, err := conn.UpdateFileSystem(input) if err != nil { @@ -367,7 +395,7 @@ func resourceAwsFsxWindowsFileSystemRead(d *schema.ResourceData, meta interface{ } if err != nil { - return fmt.Errorf("Error reading FSx File System (%s): %s", d.Id(), err) + return fmt.Errorf("Error reading FSx File System (%s): %w", d.Id(), err) } if filesystem == nil { @@ -398,30 +426,34 @@ func resourceAwsFsxWindowsFileSystemRead(d *schema.ResourceData, meta interface{ d.Set("storage_type", filesystem.StorageType) if err := d.Set("network_interface_ids", aws.StringValueSlice(filesystem.NetworkInterfaceIds)); err != nil { - return fmt.Errorf("error setting network_interface_ids: %s", err) + return fmt.Errorf("error setting network_interface_ids: %w", err) } d.Set("owner_id", filesystem.OwnerId) if err := d.Set("self_managed_active_directory", flattenFsxSelfManagedActiveDirectoryConfiguration(d, filesystem.WindowsConfiguration.SelfManagedActiveDirectoryConfiguration)); err != nil { - return fmt.Errorf("error setting self_managed_active_directory: %s", err) + return fmt.Errorf("error setting self_managed_active_directory: %w", err) + } + + if err := d.Set("audit_log_configuration", flattenFsxWindowsAuditLogConfiguration(filesystem.WindowsConfiguration.AuditLogConfiguration)); err != nil { + return fmt.Errorf("error setting audit_log_configuration: %w", err) } d.Set("storage_capacity", filesystem.StorageCapacity) if err := d.Set("subnet_ids", aws.StringValueSlice(filesystem.SubnetIds)); err != nil { - return fmt.Errorf("error setting subnet_ids: %s", err) + return fmt.Errorf("error setting subnet_ids: %w", err) } tags := keyvaluetags.FsxKeyValueTags(filesystem.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %s", err) + return fmt.Errorf("error setting tags: %w", err) } if err := d.Set("tags_all", tags.Map()); err != nil { - return fmt.Errorf("error setting tags_all: %s", err) + return fmt.Errorf("error setting tags_all: %w", err) } d.Set("throughput_capacity", filesystem.WindowsConfiguration.ThroughputCapacity) @@ -449,13 +481,13 @@ func resourceAwsFsxWindowsFileSystemDelete(d *schema.ResourceData, meta interfac } if err != nil { - return fmt.Errorf("Error deleting FSx filesystem: %s", err) + return fmt.Errorf("Error deleting FSx filesystem: %w", err) } log.Println("[DEBUG] Waiting for filesystem to delete") if err := waitForFsxFileSystemDeletion(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("Error waiting for filesystem (%s) to delete: %s", d.Id(), err) + return fmt.Errorf("Error waiting for filesystem (%s) to delete: %w", d.Id(), err) } return nil @@ -491,10 +523,18 @@ func expandFsxSelfManagedActiveDirectoryConfigurationUpdate(l []interface{}) *fs } data := l[0].(map[string]interface{}) - req := &fsx.SelfManagedActiveDirectoryConfigurationUpdates{ - DnsIps: expandStringSet(data["dns_ips"].(*schema.Set)), - Password: aws.String(data["password"].(string)), - UserName: aws.String(data["username"].(string)), + req := &fsx.SelfManagedActiveDirectoryConfigurationUpdates{} + + if v, ok := data["dns_ips"].(*schema.Set); ok && v.Len() > 0 { + req.DnsIps = expandStringSet(v) + } + + if v, ok := data["password"].(string); ok && v != "" { + req.Password = aws.String(v) + } + + if v, ok := data["username"].(string); ok && v != "" { + req.UserName = aws.String(v) } return req @@ -522,3 +562,53 @@ func flattenFsxSelfManagedActiveDirectoryConfiguration(d *schema.ResourceData, a return []map[string]interface{}{m} } + +func expandFsxWindowsAuditLogCreateConfiguration(l []interface{}) *fsx.WindowsAuditLogCreateConfiguration { + if len(l) == 0 || l[0] == nil { + return nil + } + + data := l[0].(map[string]interface{}) + req := &fsx.WindowsAuditLogCreateConfiguration{ + FileAccessAuditLogLevel: aws.String(data["file_access_audit_log_level"].(string)), + FileShareAccessAuditLogLevel: aws.String(data["file_share_access_audit_log_level"].(string)), + } + + if v, ok := data["audit_log_destionation"].(string); ok && v != "" { + req.AuditLogDestination = aws.String(fsxWindowsAuditLogStateFunc(v)) + } + + return req +} + +func flattenFsxWindowsAuditLogConfiguration(adopts *fsx.WindowsAuditLogConfiguration) []map[string]interface{} { + if adopts == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "file_access_audit_log_level": aws.StringValue(adopts.FileAccessAuditLogLevel), + "file_share_access_audit_log_level": aws.StringValue(adopts.FileShareAccessAuditLogLevel), + } + + if adopts.AuditLogDestination != nil { + m["audit_log_destionation"] = aws.StringValue(adopts.AuditLogDestination) + } + + return []map[string]interface{}{m} +} + +func fsxWindowsAuditLogStateFunc(v interface{}) string { + value := v.(string) + // API returns the specific log stream arn instead of provided log group + logArn, _ := arn.Parse(value) + if logArn.Service == "logs" { + parts := strings.SplitN(logArn.Resource, ":", 3) + if len(parts) == 3 { + return strings.TrimSuffix(value, fmt.Sprintf(":%s", parts[2])) + } else { + return value + } + } + return value +} diff --git a/aws/resource_aws_fsx_windows_file_system_test.go b/aws/resource_aws_fsx_windows_file_system_test.go index 94897cda2a70..3829430f1d27 100644 --- a/aws/resource_aws_fsx_windows_file_system_test.go +++ b/aws/resource_aws_fsx_windows_file_system_test.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/fsx" multierror "github.com/hashicorp/go-multierror" + "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" ) @@ -24,7 +25,7 @@ func testSweepFSXWindowsFileSystems(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } conn := client.(*AWSClient).fsxconn @@ -102,6 +103,9 @@ func TestAccAWSFsxWindowsFileSystem_basic(t *testing.T) { resource.TestMatchResourceAttr(resourceName, "weekly_maintenance_start_time", regexp.MustCompile(`^\d:\d\d:\d\d$`)), resource.TestCheckResourceAttr(resourceName, "deployment_type", "SINGLE_AZ_1"), resource.TestCheckResourceAttr(resourceName, "storage_type", "SSD"), + resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.0.file_access_audit_log_level", "DISABLED"), + resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.0.file_share_access_audit_log_level", "DISABLED"), ), }, { @@ -702,6 +706,50 @@ func TestAccAWSFsxWindowsFileSystem_WeeklyMaintenanceStartTime(t *testing.T) { }) } +func TestAccAWSFsxWindowsFileSystem_auditConfig(t *testing.T) { + var filesystem fsx.FileSystem + resourceName := "aws_fsx_windows_file_system.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(fsx.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, fsx.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckFsxWindowsFileSystemDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsFsxWindowsFileSystemConfigAuditConfig(rName, "SUCCESS_ONLY"), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem), + resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.0.file_access_audit_log_level", "SUCCESS_ONLY"), + resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.0.file_share_access_audit_log_level", "SUCCESS_ONLY"), + resource.TestCheckResourceAttrSet(resourceName, "audit_log_configuration.0.audit_log_destionation"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "security_group_ids", + "skip_final_backup", + }, + }, + { + Config: testAccAwsFsxWindowsFileSystemConfigAuditConfig(rName, "SUCCESS_AND_FAILURE"), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem), + resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.0.file_access_audit_log_level", "SUCCESS_AND_FAILURE"), + resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.0.file_share_access_audit_log_level", "SUCCESS_AND_FAILURE"), + resource.TestCheckResourceAttrSet(resourceName, "audit_log_configuration.0.audit_log_destionation"), + ), + }, + }, + }) +} + func testAccCheckFsxWindowsFileSystemExists(resourceName string, fs *fsx.FileSystem) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -1129,3 +1177,25 @@ resource "aws_fsx_windows_file_system" "test" { } `, weeklyMaintenanceStartTime) } + +func testAccAwsFsxWindowsFileSystemConfigAuditConfig(rName, status string) string { + return testAccAwsFsxWindowsFileSystemConfigBase() + fmt.Sprintf(` +resource aws_cloudwatch_log_group "test" { + name = "/aws/fsx/%[1]s" +} + +resource "aws_fsx_windows_file_system" "test" { + active_directory_id = aws_directory_service_directory.test.id + skip_final_backup = true + storage_capacity = 32 + subnet_ids = [aws_subnet.test1.id] + throughput_capacity = 32 + + audit_log_configuration { + audit_log_destionation = aws_cloudwatch_log_group.test.arn + file_access_audit_log_level = %[2]q + file_share_access_audit_log_level = %[2]q + } +} +`, rName, status) +} diff --git a/website/docs/r/fsx_windows_file_system.html.markdown b/website/docs/r/fsx_windows_file_system.html.markdown index bc9a765eae64..d62b97f8fc5f 100644 --- a/website/docs/r/fsx_windows_file_system.html.markdown +++ b/website/docs/r/fsx_windows_file_system.html.markdown @@ -67,6 +67,7 @@ The following arguments are supported: * `weekly_maintenance_start_time` - (Optional) The preferred start time (in `d:HH:MM` format) to perform weekly maintenance, in the UTC time zone. * `deployment_type` - (Optional) Specifies the file system deployment type, valid values are `MULTI_AZ_1`, `SINGLE_AZ_1` and `SINGLE_AZ_2`. Default value is `SINGLE_AZ_1`. * `preferred_subnet_id` - (Optional) Specifies the subnet in which you want the preferred file server to be located. Required for when deployment type is `MULTI_AZ_1`. +* `audit_log_configuration` - (Optional) The configuration that Amazon FSx for Windows File Server uses to audit and log user accesses of files, folders, and file shares on the Amazon FSx for Windows File Server file system. See below. * `storage_type` - (Optional) Specifies the storage type, Valid values are `SSD` and `HDD`. `HDD` is supported on `SINGLE_AZ_2` and `MULTI_AZ_1` Windows file system deployment types. Default value is `SSD`. ### self_managed_active_directory @@ -80,6 +81,12 @@ The following arguments are supported for `self_managed_active_directory` config * `file_system_administrators_group` - (Optional) The name of the domain group whose members are granted administrative privileges for the file system. Administrative privileges include taking ownership of files and folders, and setting audit controls (audit ACLs) on files and folders. The group that you specify must already exist in your domain. Defaults to `Domain Admins`. * `organizational_unit_distinguished_name` - (Optional) The fully qualified distinguished name of the organizational unit within your self-managed AD directory that the Windows File Server instance will join. For example, `OU=FSx,DC=yourdomain,DC=corp,DC=com`. Only accepts OU as the direct parent of the file system. If none is provided, the FSx file system is created in the default location of your self-managed AD directory. To learn more, see [RFC 2253](https://tools.ietf.org/html/rfc2253). +### audit_log_configuration + +* `audit_log_destionation` - (Optional) The Amazon Resource Name (ARN) for the destination of the audit logs. The destination can be any Amazon CloudWatch Logs log group ARN or Amazon Kinesis Data Firehose delivery stream ARN. Can be specified when `file_access_audit_log_level` and `file_share_access_audit_log_level` are not set to `DISABLED`. The name of the Amazon CloudWatch Logs log group must begin with the `/aws/fsx` prefix. The name of the Amazon Kinesis Data Firehouse delivery stream must begin with the `aws-fsx` prefix. If you do not provide a destination in `audit_log_destionation`, Amazon FSx will create and use a log stream in the CloudWatch Logs /aws/fsx/windows log group. +* `file_access_audit_log_level` - (Optional) Sets which attempt type is logged by Amazon FSx for file and folder accesses. Valid values are `SUCCESS_ONLY`, `FAILURE_ONLY`, `SUCCESS_AND_FAILURE`, and `DISABLED`. Default value is `DISABLED`. +* `file_share_access_audit_log_level` - (Optional) Sets which attempt type is logged by Amazon FSx for file share accesses. Valid values are `SUCCESS_ONLY`, `FAILURE_ONLY`, `SUCCESS_AND_FAILURE`, and `DISABLED`. Default value is `DISABLED`. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 5b757f58141f7a98de243167805e8ac7cf34531a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jun 2021 06:05:42 +0000 Subject: [PATCH 0778/1208] build(deps): bump alex-page/github-project-automation-plus Bumps [alex-page/github-project-automation-plus](https://github.com/alex-page/github-project-automation-plus) from 0.7.1 to 0.8.0. - [Release notes](https://github.com/alex-page/github-project-automation-plus/releases) - [Commits](https://github.com/alex-page/github-project-automation-plus/compare/v0.7.1...v0.8.0) --- updated-dependencies: - dependency-name: alex-page/github-project-automation-plus dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/project.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml index b7bf91aad8f5..7739fa63b75f 100644 --- a/.github/workflows/project.yml +++ b/.github/workflows/project.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Move team PRs to Review column - uses: alex-page/github-project-automation-plus@v0.7.1 + uses: alex-page/github-project-automation-plus@v0.8.0 if: contains(fromJSON('["anGie44", "bill-rich", "breathingdust", "ewbankkit", "gdavison", "maryelizbeth", "YakDriver"]'), github.actor) && github.event.pull_request.draft == false with: project: AWS Provider Working Board From cab144c152bea0385dbe6bef09d4a978b402a6e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jun 2021 06:11:27 +0000 Subject: [PATCH 0779/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.67 to 1.38.68. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.67...v1.38.68) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../github.com/aws/aws-sdk-go/aws/endpoints/defaults.go | 2 ++ .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 787471d791d4..398220035ce7 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.67 + github.com/aws/aws-sdk-go v1.38.68 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index feda3a0b582d..bb2008b449fe 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.67 h1:OCeXMKiiM8X7HAKPCE5yD+t+sEsRaj8EwDs2tlgvX2c= -github.com/aws/aws-sdk-go v1.38.67/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.68 h1:aOG8geU4SohNp659eKBHRBgbqSrZ6jNZlfimIuJAwL8= +github.com/aws/aws-sdk-go v1.38.68/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index b5fb6dd0f8f4..887c21dcb1ca 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -5138,6 +5138,7 @@ var awsPartition = partition{ "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, + "eu-west-2": endpoint{}, "fips-us-east-1": endpoint{ Hostname: "qldb-fips.us-east-1.amazonaws.com", CredentialScope: credentialScope{ @@ -6300,6 +6301,7 @@ var awsPartition = partition{ "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, + "eu-west-2": endpoint{}, "fips-us-east-1": endpoint{ Hostname: "session.qldb-fips.us-east-1.amazonaws.com", CredentialScope: credentialScope{ diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index dfd25e923b40..db6522049807 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.67" +const SDKVersion = "1.38.68" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 5019cdf24bfe..9119c60c7d00 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.67 +# github.com/aws/aws-sdk-go v1.38.68 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 8e94bbacd0b6d1686877cbbf184fedffa9d79474 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jun 2021 06:12:32 +0000 Subject: [PATCH 0780/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.67 to 1.38.68 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.67 to 1.38.68. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.67...v1.38.68) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d09c1e406419..5375fd44f872 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.67 + github.com/aws/aws-sdk-go v1.38.68 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index 99d168ccaabf..d739790c8b05 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.67 h1:OCeXMKiiM8X7HAKPCE5yD+t+sEsRaj8EwDs2tlgvX2c= -github.com/aws/aws-sdk-go v1.38.67/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.68 h1:aOG8geU4SohNp659eKBHRBgbqSrZ6jNZlfimIuJAwL8= +github.com/aws/aws-sdk-go v1.38.68/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 20cb83d5b8bdb6f23f540f2802363727d23ff285 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jun 2021 14:25:55 +0000 Subject: [PATCH 0781/1208] build(deps): bump github.com/hashicorp/terraform-plugin-sdk/v2 Bumps [github.com/hashicorp/terraform-plugin-sdk/v2](https://github.com/hashicorp/terraform-plugin-sdk) from 2.6.1 to 2.7.0. - [Release notes](https://github.com/hashicorp/terraform-plugin-sdk/releases) - [Changelog](https://github.com/hashicorp/terraform-plugin-sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/terraform-plugin-sdk/compare/v2.6.1...v2.7.0) --- updated-dependencies: - dependency-name: github.com/hashicorp/terraform-plugin-sdk/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 3 ++- go.sum | 50 ++++++++++++++++++++++++++++---------------------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index 5375fd44f872..0a0a95874679 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws go 1.16 require ( + github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect github.com/aws/aws-sdk-go v1.38.68 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect @@ -11,7 +12,7 @@ require ( github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-version v1.3.0 - github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 + github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 github.com/jen20/awspolicyequivalence v1.1.0 github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba github.com/mattn/go-colorable v0.1.7 // indirect diff --git a/go.sum b/go.sum index d739790c8b05..e9f95cdd37d9 100644 --- a/go.sum +++ b/go.sum @@ -40,12 +40,15 @@ github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuN github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U= @@ -96,12 +99,12 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.1.0 h1:4pl5BV4o7ZG/lterP4S6WzJ6xr49Ba5ET9ygheTYahk= -github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc= -github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -144,8 +147,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs= @@ -183,8 +186,8 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= -github.com/hashicorp/go-plugin v1.4.0 h1:b0O7rs5uiJ99Iu9HugEzsM67afboErkHUWddUSpUO3A= -github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= +github.com/hashicorp/go-plugin v1.4.1 h1:6UltRQlLN9iZO513VveELp5xyaFxVD2+1OVylE+2E+w= +github.com/hashicorp/go-plugin v1.4.1/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -199,14 +202,14 @@ github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggU github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/terraform-exec v0.13.3 h1:R6L2mNpDGSEqtLrSONN8Xth0xYwNrnEVzDz6LF/oJPk= -github.com/hashicorp/terraform-exec v0.13.3/go.mod h1:SSg6lbUsVB3DmFyCPjBPklqf6EYGX0TlQ6QTxOlikDU= -github.com/hashicorp/terraform-json v0.10.0 h1:9syPD/Y5t+3uFjG8AiWVPu1bklJD8QB8iTCaJASc8oQ= -github.com/hashicorp/terraform-json v0.10.0/go.mod h1:3defM4kkMfttwiE7VakJDwCd4R+umhSQnvJwORXbprE= +github.com/hashicorp/terraform-exec v0.14.0 h1:UQoUcxKTZZXhyyK68Cwn4mApT4mnFPmEXPiqaHL9r+w= +github.com/hashicorp/terraform-exec v0.14.0/go.mod h1:qrAASDq28KZiMPDnQ02sFS9udcqEkRly002EA2izXTA= +github.com/hashicorp/terraform-json v0.12.0 h1:8czPgEEWWPROStjkWPUnTQDXmpmZPlkQAwYYLETaTvw= +github.com/hashicorp/terraform-json v0.12.0/go.mod h1:pmbq9o4EuL43db5+0ogX10Yofv1nozM+wskr/bGFJpI= github.com/hashicorp/terraform-plugin-go v0.3.0 h1:AJqYzP52JFYl9NABRI7smXI1pNjgR5Q/y2WyVJ/BOZA= github.com/hashicorp/terraform-plugin-go v0.3.0/go.mod h1:dFHsQMaTLpON2gWhVWT96fvtlc/MF1vSy3OdMhWBzdM= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 h1:OZ+Q7irJBDhb71XzMSPGJvTIW101sOmbDg5i5qV1odY= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1/go.mod h1:72j8cKfs9IirGhPMXJJWLTvRUK4zATtrCOvs2avDlo8= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 h1:SuI59MqNjYDrL7EfqHX9V6P/24isgqYx/FdglwVs9bg= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0/go.mod h1:grseeRo9g3yNkYW09iFlV8LG78jTa1ssBgouogQg/RU= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= @@ -250,6 +253,7 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= @@ -281,7 +285,6 @@ github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -299,6 +302,7 @@ github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs= github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= @@ -328,8 +332,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.8.2 h1:u+xZfBKgpycDnTNjPhGiTEYZS5qS/Sb5MqSfm7vzcjg= -github.com/zclconf/go-cty v1.8.2/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.8.4 h1:pwhhz5P+Fjxse7S7UriBrMu6AUJSZM5pKqGem1PjGAs= +github.com/zclconf/go-cty v1.8.4/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -345,8 +349,9 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -458,8 +463,9 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 h1:RX8C8PRZc2hTIod4ds8ij+/4RQX3AqhYj3uOHmyaz4E= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From f6aaa7d746f18ed7264ae968da2e2c7b3eb63542 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 28 Jun 2021 11:04:45 -0400 Subject: [PATCH 0782/1208] Add CHANGELOG entry. --- .changelog/19946.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19946.txt diff --git a/.changelog/19946.txt b/.changelog/19946.txt new file mode 100644 index 000000000000..c84317ee59a3 --- /dev/null +++ b/.changelog/19946.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_cloudwatch_event_target: Don't crash if `sqs_target` configuration block is empty. +``` \ No newline at end of file From 63197efc80c7ce0ef3dee8b00fd01c439649b0f6 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Mon, 28 Jun 2021 18:30:50 +0300 Subject: [PATCH 0783/1208] Apply suggestions from code review Co-authored-by: Kit Ewbank --- aws/resource_aws_fsx_windows_file_system.go | 6 +++--- aws/resource_aws_fsx_windows_file_system_test.go | 6 +++--- website/docs/r/fsx_windows_file_system.html.markdown | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_fsx_windows_file_system.go b/aws/resource_aws_fsx_windows_file_system.go index 4670e18b6650..1dbf1f7dae05 100644 --- a/aws/resource_aws_fsx_windows_file_system.go +++ b/aws/resource_aws_fsx_windows_file_system.go @@ -54,7 +54,7 @@ func resourceAwsFsxWindowsFileSystem() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "audit_log_destionation": { + "audit_log_destination": { Type: schema.TypeString, Optional: true, Computed: true, @@ -574,7 +574,7 @@ func expandFsxWindowsAuditLogCreateConfiguration(l []interface{}) *fsx.WindowsAu FileShareAccessAuditLogLevel: aws.String(data["file_share_access_audit_log_level"].(string)), } - if v, ok := data["audit_log_destionation"].(string); ok && v != "" { + if v, ok := data["audit_log_destination"].(string); ok && v != "" { req.AuditLogDestination = aws.String(fsxWindowsAuditLogStateFunc(v)) } @@ -592,7 +592,7 @@ func flattenFsxWindowsAuditLogConfiguration(adopts *fsx.WindowsAuditLogConfigura } if adopts.AuditLogDestination != nil { - m["audit_log_destionation"] = aws.StringValue(adopts.AuditLogDestination) + m["audit_log_destination"] = aws.StringValue(adopts.AuditLogDestination) } return []map[string]interface{}{m} diff --git a/aws/resource_aws_fsx_windows_file_system_test.go b/aws/resource_aws_fsx_windows_file_system_test.go index 3829430f1d27..bffc1765b784 100644 --- a/aws/resource_aws_fsx_windows_file_system_test.go +++ b/aws/resource_aws_fsx_windows_file_system_test.go @@ -724,7 +724,7 @@ func TestAccAWSFsxWindowsFileSystem_auditConfig(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.0.file_access_audit_log_level", "SUCCESS_ONLY"), resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.0.file_share_access_audit_log_level", "SUCCESS_ONLY"), - resource.TestCheckResourceAttrSet(resourceName, "audit_log_configuration.0.audit_log_destionation"), + resource.TestCheckResourceAttrSet(resourceName, "audit_log_configuration.0.audit_log_destination"), ), }, { @@ -743,7 +743,7 @@ func TestAccAWSFsxWindowsFileSystem_auditConfig(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.0.file_access_audit_log_level", "SUCCESS_AND_FAILURE"), resource.TestCheckResourceAttr(resourceName, "audit_log_configuration.0.file_share_access_audit_log_level", "SUCCESS_AND_FAILURE"), - resource.TestCheckResourceAttrSet(resourceName, "audit_log_configuration.0.audit_log_destionation"), + resource.TestCheckResourceAttrSet(resourceName, "audit_log_configuration.0.audit_log_destination"), ), }, }, @@ -1192,7 +1192,7 @@ resource "aws_fsx_windows_file_system" "test" { throughput_capacity = 32 audit_log_configuration { - audit_log_destionation = aws_cloudwatch_log_group.test.arn + audit_log_destination = aws_cloudwatch_log_group.test.arn file_access_audit_log_level = %[2]q file_share_access_audit_log_level = %[2]q } diff --git a/website/docs/r/fsx_windows_file_system.html.markdown b/website/docs/r/fsx_windows_file_system.html.markdown index d62b97f8fc5f..4378b8970412 100644 --- a/website/docs/r/fsx_windows_file_system.html.markdown +++ b/website/docs/r/fsx_windows_file_system.html.markdown @@ -83,7 +83,7 @@ The following arguments are supported for `self_managed_active_directory` config ### audit_log_configuration -* `audit_log_destionation` - (Optional) The Amazon Resource Name (ARN) for the destination of the audit logs. The destination can be any Amazon CloudWatch Logs log group ARN or Amazon Kinesis Data Firehose delivery stream ARN. Can be specified when `file_access_audit_log_level` and `file_share_access_audit_log_level` are not set to `DISABLED`. The name of the Amazon CloudWatch Logs log group must begin with the `/aws/fsx` prefix. The name of the Amazon Kinesis Data Firehouse delivery stream must begin with the `aws-fsx` prefix. If you do not provide a destination in `audit_log_destionation`, Amazon FSx will create and use a log stream in the CloudWatch Logs /aws/fsx/windows log group. +* `audit_log_destination` - (Optional) The Amazon Resource Name (ARN) for the destination of the audit logs. The destination can be any Amazon CloudWatch Logs log group ARN or Amazon Kinesis Data Firehose delivery stream ARN. Can be specified when `file_access_audit_log_level` and `file_share_access_audit_log_level` are not set to `DISABLED`. The name of the Amazon CloudWatch Logs log group must begin with the `/aws/fsx` prefix. The name of the Amazon Kinesis Data Firehouse delivery stream must begin with the `aws-fsx` prefix. If you do not provide a destination in `audit_log_destionation`, Amazon FSx will create and use a log stream in the CloudWatch Logs /aws/fsx/windows log group. * `file_access_audit_log_level` - (Optional) Sets which attempt type is logged by Amazon FSx for file and folder accesses. Valid values are `SUCCESS_ONLY`, `FAILURE_ONLY`, `SUCCESS_AND_FAILURE`, and `DISABLED`. Default value is `DISABLED`. * `file_share_access_audit_log_level` - (Optional) Sets which attempt type is logged by Amazon FSx for file share accesses. Valid values are `SUCCESS_ONLY`, `FAILURE_ONLY`, `SUCCESS_AND_FAILURE`, and `DISABLED`. Default value is `DISABLED`. From 243cfb5ea8d198fb6daf258ae3ca6544ea4a40ad Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 28 Jun 2021 18:36:18 +0300 Subject: [PATCH 0784/1208] fmt --- aws/resource_aws_fsx_windows_file_system_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_fsx_windows_file_system_test.go b/aws/resource_aws_fsx_windows_file_system_test.go index bffc1765b784..20b4b679c8eb 100644 --- a/aws/resource_aws_fsx_windows_file_system_test.go +++ b/aws/resource_aws_fsx_windows_file_system_test.go @@ -1192,7 +1192,7 @@ resource "aws_fsx_windows_file_system" "test" { throughput_capacity = 32 audit_log_configuration { - audit_log_destination = aws_cloudwatch_log_group.test.arn + audit_log_destination = aws_cloudwatch_log_group.test.arn file_access_audit_log_level = %[2]q file_share_access_audit_log_level = %[2]q } From d9aab916290f3f28763f8ef0465f8e3e8eb57dd5 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 4 Apr 2021 12:43:17 +0300 Subject: [PATCH 0785/1208] retention policy for efs file system --- aws/resource_aws_sagemaker_app_test.go | 4 + aws/resource_aws_sagemaker_domain.go | 38 +++++- aws/resource_aws_sagemaker_domain_test.go | 118 +++++++++++++----- ...esource_aws_sagemaker_user_profile_test.go | 4 + website/docs/r/sagemaker_domain.html.markdown | 5 + 5 files changed, 136 insertions(+), 33 deletions(-) diff --git a/aws/resource_aws_sagemaker_app_test.go b/aws/resource_aws_sagemaker_app_test.go index 5870e50db72c..0cf5787350e2 100644 --- a/aws/resource_aws_sagemaker_app_test.go +++ b/aws/resource_aws_sagemaker_app_test.go @@ -318,6 +318,10 @@ resource "aws_sagemaker_domain" "test" { default_user_settings { execution_role = aws_iam_role.test.arn } + + retention_policy { + home_efs_file_system = "Delete" + } } resource "aws_sagemaker_user_profile" "test" { diff --git a/aws/resource_aws_sagemaker_domain.go b/aws/resource_aws_sagemaker_domain.go index 4ca348eb6079..175d35b15bb7 100644 --- a/aws/resource_aws_sagemaker_domain.go +++ b/aws/resource_aws_sagemaker_domain.go @@ -226,6 +226,22 @@ func resourceAwsSagemakerDomain() *schema.Resource { }, "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), + "retention_policy": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "home_efs_file_system": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(sagemaker.RetentionType_Values(), false), + Default: sagemaker.RetentionTypeRetain, + }, + }, + }, + }, "url": { Type: schema.TypeString, Computed: true, @@ -377,9 +393,10 @@ func resourceAwsSagemakerDomainDelete(d *schema.ResourceData, meta interface{}) input := &sagemaker.DeleteDomainInput{ DomainId: aws.String(d.Id()), - RetentionPolicy: &sagemaker.RetentionPolicy{ - HomeEfsFileSystem: aws.String(sagemaker.RetentionTypeDelete), - }, + } + + if v, ok := d.GetOk("retention_policy"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.RetentionPolicy = expandSagemakerRetentionPolicy(v.([]interface{})) } if _, err := conn.DeleteDomain(input); err != nil { @@ -396,6 +413,21 @@ func resourceAwsSagemakerDomainDelete(d *schema.ResourceData, meta interface{}) return nil } +func expandSagemakerRetentionPolicy(l []interface{}) *sagemaker.RetentionPolicy { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &sagemaker.RetentionPolicy{} + + if v, ok := m["home_efs_file_system"].(string); ok && v != "" { + config.HomeEfsFileSystem = aws.String(v) + } + + return config +} func expandSagemakerDomainDefaultUserSettings(l []interface{}) *sagemaker.UserSettings { if len(l) == 0 || l[0] == nil { diff --git a/aws/resource_aws_sagemaker_domain_test.go b/aws/resource_aws_sagemaker_domain_test.go index 793e7949726e..fa54d8718ec4 100644 --- a/aws/resource_aws_sagemaker_domain_test.go +++ b/aws/resource_aws_sagemaker_domain_test.go @@ -142,9 +142,10 @@ func testAccAWSSagemakerDomain_basic(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, }, }, }) @@ -169,9 +170,10 @@ func testAccAWSSagemakerDomain_kms(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, }, }, }) @@ -197,9 +199,10 @@ func testAccAWSSagemakerDomain_tags(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, }, { Config: testAccAWSSagemakerDomainConfigTags2(rName, "key1", "value1updated", "key2", "value2"), @@ -242,9 +245,10 @@ func testAccAWSSagemakerDomain_securityGroup(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, }, { Config: testAccAWSSagemakerDomainConfigSecurityGroup2(rName), @@ -281,9 +285,10 @@ func testAccAWSSagemakerDomain_sharingSettings(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, }, }, }) @@ -311,9 +316,10 @@ func testAccAWSSagemakerDomain_tensorboardAppSettings(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, }, }, }) @@ -342,9 +348,10 @@ func testAccAWSSagemakerDomain_tensorboardAppSettingsWithImage(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, }, }, }) @@ -372,9 +379,10 @@ func testAccAWSSagemakerDomain_kernelGatewayAppSettings(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, }, }, }) @@ -410,9 +418,10 @@ func testAccAWSSagemakerDomain_kernelGatewayAppSettings_customImage(t *testing.T ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, }, }, }) @@ -440,9 +449,10 @@ func testAccAWSSagemakerDomain_jupyterServerAppSettings(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, }, }, }) @@ -582,6 +592,10 @@ resource "aws_sagemaker_domain" "test" { default_user_settings { execution_role = aws_iam_role.test.arn } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName) } @@ -603,6 +617,10 @@ resource "aws_sagemaker_domain" "test" { default_user_settings { execution_role = aws_iam_role.test.arn } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName) } @@ -623,6 +641,10 @@ resource "aws_sagemaker_domain" "test" { execution_role = aws_iam_role.test.arn security_groups = [aws_security_group.test.id] } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName) } @@ -647,6 +669,10 @@ resource "aws_sagemaker_domain" "test" { execution_role = aws_iam_role.test.arn security_groups = [aws_security_group.test.id, aws_security_group.test2.id] } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName) } @@ -663,6 +689,10 @@ resource "aws_sagemaker_domain" "test" { execution_role = aws_iam_role.test.arn } + retention_policy { + home_efs_file_system = "Delete" + } + tags = { %[2]q = %[3]q } @@ -682,6 +712,10 @@ resource "aws_sagemaker_domain" "test" { execution_role = aws_iam_role.test.arn } + retention_policy { + home_efs_file_system = "Delete" + } + tags = { %[2]q = %[3]q %[4]q = %[5]q @@ -718,6 +752,10 @@ resource "aws_sagemaker_domain" "test" { s3_output_path = "s3://${aws_s3_bucket.test.bucket}/sharing" } } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName) } @@ -739,6 +777,10 @@ resource "aws_sagemaker_domain" "test" { } } } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName) } @@ -766,6 +808,10 @@ resource "aws_sagemaker_domain" "test" { } } } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName) } @@ -787,6 +833,10 @@ resource "aws_sagemaker_domain" "test" { } } } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName) } @@ -808,6 +858,10 @@ resource "aws_sagemaker_domain" "test" { } } } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName) } @@ -852,6 +906,10 @@ resource "aws_sagemaker_domain" "test" { } } } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName, baseImage) } diff --git a/aws/resource_aws_sagemaker_user_profile_test.go b/aws/resource_aws_sagemaker_user_profile_test.go index 1aa633c7923c..eb5b2f10d1ae 100644 --- a/aws/resource_aws_sagemaker_user_profile_test.go +++ b/aws/resource_aws_sagemaker_user_profile_test.go @@ -389,6 +389,10 @@ resource "aws_sagemaker_domain" "test" { default_user_settings { execution_role = aws_iam_role.test.arn } + + retention_policy { + home_efs_file_system = "Delete" + } } `, rName) } diff --git a/website/docs/r/sagemaker_domain.html.markdown b/website/docs/r/sagemaker_domain.html.markdown index 2bd8a25252d3..af437b6ce215 100644 --- a/website/docs/r/sagemaker_domain.html.markdown +++ b/website/docs/r/sagemaker_domain.html.markdown @@ -95,6 +95,7 @@ The following arguments are supported: * `vpc_id` - (Required) The ID of the Amazon Virtual Private Cloud (VPC) that Studio uses for communication. * `subnet_ids` - (Required) The VPC subnets that Studio uses for communication. * `default_user_settings` - (Required) The default user settings. See [Default User Settings](#default-user-settings) below. +* `retention_policy` - (Optional) The retention policy for this domain, which specifies whether resources will be retained after the Domain is deleted. By default, all resources are retained. See [Retention Policy](#retention-policy) below. * `kms_key_id` - (Optional) The AWS KMS customer managed CMK used to encrypt the EFS volume attached to the domain. * `app_network_access_type` - (Optional) Specifies the VPC used for non-EFS traffic. The default value is `PublicInternetOnly`. Valid values are `PublicInternetOnly` and `VpcOnly`. * `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. @@ -138,6 +139,10 @@ The following arguments are supported: * `image_name` - (Required) The name of the Custom Image. * `image_version_number` - (Optional) The version number of the Custom Image. +### Retention Policy + +* `home_efs_file_system` - (Optional) The retention policy for data stored on an Amazon Elastic File System (EFS) volume. Default value is `Retain`. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From dac2336620914bb219726cd8d965398709e88bb0 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 4 Apr 2021 12:54:17 +0300 Subject: [PATCH 0786/1208] changelog --- .changelog/18562.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/18562.txt diff --git a/.changelog/18562.txt b/.changelog/18562.txt new file mode 100644 index 000000000000..7d25f37b7a3c --- /dev/null +++ b/.changelog/18562.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_sagemaker_domain: Add support for `retention_policy` +``` \ No newline at end of file From 1c21d36013e7076339f3873fd1fee6a578820e13 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 4 Apr 2021 13:02:09 +0300 Subject: [PATCH 0787/1208] lint --- aws/resource_aws_sagemaker_domain_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_sagemaker_domain_test.go b/aws/resource_aws_sagemaker_domain_test.go index fa54d8718ec4..feb635451eba 100644 --- a/aws/resource_aws_sagemaker_domain_test.go +++ b/aws/resource_aws_sagemaker_domain_test.go @@ -620,7 +620,7 @@ resource "aws_sagemaker_domain" "test" { retention_policy { home_efs_file_system = "Delete" - } + } } `, rName) } @@ -644,7 +644,7 @@ resource "aws_sagemaker_domain" "test" { retention_policy { home_efs_file_system = "Delete" - } + } } `, rName) } @@ -672,7 +672,7 @@ resource "aws_sagemaker_domain" "test" { retention_policy { home_efs_file_system = "Delete" - } + } } `, rName) } From 4b0ec2639709534f4ab106af3385f95b132de83b Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 27 Jun 2021 08:48:16 +0300 Subject: [PATCH 0788/1208] add ecs params --- aws/resource_aws_cloudwatch_event_target.go | 140 +++++++++++++++++++- 1 file changed, 133 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index 122ffbf7f8a7..b9c8722ead33 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" tfevents "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudwatchevents/finder" ) @@ -137,6 +138,16 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "enable_ecs_managed_tags": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "enable_execute_command": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, "group": { Type: schema.TypeString, Optional: true, @@ -175,11 +186,37 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource { }, }, }, + "placement_constraints": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "expression": { + Type: schema.TypeString, + Optional: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(events.PlacementConstraintType_Values(), false), + }, + }, + }, + }, "platform_version": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringLenBetween(0, 1600), }, + "propagate_tags": { + Type: schema.TypeString, + Optional: true, + Default: events.PropagateTagsTaskDefinition, + ValidateFunc: validation.StringInSlice(events.PropagateTags_Values(), false), + }, + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), "task_count": { Type: schema.TypeInt, Optional: true, @@ -331,7 +368,7 @@ func resourceAwsCloudWatchEventTargetCreate(d *schema.ResourceData, meta interfa busName = v.(string) } - input := buildPutTargetInputStruct(d) + input := buildPutTargetInputStruct(d, meta) log.Printf("[DEBUG] Creating CloudWatch Events Target: %s", input) out, err := conn.PutTargets(input) @@ -391,7 +428,7 @@ func resourceAwsCloudWatchEventTargetRead(d *schema.ResourceData, meta interface } if t.EcsParameters != nil { - if err := d.Set("ecs_target", flattenAwsCloudWatchEventTargetEcsParameters(t.EcsParameters)); err != nil { + if err := d.Set("ecs_target", flattenAwsCloudWatchEventTargetEcsParameters(t.EcsParameters, meta)); err != nil { return fmt.Errorf("Error setting ecs_target error: %w", err) } } @@ -438,7 +475,7 @@ func resourceAwsCloudWatchEventTargetRead(d *schema.ResourceData, meta interface func resourceAwsCloudWatchEventTargetUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).cloudwatcheventsconn - input := buildPutTargetInputStruct(d) + input := buildPutTargetInputStruct(d, meta) log.Printf("[DEBUG] Updating CloudWatch Events Target: %s", input) _, err := conn.PutTargets(input) @@ -477,7 +514,7 @@ func resourceAwsCloudWatchEventTargetDelete(d *schema.ResourceData, meta interfa return nil } -func buildPutTargetInputStruct(d *schema.ResourceData) *events.PutTargetsInput { +func buildPutTargetInputStruct(d *schema.ResourceData, meta interface{}) *events.PutTargetsInput { e := &events.Target{ Arn: aws.String(d.Get("arn").(string)), Id: aws.String(d.Get("target_id").(string)), @@ -499,7 +536,7 @@ func buildPutTargetInputStruct(d *schema.ResourceData) *events.PutTargetsInput { } if v, ok := d.GetOk("ecs_target"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - e.EcsParameters = expandAwsCloudWatchEventTargetEcsParameters(v.([]interface{})) + e.EcsParameters = expandAwsCloudWatchEventTargetEcsParameters(v.([]interface{}), meta) } if v, ok := d.GetOk("http_target"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { @@ -559,22 +596,44 @@ func expandAwsCloudWatchEventTargetRunParameters(config []interface{}) *events.R return command } -func expandAwsCloudWatchEventTargetEcsParameters(config []interface{}) *events.EcsParameters { +func expandAwsCloudWatchEventTargetEcsParameters(config []interface{}, meta interface{}) *events.EcsParameters { + ecsParameters := &events.EcsParameters{} for _, c := range config { param := c.(map[string]interface{}) + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(param["tags"].(map[string]interface{}))) + if val, ok := param["group"].(string); ok && val != "" { ecsParameters.Group = aws.String(val) } + if val, ok := param["launch_type"].(string); ok && val != "" { ecsParameters.LaunchType = aws.String(val) } + if val, ok := param["network_configuration"]; ok { ecsParameters.NetworkConfiguration = expandAwsCloudWatchEventTargetEcsParametersNetworkConfiguration(val.([]interface{})) } + if val, ok := param["platform_version"].(string); ok && val != "" { ecsParameters.PlatformVersion = aws.String(val) } + + if v, ok := param["placement_constraints"].(*schema.Set); ok && v.Len() > 0 { + ecsParameters.PlacementConstraints = expandAwsCloudWatchEventTargetPlacementConstraints(v.List()) + } + + if v, ok := param["propagate_tags"].(string); ok { + ecsParameters.PropagateTags = aws.String(v) + } + + if len(tags) > 0 { + ecsParameters.Tags = tags.IgnoreAws().CloudwatcheventsTags() + } + + ecsParameters.EnableExecuteCommand = aws.Bool(param["enable_execute_command"].(bool)) + ecsParameters.EnableECSManagedTags = aws.Bool(param["enable_ecs_managed_tags"].(bool)) ecsParameters.TaskCount = aws.Int64(int64(param["task_count"].(int))) ecsParameters.TaskDefinitionArn = aws.String(param["task_definition_arn"].(string)) } @@ -735,18 +794,38 @@ func flattenAwsCloudWatchEventTargetRunParameters(runCommand *events.RunCommandP return result } -func flattenAwsCloudWatchEventTargetEcsParameters(ecsParameters *events.EcsParameters) []map[string]interface{} { +func flattenAwsCloudWatchEventTargetEcsParameters(ecsParameters *events.EcsParameters, meta interface{}) []map[string]interface{} { + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + config := make(map[string]interface{}) if ecsParameters.Group != nil { config["group"] = aws.StringValue(ecsParameters.Group) } + if ecsParameters.LaunchType != nil { config["launch_type"] = aws.StringValue(ecsParameters.LaunchType) } + config["network_configuration"] = flattenAwsCloudWatchEventTargetEcsParametersNetworkConfiguration(ecsParameters.NetworkConfiguration) if ecsParameters.PlatformVersion != nil { config["platform_version"] = aws.StringValue(ecsParameters.PlatformVersion) } + + if ecsParameters.PropagateTags != nil { + config["propagate_tags"] = aws.StringValue(ecsParameters.PropagateTags) + } + + if ecsParameters.PlacementConstraints != nil { + config["placement_constraints"] = flattenAwsCloudWatchEventTargetPlacementConstraints(ecsParameters.PlacementConstraints) + } + + tags := keyvaluetags.CloudwatcheventsKeyValueTags(ecsParameters.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + config["tags"] = tags.RemoveDefaultConfig(defaultTagsConfig).Map() + config["tags_all"] = tags.Map() + + config["enable_execute_command"] = aws.BoolValue(ecsParameters.EnableExecuteCommand) + config["enable_ecs_managed_tags"] = aws.BoolValue(ecsParameters.EnableECSManagedTags) config["task_count"] = aws.Int64Value(ecsParameters.TaskCount) config["task_definition_arn"] = aws.StringValue(ecsParameters.TaskDefinitionArn) result := []map[string]interface{}{config} @@ -851,6 +930,53 @@ func flatternAwsCloudWatchEventTargetDeadLetterConfig(dlc *events.DeadLetterConf return result } +func expandAwsCloudWatchEventTargetPlacementConstraints(tfList []interface{}) []*events.PlacementConstraint { + if len(tfList) == 0 { + return nil + } + + var result []*events.PlacementConstraint + + for _, tfMapRaw := range tfList { + if tfMapRaw == nil { + continue + } + + tfMap := tfMapRaw.(map[string]interface{}) + + apiObject := &events.PlacementConstraint{} + + if v, ok := tfMap["expression"].(string); ok && v != "" { + apiObject.Expression = aws.String(v) + } + + if v, ok := tfMap["type"].(string); ok && v != "" { + apiObject.Type = aws.String(v) + } + + result = append(result, apiObject) + } + + return result +} + +func flattenAwsCloudWatchEventTargetPlacementConstraints(pcs []*events.PlacementConstraint) []map[string]interface{} { + if len(pcs) == 0 { + return nil + } + results := make([]map[string]interface{}, 0) + for _, pc := range pcs { + c := make(map[string]interface{}) + c["type"] = aws.StringValue(pc.Type) + if pc.Expression != nil { + c["expression"] = aws.StringValue(pc.Expression) + } + + results = append(results, c) + } + return results +} + func resourceAwsCloudWatchEventTargetImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { busName, ruleName, targetID, err := tfevents.TargetParseImportID(d.Id()) if err != nil { From 5d9a48438f315c94790b647e386837556100d639 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 27 Jun 2021 11:19:44 +0300 Subject: [PATCH 0789/1208] docs --- .../r/cloudwatch_event_target.html.markdown | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/website/docs/r/cloudwatch_event_target.html.markdown b/website/docs/r/cloudwatch_event_target.html.markdown index 9e97e856faf3..7e32f1e4c03d 100644 --- a/website/docs/r/cloudwatch_event_target.html.markdown +++ b/website/docs/r/cloudwatch_event_target.html.markdown @@ -344,12 +344,12 @@ The following arguments are supported: * `retry_policy` - (Optional) Parameters used when you are providing retry policies. Documented below. A maximum of 1 are allowed. * `dead_letter_config` - (Optional) Parameters used when you are providing a dead letter config. Documented below. A maximum of 1 are allowed. -`run_command_targets` support the following: +### run_command_targets * `key` - (Required) Can be either `tag:tag-key` or `InstanceIds`. * `values` - (Required) If Key is `tag:tag-key`, Values is a list of tag values. If Key is `InstanceIds`, Values is a list of Amazon EC2 instance IDs. -`ecs_target` support the following: +### ecs_target * `group` - (Optional) Specifies an ECS task group for the task. The maximum length is 255 characters. * `launch_type` - (Optional) Specifies the launch type on which your task is running. The launch type that you specify here must match one of the launch type (compatibilities) of the target task. Valid values include: an empty string `""` (to specify no launch type), `EC2`, or `FARGATE`. @@ -357,8 +357,13 @@ The following arguments are supported: * `platform_version` - (Optional) Specifies the platform version for the task. Specify only the numeric portion of the platform version, such as 1.1.0. This is used only if LaunchType is FARGATE. For more information about valid platform versions, see [AWS Fargate Platform Versions](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html). * `task_count` - (Optional) The number of tasks to create based on the TaskDefinition. The default is 1. * `task_definition_arn` - (Required) The ARN of the task definition to use if the event target is an Amazon ECS cluster. +* `tags` - (Optional) A map of tags to assign to ecs resources. 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. +* `propagate_tags` - (Optional) Specifies whether to propagate the tags from the task definition to the task. If no value is specified, the tags are not propagated. Tags can only be propagated to the task during task creation. +* `placement_constraints` - (Optional) An array of placement constraint objects to use for the task. You can specify up to 10 constraints per task (including constraints in the task definition and those specified at runtime). See Below. +* `enable_execute_command` - (Optional) Whether or not to enable the execute command functionality for the containers in this task. If true, this enables execute command functionality on all containers in the task. +* `enable_ecs_managed_tags` - (Optional) Specifies whether to enable Amazon ECS managed tags for the task. -`network_configuration` support the following: +#### network_configuration * `subnets` - (Required) The subnets associated with the task or service. * `security_groups` - (Optional) The security groups associated with the task or service. If you do not specify a security group, the default security group for the VPC is used. @@ -366,18 +371,23 @@ The following arguments are supported: For more information, see [Task Networking](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html) -`batch_target` support the following: +#### placement_constraints + +* `type` - (Required) Type of constraint. The only valid values at this time are `memberOf` and `distinctInstance`. +* `expression` - (Optional) Cluster Query Language expression to apply to the constraint. Does not need to be specified for the `distinctInstance` type. For more information, see [Cluster Query Language in the Amazon EC2 Container Service Developer Guide](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-query-language.html). + +### batch_target * `job_definition` - (Required) The ARN or name of the job definition to use if the event target is an AWS Batch job. This job definition must already exist. * `job_name` - (Required) The name to use for this execution of the job, if the target is an AWS Batch job. * `array_size` - (Optional) The size of the array, if this is an array batch job. Valid values are integers between 2 and 10,000. * `job_attempts` - (Optional) The number of times to attempt to retry, if the job fails. Valid values are 1 to 10. -`kinesis_target` support the following: +### kinesis_target * `partition_key_path` - (Optional) The JSON path to be extracted from the event and used as the partition key. -`sqs_target` support the following: +### sqs_target * `message_group_id` - (Optional) The FIFO message group ID to use as the target. @@ -387,7 +397,7 @@ For more information, see [Task Networking](https://docs.aws.amazon.com/AmazonEC * `query_string_parameters` - (Optional) Represents keys/values of query string parameters that are appended to the invoked endpoint. * `header_parameters` - (Optional) Enables you to specify HTTP headers to add to the request. -`input_transformer` support the following: +### input_transformer * `input_paths` - (Optional) Key value pairs specified in the form of JSONPath (for example, time = $.time) * You can have as many as 100 key-value pairs. @@ -396,12 +406,12 @@ For more information, see [Task Networking](https://docs.aws.amazon.com/AmazonEC * `input_template` - (Required) Template to customize data sent to the target. Must be valid JSON. To send a string value, the string value must include double quotes. Values must be escaped for both JSON and Terraform, e.g. `"\"Your string goes here.\\nA new line.\""` -`retry_policy` support the following: +### retry_policy * `maximum_event_age_in_seconds` - (Optional) The age in seconds to continue to make retry attempts. * `maximum_retry_attempts` - (Optional) maximum number of retry attempts to make before the request fails -`dead_letter_config` support the following: +### dead_letter_config * `arn` - (Optional) - ARN of the SQS queue specified as the target for the dead-letter queue. From 2f7d26ebd9081d17385685ca5eb1ffc70940a476 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 27 Jun 2021 11:25:21 +0300 Subject: [PATCH 0790/1208] changelog --- .changelog/19975.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19975.txt diff --git a/.changelog/19975.txt b/.changelog/19975.txt new file mode 100644 index 000000000000..af62320796df --- /dev/null +++ b/.changelog/19975.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_cloudwatch_event_target: Add `enable_ecs_managed_tags`, `enable_execute_command`, `placement_constraints`, `propagate_tags`, and `tags` arguments to `ecs_target` block. +``` \ No newline at end of file From e6d217e3ed935bcfab4da277690f7a7cb7d7f197 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 27 Jun 2021 14:13:25 +0300 Subject: [PATCH 0791/1208] test --- ...source_aws_cloudwatch_event_target_test.go | 261 ++++++------------ 1 file changed, 82 insertions(+), 179 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target_test.go b/aws/resource_aws_cloudwatch_event_target_test.go index c218afcbeafc..2426e09e423a 100644 --- a/aws/resource_aws_cloudwatch_event_target_test.go +++ b/aws/resource_aws_cloudwatch_event_target_test.go @@ -536,6 +536,43 @@ func TestAccAWSCloudWatchEventTarget_ecsWithBlankTaskCount(t *testing.T) { }) } +func TestAccAWSCloudWatchEventTarget_ecsFull(t *testing.T) { + resourceName := "aws_cloudwatch_event_target.test" + var v events.Target + rName := acctest.RandomWithPrefix("tf_ecs_target") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, events.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCloudWatchEventTargetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudWatchEventTargetConfigEcsWithBlankTaskCountFull(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudWatchEventTargetExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "ecs_target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.task_count", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.launch_type", "FARGATE"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.enable_execute_command", "true"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.enable_ecs_managed_tags", "true"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.propagate_tags", "TASK_DEFINITION"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.placement_constraints.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.placement_constraints.0.type", "distinctInstance"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.tags.test", "test1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAWSCloudWatchEventTargetImportStateIdFunc(resourceName), + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSCloudWatchEventTarget_batch(t *testing.T) { resourceName := "aws_cloudwatch_event_target.test" batchJobDefinitionResourceName := "aws_batch_job_definition.test" @@ -1212,15 +1249,8 @@ data "aws_partition" "current" {} `, rName) } -func testAccAWSCloudWatchEventTargetConfigEcs(rName string) string { +func testAccAWSCloudWatchEventTargetConfigEcsBase(rName string) string { return fmt.Sprintf(` -resource "aws_cloudwatch_event_rule" "test" { - name = %[1]q - description = "schedule_ecs_test" - - schedule_expression = "rate(5 minutes)" -} - resource "aws_vpc" "vpc" { cidr_block = "10.1.0.0/16" } @@ -1230,22 +1260,6 @@ resource "aws_subnet" "subnet" { cidr_block = "10.1.1.0/24" } -resource "aws_cloudwatch_event_target" "test" { - arn = aws_ecs_cluster.test.id - rule = aws_cloudwatch_event_rule.test.id - role_arn = aws_iam_role.test.arn - - ecs_target { - task_count = 1 - task_definition_arn = aws_ecs_task_definition.task.arn - launch_type = "FARGATE" - - network_configuration { - subnets = [aws_subnet.subnet.id] - } - } -} - resource "aws_iam_role" "test" { name = %[1]q @@ -1313,27 +1327,18 @@ EOF } data "aws_partition" "current" {} -`, rName) -} -func testAccAWSCloudWatchEventTargetConfigEcsWithBlankLaunchType(rName string) string { - return fmt.Sprintf(` resource "aws_cloudwatch_event_rule" "test" { name = %[1]q description = "schedule_ecs_test" schedule_expression = "rate(5 minutes)" } - -resource "aws_vpc" "vpc" { - cidr_block = "10.1.0.0/16" -} - -resource "aws_subnet" "subnet" { - vpc_id = aws_vpc.vpc.id - cidr_block = "10.1.1.0/24" +`, rName) } +func testAccAWSCloudWatchEventTargetConfigEcs(rName string) string { + return testAccAWSCloudWatchEventTargetConfigEcsBase(rName) + ` resource "aws_cloudwatch_event_target" "test" { arn = aws_ecs_cluster.test.id rule = aws_cloudwatch_event_rule.test.id @@ -1342,102 +1347,38 @@ resource "aws_cloudwatch_event_target" "test" { ecs_target { task_count = 1 task_definition_arn = aws_ecs_task_definition.task.arn - launch_type = "" + launch_type = "FARGATE" network_configuration { subnets = [aws_subnet.subnet.id] } } } - -resource "aws_iam_role" "test" { - name = %[1]q - - assume_role_policy = < Date: Sun, 27 Jun 2021 14:19:35 +0300 Subject: [PATCH 0792/1208] fmt --- aws/resource_aws_cloudwatch_event_target_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target_test.go b/aws/resource_aws_cloudwatch_event_target_test.go index 2426e09e423a..74dcace445ef 100644 --- a/aws/resource_aws_cloudwatch_event_target_test.go +++ b/aws/resource_aws_cloudwatch_event_target_test.go @@ -1414,9 +1414,9 @@ resource "aws_cloudwatch_event_target" "test" { type = "distinctInstance" } - tags = { + tags = { test = "test1" - } + } network_configuration { subnets = [aws_subnet.subnet.id] From c2f2b1dc016901982f9f1d8b9ce086f7acd2b442 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 28 Jun 2021 12:11:22 -0400 Subject: [PATCH 0793/1208] r/aws_eks_cluster: Don't associate an encryption_config if there's already one. --- aws/resource_aws_eks_cluster.go | 33 +++++++----- aws/resource_aws_eks_cluster_test.go | 81 ++++++++++++++++++++++++++-- 2 files changed, 97 insertions(+), 17 deletions(-) diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index 57737fdbb759..c13ed4eb7a9d 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -91,14 +91,15 @@ func resourceAwsEksCluster() *schema.Resource { "key_arn": { Type: schema.TypeString, Required: true, + ForceNew: true, }, }, }, }, "resources": { Type: schema.TypeSet, - MinItems: 1, Required: true, + ForceNew: true, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.StringInSlice(tfeks.Resources_Values(), false), @@ -409,24 +410,28 @@ func resourceAwsEksClusterUpdate(d *schema.ResourceData, meta interface{}) error } if d.HasChange("encryption_config") { - input := &eks.AssociateEncryptionConfigInput{ - ClusterName: aws.String(d.Id()), - EncryptionConfig: expandEksEncryptionConfig(d.Get("encryption_config").([]interface{})), - } + o, n := d.GetChange("encryption_config") - log.Printf("[DEBUG] Associating EKS Cluster (%s) encryption config: %s", d.Id(), input) - output, err := conn.AssociateEncryptionConfig(input) + if len(o.([]interface{})) == 0 && len(n.([]interface{})) == 1 { + input := &eks.AssociateEncryptionConfigInput{ + ClusterName: aws.String(d.Id()), + EncryptionConfig: expandEksEncryptionConfig(d.Get("encryption_config").([]interface{})), + } - if err != nil { - return fmt.Errorf("error associating EKS Cluster (%s) encryption config: %w", d.Id(), err) - } + log.Printf("[DEBUG] Associating EKS Cluster (%s) encryption config: %s", d.Id(), input) + output, err := conn.AssociateEncryptionConfig(input) - updateID := aws.StringValue(output.Update.Id) + if err != nil { + return fmt.Errorf("error associating EKS Cluster (%s) encryption config: %w", d.Id(), err) + } - _, err = waiter.ClusterUpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + updateID := aws.StringValue(output.Update.Id) - if err != nil { - return fmt.Errorf("error waiting for EKS Cluster (%s) encryption config association (%s): %w", d.Id(), updateID, err) + _, err = waiter.ClusterUpdateSuccessful(conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("error waiting for EKS Cluster (%s) encryption config association (%s): %w", d.Id(), updateID, err) + } } } diff --git a/aws/resource_aws_eks_cluster_test.go b/aws/resource_aws_eks_cluster_test.go index c78780531311..9ccc216fee5c 100644 --- a/aws/resource_aws_eks_cluster_test.go +++ b/aws/resource_aws_eks_cluster_test.go @@ -174,7 +174,7 @@ func TestAccAWSEksCluster_EncryptionConfig_Create(t *testing.T) { } func TestAccAWSEksCluster_EncryptionConfig_Update(t *testing.T) { - var cluster eks.Cluster + var cluster1, cluster2 eks.Cluster rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_cluster.test" kmsKeyResourceName := "aws_kms_key.test" @@ -188,14 +188,15 @@ func TestAccAWSEksCluster_EncryptionConfig_Update(t *testing.T) { { Config: testAccAWSEksClusterConfig_Required(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksClusterExists(resourceName, &cluster), + testAccCheckAWSEksClusterExists(resourceName, &cluster1), resource.TestCheckResourceAttr(resourceName, "encryption_config.#", "0"), ), }, { Config: testAccAWSEksClusterConfig_EncryptionConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksClusterExists(resourceName, &cluster), + testAccCheckAWSEksClusterExists(resourceName, &cluster2), + testAccCheckAWSEksClusterNotRecreated(&cluster1, &cluster2), resource.TestCheckResourceAttr(resourceName, "encryption_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "encryption_config.0.provider.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "encryption_config.0.provider.0.key_arn", kmsKeyResourceName, "arn"), @@ -211,6 +212,51 @@ func TestAccAWSEksCluster_EncryptionConfig_Update(t *testing.T) { }) } +// https://github.com/hashicorp/terraform-provider-aws/issues/19968. +func TestAccAWSEksCluster_EncryptionConfig_VersionUpdate(t *testing.T) { + var cluster1, cluster2 eks.Cluster + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_eks_cluster.test" + kmsKeyResourceName := "aws_kms_key.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEksClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksClusterConfig_EncryptionConfig_Version(rName, "1.19"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksClusterExists(resourceName, &cluster1), + resource.TestCheckResourceAttr(resourceName, "encryption_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "encryption_config.0.provider.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "encryption_config.0.provider.0.key_arn", kmsKeyResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "encryption_config.0.resources.#", "1"), + resource.TestCheckResourceAttr(resourceName, "version", "1.19"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSEksClusterConfig_EncryptionConfig_Version(rName, "1.20"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksClusterExists(resourceName, &cluster2), + testAccCheckAWSEksClusterNotRecreated(&cluster1, &cluster2), + resource.TestCheckResourceAttr(resourceName, "encryption_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "encryption_config.0.provider.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "encryption_config.0.provider.0.key_arn", kmsKeyResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "encryption_config.0.resources.#", "1"), + resource.TestCheckResourceAttr(resourceName, "version", "1.20"), + ), + }, + }, + }) +} + func TestAccAWSEksCluster_Version(t *testing.T) { var cluster1, cluster2 eks.Cluster rName := acctest.RandomWithPrefix("tf-acc-test") @@ -816,6 +862,35 @@ resource "aws_eks_cluster" "test" { `, rName)) } +func testAccAWSEksClusterConfig_EncryptionConfig_Version(rName, version string) string { + return composeConfig(testAccAWSEksClusterConfig_Base(rName), fmt.Sprintf(` +resource "aws_kms_key" "test" { + description = %[1]q + deletion_window_in_days = 7 +} + +resource "aws_eks_cluster" "test" { + name = %[1]q + role_arn = aws_iam_role.test.arn + version = %[2]q + + encryption_config { + resources = ["secrets"] + + provider { + key_arn = aws_kms_key.test.arn + } + } + + vpc_config { + subnet_ids = aws_subnet.test[*].id + } + + depends_on = [aws_iam_role_policy_attachment.test-AmazonEKSClusterPolicy] +} +`, rName, version)) +} + func testAccAWSEksClusterConfig_VpcConfig_SecurityGroupIds(rName string) string { return composeConfig(testAccAWSEksClusterConfig_Base(rName), fmt.Sprintf(` resource "aws_security_group" "test" { From 339252731fa13dea74be82acfc6bca4c2b9cfa27 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 28 Jun 2021 12:14:48 -0400 Subject: [PATCH 0794/1208] Add CHANGELOG entry. --- .changelog/19986.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19986.txt diff --git a/.changelog/19986.txt b/.changelog/19986.txt new file mode 100644 index 000000000000..0638db645e14 --- /dev/null +++ b/.changelog/19986.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_eks_cluster: Don't associate an `encryption_config` if there's already one +``` \ No newline at end of file From 1a02f9660c5ad2d8e7835efccab32bf0ae7c05d5 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 12:37:10 -0400 Subject: [PATCH 0795/1208] iam: Rename role finder for general use --- aws/internal/service/iam/finder/finder.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/internal/service/iam/finder/finder.go b/aws/internal/service/iam/finder/finder.go index 5b9065a6502d..78d8ef9b2845 100644 --- a/aws/internal/service/iam/finder/finder.go +++ b/aws/internal/service/iam/finder/finder.go @@ -112,8 +112,8 @@ func Policies(conn *iam.IAM, arn, name, pathPrefix string) ([]*iam.Policy, error return results, err } -// RoleARNByName returns a role's ARN given the role name -func RoleARNByName(conn *iam.IAM, name string) (*iam.Role, error) { +// RoleByName returns a role's ARN given the role name +func RoleByName(conn *iam.IAM, name string) (*iam.Role, error) { input := &iam.GetRoleInput{ RoleName: aws.String(name), } From 8abcda52f16e6e12bdcf634c81e3e3c2679931c2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 12:37:49 -0400 Subject: [PATCH 0796/1208] d/iam_assumed_role: Rework ARN helper function --- ...data_source_aws_iam_assumed_role_source.go | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/aws/data_source_aws_iam_assumed_role_source.go b/aws/data_source_aws_iam_assumed_role_source.go index e66db1381cf2..a6c810cbf8cc 100644 --- a/aws/data_source_aws_iam_assumed_role_source.go +++ b/aws/data_source_aws_iam_assumed_role_source.go @@ -55,8 +55,7 @@ func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interfac sessionName := "" var err error - if roleName, sessionName, err = roleSessionNameFromARN(arn); err != nil { - // errors purposely eaten to pass through ARN + if roleName, sessionName = roleNameSessionFromARN(arn); roleName == "" { d.Set("source_arn", arn) d.Set("session_name", "") d.Set("role_name", "") @@ -70,7 +69,7 @@ func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interfac err = resource.Retry(waiter.PropagationTimeout, func() *resource.RetryError { var err error - role, err = finder.RoleARNByName(conn, roleName) + role, err = finder.RoleByName(conn, roleName) if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) { return resource.RetryableError(err) @@ -84,7 +83,7 @@ func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interfac }) if tfresource.TimedOut(err) { - role, err = finder.RoleARNByName(conn, roleName) + role, err = finder.RoleByName(conn, roleName) } if err != nil { @@ -99,11 +98,13 @@ func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interfac return nil } -func roleSessionNameFromARN(rawARN string) (string, string, error) { +// roleNameSessionFromARN returns the role and session names in an ARN if any. +// Otherwise, it returns empty strings. +func roleNameSessionFromARN(rawARN string) (string, string) { parsedARN, err := arn.Parse(rawARN) if err != nil { - return "", "", fmt.Errorf("could not parse ARN (%s)", rawARN) + return "", "" } parts := strings.Split(parsedARN.Resource, "/") @@ -112,24 +113,24 @@ func roleSessionNameFromARN(rawARN string) (string, string, error) { reRole := regexp.MustCompile(`^role/.{1,}`) if reAssume.MatchString(parsedARN.Resource) && parsedARN.Service != "sts" { - return "", "", fmt.Errorf("assume role service must be STS (%s)", rawARN) + return "", "" } if reRole.MatchString(parsedARN.Resource) && parsedARN.Service != "iam" { - return "", "", fmt.Errorf("role service must be IAM (%s)", rawARN) + return "", "" } if !reAssume.MatchString(parsedARN.Resource) && !reRole.MatchString(parsedARN.Resource) { - return "", "", fmt.Errorf("not a role nor assumed role (%s)", rawARN) + return "", "" } if reRole.MatchString(parsedARN.Resource) && len(parts) > 1 { - return parts[len(parts)-1], "", nil + return parts[len(parts)-1], "" } if len(parts) < 3 { - return "", "", fmt.Errorf("not a valid assumed role (%s)", rawARN) + return "", "" } - return parts[len(parts)-2], parts[len(parts)-1], nil + return parts[len(parts)-2], parts[len(parts)-1] } From 074ec4e51d1917b87cb148f96625846d776cd60d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 12:38:11 -0400 Subject: [PATCH 0797/1208] tests/d/iam_assumed_role: Rework ARN helper function --- ...source_aws_iam_assumed_role_source_test.go | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/aws/data_source_aws_iam_assumed_role_source_test.go b/aws/data_source_aws_iam_assumed_role_source_test.go index 4b733b185e7c..10379b2eb999 100644 --- a/aws/data_source_aws_iam_assumed_role_source_test.go +++ b/aws/data_source_aws_iam_assumed_role_source_test.go @@ -22,84 +22,66 @@ func TestAssumedRoleRoleSessionName(t *testing.T) { ARN: "abcd", ExpectedRoleName: "", ExpectedSessionName: "", - ExpectedError: true, }, { Name: "regular role ARN", ARN: "arn:aws:iam::111122223333:role/role_name", //lintignore:AWSAT005 ExpectedRoleName: "role_name", ExpectedSessionName: "", - ExpectedError: false, }, { Name: "assumed role ARN", ARN: "arn:aws:sts::444433332222:assumed-role/something_something-admin/sessionIDNotPartOfRoleARN", //lintignore:AWSAT005 ExpectedRoleName: "something_something-admin", ExpectedSessionName: "sessionIDNotPartOfRoleARN", - ExpectedError: false, }, { Name: "'assumed-role' part of ARN resource", ARN: "arn:aws:iam::444433332222:user/assumed-role-but-not-really", //lintignore:AWSAT005 ExpectedRoleName: "", ExpectedSessionName: "", - ExpectedError: true, }, { Name: "user ARN", ARN: "arn:aws:iam::123456789012:user/Bob", //lintignore:AWSAT005 ExpectedRoleName: "", ExpectedSessionName: "", - ExpectedError: true, }, { Name: "assumed role from AWS example", ARN: "arn:aws:sts::123456789012:assumed-role/example-role/AWSCLI-Session", //lintignore:AWSAT005 ExpectedRoleName: "example-role", ExpectedSessionName: "AWSCLI-Session", - ExpectedError: false, }, { Name: "multiple slashes in resource", // not sure this is even valid ARN: "arn:aws:sts::123456789012:assumed-role/path/role-name/AWSCLI-Session", //lintignore:AWSAT005 ExpectedRoleName: "role-name", ExpectedSessionName: "AWSCLI-Session", - ExpectedError: false, }, { Name: "not an sts ARN", ARN: "arn:aws:iam::123456789012:assumed-role/example-role/AWSCLI-Session", //lintignore:AWSAT005 ExpectedRoleName: "", ExpectedSessionName: "", - ExpectedError: true, }, { Name: "role with path", ARN: "arn:aws:iam::123456789012:role/this/is/the/path/role-name", //lintignore:AWSAT005 ExpectedRoleName: "role-name", ExpectedSessionName: "", - ExpectedError: false, }, { Name: "wrong service", ARN: "arn:aws:ec2::123456789012:role/role-name", //lintignore:AWSAT005 ExpectedRoleName: "", ExpectedSessionName: "", - ExpectedError: true, }, } for _, testCase := range testCases { t.Run(testCase.Name, func(t *testing.T) { - role, session, err := roleSessionNameFromARN(testCase.ARN) - - if err != nil && !testCase.ExpectedError { - t.Errorf("for %s: got error (%s), expected none", testCase.ARN, err) - } - - if err == nil && testCase.ExpectedError { - t.Errorf("for %s: got no error, expected an error", testCase.ARN) - } + role, session := roleNameSessionFromARN(testCase.ARN) if testCase.ExpectedRoleName != role || testCase.ExpectedSessionName != session { t.Errorf("for %s: got role %s, session %s; expected role %s, session %s", testCase.ARN, role, session, testCase.ExpectedRoleName, testCase.ExpectedSessionName) From c096125d096ce3c3531c891703940ae76ed820ab Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 12:41:03 -0400 Subject: [PATCH 0798/1208] d/iam_assumed_role: Add extra check for nil --- aws/data_source_aws_iam_assumed_role_source.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/data_source_aws_iam_assumed_role_source.go b/aws/data_source_aws_iam_assumed_role_source.go index a6c810cbf8cc..1a658f05970a 100644 --- a/aws/data_source_aws_iam_assumed_role_source.go +++ b/aws/data_source_aws_iam_assumed_role_source.go @@ -90,6 +90,10 @@ func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interfac return fmt.Errorf("unable to get role (%s): %w", roleName, err) } + if role == nil || role.Arn == nil { + return fmt.Errorf("empty role returned (%s)", roleName) + } + d.Set("session_name", sessionName) d.Set("role_name", roleName) d.Set("source_arn", role.Arn) From 062fee7032b9484c699f459b03a8f88d7e26184b Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 28 Jun 2021 19:59:57 +0300 Subject: [PATCH 0799/1208] ammend sweeper --- aws/resource_aws_sagemaker_domain_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_sagemaker_domain_test.go b/aws/resource_aws_sagemaker_domain_test.go index feb635451eba..b11720bff587 100644 --- a/aws/resource_aws_sagemaker_domain_test.go +++ b/aws/resource_aws_sagemaker_domain_test.go @@ -90,6 +90,7 @@ func testSweepSagemakerDomains(region string) error { r := resourceAwsSagemakerDomain() d := r.Data(nil) d.SetId(aws.StringValue(domain.DomainId)) + d.Set("retention_policy.0.home_efs_file_system", "Delete") err = r.Delete(d, client) if err != nil { log.Printf("[ERROR] %s", err) From 37a65a7b50161b18fe7a0782720715842e0f0c10 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Mon, 28 Jun 2021 20:22:17 +0300 Subject: [PATCH 0800/1208] Apply suggestions from code review Co-authored-by: Kit Ewbank --- aws/resource_aws_cloudwatch_event_target.go | 6 +++--- aws/resource_aws_cloudwatch_event_target_test.go | 2 +- website/docs/r/cloudwatch_event_target.html.markdown | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index b9c8722ead33..99c12478927b 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -186,7 +186,7 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource { }, }, }, - "placement_constraints": { + "placement_constraint": { Type: schema.TypeSet, Optional: true, MaxItems: 10, @@ -620,7 +620,7 @@ func expandAwsCloudWatchEventTargetEcsParameters(config []interface{}, meta inte ecsParameters.PlatformVersion = aws.String(val) } - if v, ok := param["placement_constraints"].(*schema.Set); ok && v.Len() > 0 { + if v, ok := param["placement_constraint"].(*schema.Set); ok && v.Len() > 0 { ecsParameters.PlacementConstraints = expandAwsCloudWatchEventTargetPlacementConstraints(v.List()) } @@ -817,7 +817,7 @@ func flattenAwsCloudWatchEventTargetEcsParameters(ecsParameters *events.EcsParam } if ecsParameters.PlacementConstraints != nil { - config["placement_constraints"] = flattenAwsCloudWatchEventTargetPlacementConstraints(ecsParameters.PlacementConstraints) + config["placement_constraint"] = flattenAwsCloudWatchEventTargetPlacementConstraints(ecsParameters.PlacementConstraints) } tags := keyvaluetags.CloudwatcheventsKeyValueTags(ecsParameters.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) diff --git a/aws/resource_aws_cloudwatch_event_target_test.go b/aws/resource_aws_cloudwatch_event_target_test.go index 74dcace445ef..b7b0d23fd938 100644 --- a/aws/resource_aws_cloudwatch_event_target_test.go +++ b/aws/resource_aws_cloudwatch_event_target_test.go @@ -1410,7 +1410,7 @@ resource "aws_cloudwatch_event_target" "test" { enable_ecs_managed_tags = true propagate_tags = "TASK_DEFINITION" - placement_constraints { + placement_constraint { type = "distinctInstance" } diff --git a/website/docs/r/cloudwatch_event_target.html.markdown b/website/docs/r/cloudwatch_event_target.html.markdown index 7e32f1e4c03d..09710ceda8d1 100644 --- a/website/docs/r/cloudwatch_event_target.html.markdown +++ b/website/docs/r/cloudwatch_event_target.html.markdown @@ -359,7 +359,7 @@ The following arguments are supported: * `task_definition_arn` - (Required) The ARN of the task definition to use if the event target is an Amazon ECS cluster. * `tags` - (Optional) A map of tags to assign to ecs resources. 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. * `propagate_tags` - (Optional) Specifies whether to propagate the tags from the task definition to the task. If no value is specified, the tags are not propagated. Tags can only be propagated to the task during task creation. -* `placement_constraints` - (Optional) An array of placement constraint objects to use for the task. You can specify up to 10 constraints per task (including constraints in the task definition and those specified at runtime). See Below. +* `placement_constraint` - (Optional) An array of placement constraint objects to use for the task. You can specify up to 10 constraints per task (including constraints in the task definition and those specified at runtime). See Below. * `enable_execute_command` - (Optional) Whether or not to enable the execute command functionality for the containers in this task. If true, this enables execute command functionality on all containers in the task. * `enable_ecs_managed_tags` - (Optional) Specifies whether to enable Amazon ECS managed tags for the task. @@ -371,7 +371,7 @@ The following arguments are supported: For more information, see [Task Networking](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html) -#### placement_constraints +#### placement_constraint * `type` - (Required) Type of constraint. The only valid values at this time are `memberOf` and `distinctInstance`. * `expression` - (Optional) Cluster Query Language expression to apply to the constraint. Does not need to be specified for the `distinctInstance` type. For more information, see [Cluster Query Language in the Amazon EC2 Container Service Developer Guide](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-query-language.html). From 5da1ad38f35ed9d0afc877f4f0904851b0ea0459 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 28 Jun 2021 20:28:10 +0300 Subject: [PATCH 0801/1208] remove default tags from ecs tags --- aws/resource_aws_cloudwatch_event_target.go | 23 ++++++------------- .../r/cloudwatch_event_target.html.markdown | 2 +- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index 99c12478927b..f793498ddb0c 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -215,8 +215,7 @@ func resourceAwsCloudWatchEventTarget() *schema.Resource { Default: events.PropagateTagsTaskDefinition, ValidateFunc: validation.StringInSlice(events.PropagateTags_Values(), false), }, - "tags": tagsSchema(), - "tags_all": tagsSchemaComputed(), + "tags": tagsSchema(), "task_count": { Type: schema.TypeInt, Optional: true, @@ -428,7 +427,7 @@ func resourceAwsCloudWatchEventTargetRead(d *schema.ResourceData, meta interface } if t.EcsParameters != nil { - if err := d.Set("ecs_target", flattenAwsCloudWatchEventTargetEcsParameters(t.EcsParameters, meta)); err != nil { + if err := d.Set("ecs_target", flattenAwsCloudWatchEventTargetEcsParameters(t.EcsParameters)); err != nil { return fmt.Errorf("Error setting ecs_target error: %w", err) } } @@ -536,7 +535,7 @@ func buildPutTargetInputStruct(d *schema.ResourceData, meta interface{}) *events } if v, ok := d.GetOk("ecs_target"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - e.EcsParameters = expandAwsCloudWatchEventTargetEcsParameters(v.([]interface{}), meta) + e.EcsParameters = expandAwsCloudWatchEventTargetEcsParameters(v.([]interface{})) } if v, ok := d.GetOk("http_target"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { @@ -596,13 +595,11 @@ func expandAwsCloudWatchEventTargetRunParameters(config []interface{}) *events.R return command } -func expandAwsCloudWatchEventTargetEcsParameters(config []interface{}, meta interface{}) *events.EcsParameters { - +func expandAwsCloudWatchEventTargetEcsParameters(config []interface{}) *events.EcsParameters { ecsParameters := &events.EcsParameters{} for _, c := range config { param := c.(map[string]interface{}) - defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig - tags := defaultTagsConfig.MergeTags(keyvaluetags.New(param["tags"].(map[string]interface{}))) + tags := keyvaluetags.New(param["tags"].(map[string]interface{})) if val, ok := param["group"].(string); ok && val != "" { ecsParameters.Group = aws.String(val) @@ -794,10 +791,7 @@ func flattenAwsCloudWatchEventTargetRunParameters(runCommand *events.RunCommandP return result } -func flattenAwsCloudWatchEventTargetEcsParameters(ecsParameters *events.EcsParameters, meta interface{}) []map[string]interface{} { - defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig - ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - +func flattenAwsCloudWatchEventTargetEcsParameters(ecsParameters *events.EcsParameters) []map[string]interface{} { config := make(map[string]interface{}) if ecsParameters.Group != nil { config["group"] = aws.StringValue(ecsParameters.Group) @@ -820,10 +814,7 @@ func flattenAwsCloudWatchEventTargetEcsParameters(ecsParameters *events.EcsParam config["placement_constraint"] = flattenAwsCloudWatchEventTargetPlacementConstraints(ecsParameters.PlacementConstraints) } - tags := keyvaluetags.CloudwatcheventsKeyValueTags(ecsParameters.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) - config["tags"] = tags.RemoveDefaultConfig(defaultTagsConfig).Map() - config["tags_all"] = tags.Map() - + config["tags"] = keyvaluetags.CloudwatcheventsKeyValueTags(ecsParameters.Tags).IgnoreAws().Map() config["enable_execute_command"] = aws.BoolValue(ecsParameters.EnableExecuteCommand) config["enable_ecs_managed_tags"] = aws.BoolValue(ecsParameters.EnableECSManagedTags) config["task_count"] = aws.Int64Value(ecsParameters.TaskCount) diff --git a/website/docs/r/cloudwatch_event_target.html.markdown b/website/docs/r/cloudwatch_event_target.html.markdown index 09710ceda8d1..0ab5232a2ca7 100644 --- a/website/docs/r/cloudwatch_event_target.html.markdown +++ b/website/docs/r/cloudwatch_event_target.html.markdown @@ -357,7 +357,7 @@ The following arguments are supported: * `platform_version` - (Optional) Specifies the platform version for the task. Specify only the numeric portion of the platform version, such as 1.1.0. This is used only if LaunchType is FARGATE. For more information about valid platform versions, see [AWS Fargate Platform Versions](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html). * `task_count` - (Optional) The number of tasks to create based on the TaskDefinition. The default is 1. * `task_definition_arn` - (Required) The ARN of the task definition to use if the event target is an Amazon ECS cluster. -* `tags` - (Optional) A map of tags to assign to ecs resources. 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. +* `tags` - (Optional) A map of tags to assign to ecs resources. * `propagate_tags` - (Optional) Specifies whether to propagate the tags from the task definition to the task. If no value is specified, the tags are not propagated. Tags can only be propagated to the task during task creation. * `placement_constraint` - (Optional) An array of placement constraint objects to use for the task. You can specify up to 10 constraints per task (including constraints in the task definition and those specified at runtime). See Below. * `enable_execute_command` - (Optional) Whether or not to enable the execute command functionality for the containers in this task. If true, this enables execute command functionality on all containers in the task. From b2b8e9374435aade1786e4c680943cb4d22507b6 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 28 Jun 2021 20:30:10 +0300 Subject: [PATCH 0802/1208] missed test config rename --- aws/resource_aws_cloudwatch_event_target_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target_test.go b/aws/resource_aws_cloudwatch_event_target_test.go index b7b0d23fd938..24c57d411211 100644 --- a/aws/resource_aws_cloudwatch_event_target_test.go +++ b/aws/resource_aws_cloudwatch_event_target_test.go @@ -557,8 +557,8 @@ func TestAccAWSCloudWatchEventTarget_ecsFull(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "ecs_target.0.enable_execute_command", "true"), resource.TestCheckResourceAttr(resourceName, "ecs_target.0.enable_ecs_managed_tags", "true"), resource.TestCheckResourceAttr(resourceName, "ecs_target.0.propagate_tags", "TASK_DEFINITION"), - resource.TestCheckResourceAttr(resourceName, "ecs_target.0.placement_constraints.#", "1"), - resource.TestCheckResourceAttr(resourceName, "ecs_target.0.placement_constraints.0.type", "distinctInstance"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.placement_constraint.#", "1"), + resource.TestCheckResourceAttr(resourceName, "ecs_target.0.placement_constraint.0.type", "distinctInstance"), resource.TestCheckResourceAttr(resourceName, "ecs_target.0.tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "ecs_target.0.tags.test", "test1"), ), From aa4183cb50798d02cfb2345d2ee73c16d505e50a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 13:50:17 -0400 Subject: [PATCH 0803/1208] d/iam_session_context: Refactor --- ...=> data_source_aws_iam_session_context.go} | 23 ++++----- ...ta_source_aws_iam_session_context_test.go} | 47 +++++++++---------- aws/internal/service/iam/finder/finder.go | 4 +- aws/provider.go | 2 +- ....markdown => iam_session_context.markdown} | 9 ++-- 5 files changed, 37 insertions(+), 48 deletions(-) rename aws/{data_source_aws_iam_assumed_role_source.go => data_source_aws_iam_session_context.go} (84%) rename aws/{data_source_aws_iam_assumed_role_source_test.go => data_source_aws_iam_session_context_test.go} (80%) rename website/docs/d/{iam_assumed_role_source.markdown => iam_session_context.markdown} (86%) diff --git a/aws/data_source_aws_iam_assumed_role_source.go b/aws/data_source_aws_iam_session_context.go similarity index 84% rename from aws/data_source_aws_iam_assumed_role_source.go rename to aws/data_source_aws_iam_session_context.go index 1a658f05970a..485847af91f1 100644 --- a/aws/data_source_aws_iam_assumed_role_source.go +++ b/aws/data_source_aws_iam_session_context.go @@ -15,18 +15,15 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -func dataSourceAwsIAMAssumedRoleSource() *schema.Resource { +func dataSourceAwsIAMSessionContext() *schema.Resource { return &schema.Resource{ - Read: dataSourceAwsIAMAssumedRoleSourceRead, + Read: dataSourceAwsIAMSessionContextRead, Schema: map[string]*schema.Schema{ "arn": { - Type: schema.TypeString, - Required: true, - }, - "role_path": { - Type: schema.TypeString, - Computed: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, }, "role_name": { Type: schema.TypeString, @@ -44,7 +41,7 @@ func dataSourceAwsIAMAssumedRoleSource() *schema.Resource { } } -func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interface{}) error { +func dataSourceAwsIAMSessionContextRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).iamconn arn := d.Get("arn").(string) @@ -59,7 +56,6 @@ func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interfac d.Set("source_arn", arn) d.Set("session_name", "") d.Set("role_name", "") - d.Set("role_path", "") return nil } @@ -69,7 +65,7 @@ func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interfac err = resource.Retry(waiter.PropagationTimeout, func() *resource.RetryError { var err error - role, err = finder.RoleByName(conn, roleName) + role, err = finder.Role(conn, roleName) if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) { return resource.RetryableError(err) @@ -83,7 +79,7 @@ func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interfac }) if tfresource.TimedOut(err) { - role, err = finder.RoleByName(conn, roleName) + role, err = finder.Role(conn, roleName) } if err != nil { @@ -97,7 +93,6 @@ func dataSourceAwsIAMAssumedRoleSourceRead(d *schema.ResourceData, meta interfac d.Set("session_name", sessionName) d.Set("role_name", roleName) d.Set("source_arn", role.Arn) - d.Set("role_path", role.Path) return nil } @@ -120,7 +115,7 @@ func roleNameSessionFromARN(rawARN string) (string, string) { return "", "" } - if reRole.MatchString(parsedARN.Resource) && parsedARN.Service != "iam" { + if reRole.MatchString(parsedARN.Resource) && parsedARN.Service != iam.ServiceName { return "", "" } diff --git a/aws/data_source_aws_iam_assumed_role_source_test.go b/aws/data_source_aws_iam_session_context_test.go similarity index 80% rename from aws/data_source_aws_iam_assumed_role_source_test.go rename to aws/data_source_aws_iam_session_context_test.go index 10379b2eb999..06f871160c8e 100644 --- a/aws/data_source_aws_iam_assumed_role_source_test.go +++ b/aws/data_source_aws_iam_session_context_test.go @@ -90,9 +90,9 @@ func TestAssumedRoleRoleSessionName(t *testing.T) { } } -func TestAccAWSDataSourceIAMAssumedRoleSource_basic(t *testing.T) { +func TestAccAWSDataSourceIAMSessionContext_basic(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") - dataSourceName := "data.aws_iam_assumed_role_source.test" + dataSourceName := "data.aws_iam_session_context.test" resourceName := "aws_iam_role.test" resource.ParallelTest(t, resource.TestCase{ @@ -101,11 +101,10 @@ func TestAccAWSDataSourceIAMAssumedRoleSource_basic(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccAwsIAMAssumedRoleSourceConfig(rName, "/", "session-id"), + Config: testAccAwsIAMSessionContextConfig(rName, "/", "session-id"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), - resource.TestCheckResourceAttrPair(dataSourceName, "role_path", resourceName, "path"), resource.TestCheckResourceAttr(dataSourceName, "session_name", "session-id"), ), }, @@ -113,9 +112,9 @@ func TestAccAWSDataSourceIAMAssumedRoleSource_basic(t *testing.T) { }) } -func TestAccAWSDataSourceIAMAssumedRoleSource_withPath(t *testing.T) { +func TestAccAWSDataSourceIAMSessionContext_withPath(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") - dataSourceName := "data.aws_iam_assumed_role_source.test" + dataSourceName := "data.aws_iam_session_context.test" resourceName := "aws_iam_role.test" resource.ParallelTest(t, resource.TestCase{ @@ -124,11 +123,10 @@ func TestAccAWSDataSourceIAMAssumedRoleSource_withPath(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccAwsIAMAssumedRoleSourceConfig(rName, "/this/is/a/long/path/", "session-id"), + Config: testAccAwsIAMSessionContextConfig(rName, "/this/is/a/long/path/", "session-id"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), - resource.TestCheckResourceAttrPair(dataSourceName, "role_path", resourceName, "path"), resource.TestCheckResourceAttr(dataSourceName, "session_name", "session-id"), ), }, @@ -136,9 +134,9 @@ func TestAccAWSDataSourceIAMAssumedRoleSource_withPath(t *testing.T) { }) } -func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRole(t *testing.T) { +func TestAccAWSDataSourceIAMSessionContext_notAssumedRole(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") - dataSourceName := "data.aws_iam_assumed_role_source.test" + dataSourceName := "data.aws_iam_session_context.test" resourceName := "aws_iam_role.test" resource.ParallelTest(t, resource.TestCase{ @@ -147,11 +145,10 @@ func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRole(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccAwsIAMAssumedRoleSourceNotAssumedConfig(rName, "/"), + Config: testAccAwsIAMSessionContextNotAssumedConfig(rName, "/"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), - resource.TestCheckResourceAttrPair(dataSourceName, "role_path", resourceName, "path"), resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), ), }, @@ -159,9 +156,9 @@ func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRole(t *testing.T) { }) } -func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRoleWithPath(t *testing.T) { +func TestAccAWSDataSourceIAMSessionContext_notAssumedRoleWithPath(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") - dataSourceName := "data.aws_iam_assumed_role_source.test" + dataSourceName := "data.aws_iam_session_context.test" resourceName := "aws_iam_role.test" resource.ParallelTest(t, resource.TestCase{ @@ -170,11 +167,10 @@ func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRoleWithPath(t *testing. Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccAwsIAMAssumedRoleSourceNotAssumedConfig(rName, "/this/is/a/long/path/"), + Config: testAccAwsIAMSessionContextNotAssumedConfig(rName, "/this/is/a/long/path/"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), - resource.TestCheckResourceAttrPair(dataSourceName, "role_path", resourceName, "path"), resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), ), }, @@ -182,9 +178,9 @@ func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRoleWithPath(t *testing. }) } -func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRoleUser(t *testing.T) { +func TestAccAWSDataSourceIAMSessionContext_notAssumedRoleUser(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") - dataSourceName := "data.aws_iam_assumed_role_source.test" + dataSourceName := "data.aws_iam_session_context.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -192,11 +188,10 @@ func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRoleUser(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccAwsIAMAssumedRoleSourceUserConfig(rName), + Config: testAccAwsIAMSessionContextUserConfig(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckResourceAttrGlobalARN(dataSourceName, "arn", "iam", fmt.Sprintf("user/division/extra-division/not-assumed-role/%[1]s", rName)), resource.TestCheckResourceAttr(dataSourceName, "role_name", ""), - resource.TestCheckResourceAttr(dataSourceName, "role_path", ""), resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), ), }, @@ -204,7 +199,7 @@ func TestAccAWSDataSourceIAMAssumedRoleSource_notAssumedRoleUser(t *testing.T) { }) } -func testAccAwsIAMAssumedRoleSourceConfig(rName, path, sessionID string) string { +func testAccAwsIAMSessionContextConfig(rName, path, sessionID string) string { return fmt.Sprintf(` resource "aws_iam_role" "test" { name = %[1]q @@ -226,13 +221,13 @@ resource "aws_iam_role" "test" { data "aws_partition" "current" {} data "aws_caller_identity" "current" {} -data "aws_iam_assumed_role_source" "test" { +data "aws_iam_session_context" "test" { arn = "arn:${data.aws_partition.current.partition}:sts::${data.aws_caller_identity.current.account_id}:assumed-role/${aws_iam_role.test.name}/%[3]s" } `, rName, path, sessionID) } -func testAccAwsIAMAssumedRoleSourceNotAssumedConfig(rName, path string) string { +func testAccAwsIAMSessionContextNotAssumedConfig(rName, path string) string { return fmt.Sprintf(` data "aws_partition" "current" {} @@ -253,18 +248,18 @@ resource "aws_iam_role" "test" { }) } -data "aws_iam_assumed_role_source" "test" { +data "aws_iam_session_context" "test" { arn = aws_iam_role.test.arn } `, rName, path) } -func testAccAwsIAMAssumedRoleSourceUserConfig(rName string) string { +func testAccAwsIAMSessionContextUserConfig(rName string) string { return fmt.Sprintf(` data "aws_partition" "current" {} data "aws_caller_identity" "current" {} -data "aws_iam_assumed_role_source" "test" { +data "aws_iam_session_context" "test" { arn = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:user/division/extra-division/not-assumed-role/%[1]s" } `, rName) diff --git a/aws/internal/service/iam/finder/finder.go b/aws/internal/service/iam/finder/finder.go index 78d8ef9b2845..8b664f9a130f 100644 --- a/aws/internal/service/iam/finder/finder.go +++ b/aws/internal/service/iam/finder/finder.go @@ -112,8 +112,8 @@ func Policies(conn *iam.IAM, arn, name, pathPrefix string) ([]*iam.Policy, error return results, err } -// RoleByName returns a role's ARN given the role name -func RoleByName(conn *iam.IAM, name string) (*iam.Role, error) { +// Role returns a role's ARN given the role name +func Role(conn *iam.IAM, name string) (*iam.Role, error) { input := &iam.GetRoleInput{ RoleName: aws.String(name), } diff --git a/aws/provider.go b/aws/provider.go index 1adb6d59a662..15a0d8f4f02d 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -298,13 +298,13 @@ func Provider() *schema.Provider { "aws_glue_script": dataSourceAwsGlueScript(), "aws_guardduty_detector": dataSourceAwsGuarddutyDetector(), "aws_iam_account_alias": dataSourceAwsIamAccountAlias(), - "aws_iam_assumed_role_source": dataSourceAwsIAMAssumedRoleSource(), "aws_iam_group": dataSourceAwsIAMGroup(), "aws_iam_instance_profile": dataSourceAwsIAMInstanceProfile(), "aws_iam_policy": dataSourceAwsIAMPolicy(), "aws_iam_policy_document": dataSourceAwsIamPolicyDocument(), "aws_iam_role": dataSourceAwsIAMRole(), "aws_iam_server_certificate": dataSourceAwsIAMServerCertificate(), + "aws_iam_session_context": dataSourceAwsIAMSessionContext(), "aws_iam_user": dataSourceAwsIAMUser(), "aws_identitystore_group": dataSourceAwsIdentityStoreGroup(), "aws_identitystore_user": dataSourceAwsIdentityStoreUser(), diff --git a/website/docs/d/iam_assumed_role_source.markdown b/website/docs/d/iam_session_context.markdown similarity index 86% rename from website/docs/d/iam_assumed_role_source.markdown rename to website/docs/d/iam_session_context.markdown index 16491196ecd5..c29cf25454c1 100644 --- a/website/docs/d/iam_assumed_role_source.markdown +++ b/website/docs/d/iam_session_context.markdown @@ -1,12 +1,12 @@ --- subcategory: "IAM" layout: "aws" -page_title: "AWS: aws_iam_assumed_role_source" +page_title: "AWS: aws_iam_session_context" description: |- Get information on the IAM source role of an STS assumed role --- -# Data Source: aws_iam_assumed_role_source +# Data Source: aws_iam_session_context This data source provides information on the IAM source role of an STS assumed role. For non-role ARNs, this data source simply passes the ARN through. @@ -17,7 +17,7 @@ For some AWS resources, multiple types of principals are allowed in the same arg ### Basic Example ```terraform -data "aws_iam_assumed_role_source" "example" { +data "aws_iam_session_context" "example" { arn = "arn:aws:sts::123456789012:assumed-role/Audien-Heaven/MatyNoyes" } ``` @@ -29,7 +29,7 @@ Combined with `aws_caller_identity`, you can get the current user's source IAM r ```terraform data "aws_caller_identity" "current" {} -data "aws_iam_assumed_role_source" "example" { +data "aws_iam_session_context" "example" { arn = data.aws_called_identity.current.arn } ``` @@ -42,7 +42,6 @@ data "aws_iam_assumed_role_source" "example" { ## Attributes Reference -* `role_path` - Path of the source role. Only available if `arn` corresponds to an IAM role or STS assumed role. * `role_name` - Name of the source role. Only available if `arn` corresponds to an IAM role or STS assumed role. * `source_arn` - IAM source role ARN if `arn` corresponds to an STS assumed role. Otherwise, `source_arn` is equal to `arn`. * `session_name` - Name of the STS session. Only available if `arn` corresponds to an STS assumed role. From 3f2f55bef3266e69b1d681cb9b0910e9205da215 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 14:26:58 -0400 Subject: [PATCH 0804/1208] d/iam_session_context: Refactor attribute --- aws/data_source_aws_iam_session_context.go | 6 +++--- aws/data_source_aws_iam_session_context_test.go | 8 ++++---- website/docs/d/iam_session_context.markdown | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/aws/data_source_aws_iam_session_context.go b/aws/data_source_aws_iam_session_context.go index 485847af91f1..50f5bd593f15 100644 --- a/aws/data_source_aws_iam_session_context.go +++ b/aws/data_source_aws_iam_session_context.go @@ -29,7 +29,7 @@ func dataSourceAwsIAMSessionContext() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "source_arn": { + "issuer_arn": { Type: schema.TypeString, Computed: true, }, @@ -53,7 +53,7 @@ func dataSourceAwsIAMSessionContextRead(d *schema.ResourceData, meta interface{} var err error if roleName, sessionName = roleNameSessionFromARN(arn); roleName == "" { - d.Set("source_arn", arn) + d.Set("issuer_arn", arn) d.Set("session_name", "") d.Set("role_name", "") @@ -92,7 +92,7 @@ func dataSourceAwsIAMSessionContextRead(d *schema.ResourceData, meta interface{} d.Set("session_name", sessionName) d.Set("role_name", roleName) - d.Set("source_arn", role.Arn) + d.Set("issuer_arn", role.Arn) return nil } diff --git a/aws/data_source_aws_iam_session_context_test.go b/aws/data_source_aws_iam_session_context_test.go index 06f871160c8e..3701fdc56924 100644 --- a/aws/data_source_aws_iam_session_context_test.go +++ b/aws/data_source_aws_iam_session_context_test.go @@ -103,7 +103,7 @@ func TestAccAWSDataSourceIAMSessionContext_basic(t *testing.T) { { Config: testAccAwsIAMSessionContextConfig(rName, "/", "session-id"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "issuer_arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), resource.TestCheckResourceAttr(dataSourceName, "session_name", "session-id"), ), @@ -125,7 +125,7 @@ func TestAccAWSDataSourceIAMSessionContext_withPath(t *testing.T) { { Config: testAccAwsIAMSessionContextConfig(rName, "/this/is/a/long/path/", "session-id"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "issuer_arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), resource.TestCheckResourceAttr(dataSourceName, "session_name", "session-id"), ), @@ -147,7 +147,7 @@ func TestAccAWSDataSourceIAMSessionContext_notAssumedRole(t *testing.T) { { Config: testAccAwsIAMSessionContextNotAssumedConfig(rName, "/"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "issuer_arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), ), @@ -169,7 +169,7 @@ func TestAccAWSDataSourceIAMSessionContext_notAssumedRoleWithPath(t *testing.T) { Config: testAccAwsIAMSessionContextNotAssumedConfig(rName, "/this/is/a/long/path/"), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrPair(dataSourceName, "source_arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "issuer_arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), ), diff --git a/website/docs/d/iam_session_context.markdown b/website/docs/d/iam_session_context.markdown index c29cf25454c1..9e75ac378c52 100644 --- a/website/docs/d/iam_session_context.markdown +++ b/website/docs/d/iam_session_context.markdown @@ -8,7 +8,7 @@ description: |- # Data Source: aws_iam_session_context -This data source provides information on the IAM source role of an STS assumed role. For non-role ARNs, this data source simply passes the ARN through. +This data source provides information on the IAM source role of an STS assumed role. For non-role ARNs, this data source simply passes the ARN through in `issuer_arn`. For some AWS resources, multiple types of principals are allowed in the same argument (e.g., IAM users and IAM roles). However, these arguments often do not allow assumed-role (i.e., STS, temporary credential) principals. Given an STS ARN, this data source provides the ARN for the source IAM role. @@ -24,7 +24,7 @@ data "aws_iam_session_context" "example" { ### Find the Terraform Runner's Source Role -Combined with `aws_caller_identity`, you can get the current user's source IAM role ARN (`source_arn`) if you're using an assumed role. If you're not using an assumed role, the caller's (e.g., an IAM user's) ARN will simply be passed through. In environments where both IAM users and individuals using assumed roles need to apply the same configurations, this data source enables seamless use. +Combined with `aws_caller_identity`, you can get the current user's source IAM role ARN (`issuer_arn`) if you're using an assumed role. If you're not using an assumed role, the caller's (e.g., an IAM user's) ARN will simply be passed through. In environments where both IAM users and individuals using assumed roles need to apply the same configurations, this data source enables seamless use. ```terraform data "aws_caller_identity" "current" {} @@ -38,10 +38,10 @@ data "aws_iam_session_context" "example" { * `arn` - (Required) ARN for an assumed role. -~> If `arn` is a non-role ARN (or non-ARN), Terraform gives no error and `source_arn` will be equal to the `arn` value. For IAM role and STS assumed-role ARNs, Terraform gives an error if the identified IAM role does not exist. +~> If `arn` is a non-role ARN (or non-ARN), Terraform gives no error and `issuer_arn` will be equal to the `arn` value. For IAM role and STS assumed-role ARNs, Terraform gives an error if the identified IAM role does not exist. ## Attributes Reference * `role_name` - Name of the source role. Only available if `arn` corresponds to an IAM role or STS assumed role. -* `source_arn` - IAM source role ARN if `arn` corresponds to an STS assumed role. Otherwise, `source_arn` is equal to `arn`. +* `issuer_arn` - IAM source role ARN if `arn` corresponds to an STS assumed role. Otherwise, `issuer_arn` is equal to `arn`. * `session_name` - Name of the STS session. Only available if `arn` corresponds to an STS assumed role. From 494720047b1697c3093e20204cb7cb879e124af7 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 14:27:55 -0400 Subject: [PATCH 0805/1208] d/iam_session_context: Update changelog --- .changelog/19957.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/19957.txt b/.changelog/19957.txt index 4521f23bd83e..e4b1f3b3064e 100644 --- a/.changelog/19957.txt +++ b/.changelog/19957.txt @@ -1,3 +1,3 @@ ```release-note:new-data-source -aws_iam_assumed_role_source +aws_iam_session_context ``` \ No newline at end of file From 8c76c24ea45ef9c49d4b91d8216146a67427af8d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 14:40:10 -0400 Subject: [PATCH 0806/1208] d/iam_session_context: Refactor arguments, attributes --- aws/data_source_aws_iam_session_context.go | 16 +++++++++++----- aws/data_source_aws_iam_session_context_test.go | 11 ++++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/aws/data_source_aws_iam_session_context.go b/aws/data_source_aws_iam_session_context.go index 50f5bd593f15..40354ef27ae5 100644 --- a/aws/data_source_aws_iam_session_context.go +++ b/aws/data_source_aws_iam_session_context.go @@ -25,11 +25,15 @@ func dataSourceAwsIAMSessionContext() *schema.Resource { Required: true, ValidateFunc: validateArn, }, - "role_name": { + "issuer_arn": { Type: schema.TypeString, Computed: true, }, - "issuer_arn": { + "issuer_id": { + Type: schema.TypeString, + Computed: true, + }, + "issuer_name": { Type: schema.TypeString, Computed: true, }, @@ -54,8 +58,9 @@ func dataSourceAwsIAMSessionContextRead(d *schema.ResourceData, meta interface{} if roleName, sessionName = roleNameSessionFromARN(arn); roleName == "" { d.Set("issuer_arn", arn) + d.Set("issuer_id", "") + d.Set("issuer_name", "") d.Set("session_name", "") - d.Set("role_name", "") return nil } @@ -90,9 +95,10 @@ func dataSourceAwsIAMSessionContextRead(d *schema.ResourceData, meta interface{} return fmt.Errorf("empty role returned (%s)", roleName) } - d.Set("session_name", sessionName) - d.Set("role_name", roleName) d.Set("issuer_arn", role.Arn) + d.Set("issuer_id", role.RoleId) + d.Set("issuer_name", roleName) + d.Set("session_name", sessionName) return nil } diff --git a/aws/data_source_aws_iam_session_context_test.go b/aws/data_source_aws_iam_session_context_test.go index 3701fdc56924..97e8cd6524d4 100644 --- a/aws/data_source_aws_iam_session_context_test.go +++ b/aws/data_source_aws_iam_session_context_test.go @@ -104,7 +104,8 @@ func TestAccAWSDataSourceIAMSessionContext_basic(t *testing.T) { Config: testAccAwsIAMSessionContextConfig(rName, "/", "session-id"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "issuer_arn", resourceName, "arn"), - resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "issuer_id", resourceName, "unique_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "issuer_name", resourceName, "name"), resource.TestCheckResourceAttr(dataSourceName, "session_name", "session-id"), ), }, @@ -126,7 +127,7 @@ func TestAccAWSDataSourceIAMSessionContext_withPath(t *testing.T) { Config: testAccAwsIAMSessionContextConfig(rName, "/this/is/a/long/path/", "session-id"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "issuer_arn", resourceName, "arn"), - resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "issuer_name", resourceName, "name"), resource.TestCheckResourceAttr(dataSourceName, "session_name", "session-id"), ), }, @@ -148,7 +149,7 @@ func TestAccAWSDataSourceIAMSessionContext_notAssumedRole(t *testing.T) { Config: testAccAwsIAMSessionContextNotAssumedConfig(rName, "/"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "issuer_arn", resourceName, "arn"), - resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "issuer_name", resourceName, "name"), resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), ), }, @@ -170,7 +171,7 @@ func TestAccAWSDataSourceIAMSessionContext_notAssumedRoleWithPath(t *testing.T) Config: testAccAwsIAMSessionContextNotAssumedConfig(rName, "/this/is/a/long/path/"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "issuer_arn", resourceName, "arn"), - resource.TestCheckResourceAttrPair(dataSourceName, "role_name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "issuer_name", resourceName, "name"), resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), ), }, @@ -191,7 +192,7 @@ func TestAccAWSDataSourceIAMSessionContext_notAssumedRoleUser(t *testing.T) { Config: testAccAwsIAMSessionContextUserConfig(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckResourceAttrGlobalARN(dataSourceName, "arn", "iam", fmt.Sprintf("user/division/extra-division/not-assumed-role/%[1]s", rName)), - resource.TestCheckResourceAttr(dataSourceName, "role_name", ""), + resource.TestCheckResourceAttr(dataSourceName, "issuer_name", ""), resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), ), }, From 1232685e3d069514afb2351ccd0b4f75633f93b6 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 14:47:02 -0400 Subject: [PATCH 0807/1208] docs/d/iam_session_context: Fix docs --- website/docs/d/iam_session_context.markdown | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/website/docs/d/iam_session_context.markdown b/website/docs/d/iam_session_context.markdown index 9e75ac378c52..5c0f168b9f9e 100644 --- a/website/docs/d/iam_session_context.markdown +++ b/website/docs/d/iam_session_context.markdown @@ -38,10 +38,13 @@ data "aws_iam_session_context" "example" { * `arn` - (Required) ARN for an assumed role. -~> If `arn` is a non-role ARN (or non-ARN), Terraform gives no error and `issuer_arn` will be equal to the `arn` value. For IAM role and STS assumed-role ARNs, Terraform gives an error if the identified IAM role does not exist. +~> If `arn` is a non-role ARN (or non-ARN), Terraform gives no error and `issuer_arn` will be equal to the `arn` value. For STS assumed-role ARNs, Terraform gives an error if the identified IAM role does not exist. ## Attributes Reference -* `role_name` - Name of the source role. Only available if `arn` corresponds to an IAM role or STS assumed role. +~> With the exception of `issuer_arn`, the attributes will not be populated unless the `arn` corresponds to an STS assumed role. + * `issuer_arn` - IAM source role ARN if `arn` corresponds to an STS assumed role. Otherwise, `issuer_arn` is equal to `arn`. +* `issuer_id` - Unique identifier of the IAM role that issues the STS assumed role. +* `issuer_name` - Name of the source role. Only available if `arn` corresponds to an STS assumed role. * `session_name` - Name of the STS session. Only available if `arn` corresponds to an STS assumed role. From db6575bb512ab31f09967933671653252aab206b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 15:02:25 -0400 Subject: [PATCH 0808/1208] d/iam_session_context: Rework helper --- aws/data_source_aws_iam_session_context.go | 17 ++--------------- aws/data_source_aws_iam_session_context_test.go | 8 ++++---- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/aws/data_source_aws_iam_session_context.go b/aws/data_source_aws_iam_session_context.go index 40354ef27ae5..9b976e16d1ab 100644 --- a/aws/data_source_aws_iam_session_context.go +++ b/aws/data_source_aws_iam_session_context.go @@ -112,26 +112,13 @@ func roleNameSessionFromARN(rawARN string) (string, string) { return "", "" } - parts := strings.Split(parsedARN.Resource, "/") - reAssume := regexp.MustCompile(`^assumed-role/.{1,}/.{2,}`) - reRole := regexp.MustCompile(`^role/.{1,}`) - - if reAssume.MatchString(parsedARN.Resource) && parsedARN.Service != "sts" { - return "", "" - } - if reRole.MatchString(parsedARN.Resource) && parsedARN.Service != iam.ServiceName { + if !reAssume.MatchString(parsedARN.Resource) || parsedARN.Service != "sts" { return "", "" } - if !reAssume.MatchString(parsedARN.Resource) && !reRole.MatchString(parsedARN.Resource) { - return "", "" - } - - if reRole.MatchString(parsedARN.Resource) && len(parts) > 1 { - return parts[len(parts)-1], "" - } + parts := strings.Split(parsedARN.Resource, "/") if len(parts) < 3 { return "", "" diff --git a/aws/data_source_aws_iam_session_context_test.go b/aws/data_source_aws_iam_session_context_test.go index 97e8cd6524d4..ba458d8586a3 100644 --- a/aws/data_source_aws_iam_session_context_test.go +++ b/aws/data_source_aws_iam_session_context_test.go @@ -26,7 +26,7 @@ func TestAssumedRoleRoleSessionName(t *testing.T) { { Name: "regular role ARN", ARN: "arn:aws:iam::111122223333:role/role_name", //lintignore:AWSAT005 - ExpectedRoleName: "role_name", + ExpectedRoleName: "", ExpectedSessionName: "", }, { @@ -68,7 +68,7 @@ func TestAssumedRoleRoleSessionName(t *testing.T) { { Name: "role with path", ARN: "arn:aws:iam::123456789012:role/this/is/the/path/role-name", //lintignore:AWSAT005 - ExpectedRoleName: "role-name", + ExpectedRoleName: "", ExpectedSessionName: "", }, { @@ -149,7 +149,7 @@ func TestAccAWSDataSourceIAMSessionContext_notAssumedRole(t *testing.T) { Config: testAccAwsIAMSessionContextNotAssumedConfig(rName, "/"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "issuer_arn", resourceName, "arn"), - resource.TestCheckResourceAttrPair(dataSourceName, "issuer_name", resourceName, "name"), + resource.TestCheckResourceAttr(dataSourceName, "issuer_name", ""), resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), ), }, @@ -171,7 +171,7 @@ func TestAccAWSDataSourceIAMSessionContext_notAssumedRoleWithPath(t *testing.T) Config: testAccAwsIAMSessionContextNotAssumedConfig(rName, "/this/is/a/long/path/"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "issuer_arn", resourceName, "arn"), - resource.TestCheckResourceAttrPair(dataSourceName, "issuer_name", resourceName, "name"), + resource.TestCheckResourceAttr(dataSourceName, "issuer_name", ""), resource.TestCheckResourceAttr(dataSourceName, "session_name", ""), ), }, From a824e7cc620b8dc4105e13935c05c9233f6cf949 Mon Sep 17 00:00:00 2001 From: Dirk Avery <31492422+YakDriver@users.noreply.github.com> Date: Mon, 28 Jun 2021 15:18:17 -0400 Subject: [PATCH 0809/1208] Update website/docs/d/iam_session_context.markdown Co-authored-by: Kit Ewbank --- website/docs/d/iam_session_context.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/iam_session_context.markdown b/website/docs/d/iam_session_context.markdown index 5c0f168b9f9e..7f1a720afcf9 100644 --- a/website/docs/d/iam_session_context.markdown +++ b/website/docs/d/iam_session_context.markdown @@ -30,7 +30,7 @@ Combined with `aws_caller_identity`, you can get the current user's source IAM r data "aws_caller_identity" "current" {} data "aws_iam_session_context" "example" { - arn = data.aws_called_identity.current.arn + arn = data.aws_caller_identity.current.arn } ``` From 4252de01a2c8aed79bda5900371b19c58f440113 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 28 Jun 2021 15:20:18 -0400 Subject: [PATCH 0810/1208] Fix docs --- website/docs/d/iam_session_context.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/iam_session_context.markdown b/website/docs/d/iam_session_context.markdown index 7f1a720afcf9..4cea6665624d 100644 --- a/website/docs/d/iam_session_context.markdown +++ b/website/docs/d/iam_session_context.markdown @@ -38,7 +38,7 @@ data "aws_iam_session_context" "example" { * `arn` - (Required) ARN for an assumed role. -~> If `arn` is a non-role ARN (or non-ARN), Terraform gives no error and `issuer_arn` will be equal to the `arn` value. For STS assumed-role ARNs, Terraform gives an error if the identified IAM role does not exist. +~> If `arn` is a non-role ARN, Terraform gives no error and `issuer_arn` will be equal to the `arn` value. For STS assumed-role ARNs, Terraform gives an error if the identified IAM role does not exist. ## Attributes Reference From 472a694ae82d8826a14db5eab1b3c123b010d18a Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 2 Feb 2021 15:27:44 -0300 Subject: [PATCH 0811/1208] ADd new key --- aws/resource_aws_transfer_server.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index eef991d07cec..7b455f00fff3 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -66,6 +66,14 @@ func resourceAwsTransferServer() *schema.Resource { Set: schema.HashString, ConflictsWith: []string{"endpoint_details.0.vpc_endpoint_id"}, }, + "security_group_ids": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + ConflictsWith: []string{"endpoint_details.0.vpc_endpoint_id"}, + }, "subnet_ids": { Type: schema.TypeSet, Optional: true, @@ -76,7 +84,7 @@ func resourceAwsTransferServer() *schema.Resource { "vpc_endpoint_id": { Type: schema.TypeString, Optional: true, - ConflictsWith: []string{"endpoint_details.0.address_allocation_ids", "endpoint_details.0.subnet_ids", "endpoint_details.0.vpc_id"}, + ConflictsWith: []string{"endpoint_details.0.address_allocation_ids", "endpoint_details.0.security_group_ids", "endpoint_details.0.subnet_ids", "endpoint_details.0.vpc_id"}, Computed: true, }, "vpc_id": { From a1aa8edc05bb916368c5f329f91db6b0f3aa4340 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 2 Feb 2021 17:35:19 -0300 Subject: [PATCH 0812/1208] Change --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9470fd018ef0..c836d55f1921 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -836,6 +836,7 @@ FEATURES: ENHANCEMENTS: + * data-source/aws_subnet: Add `customer_owned_ipv4_pool` and `map_customer_owned_ip_on_launch` attributes ([#16676](https://github.com/hashicorp/terraform-provider-aws/issues/16676)) * resource/aws_glacier_vault: Add plan-time validation for `notification` configuration block `events` and `sns_topic_arn` arguments ([#12645](https://github.com/hashicorp/terraform-provider-aws/issues/12645)) * resource/aws_glue_catalog_table: Adds support for specifying schema from schema registry. ([#17335](https://github.com/hashicorp/terraform-provider-aws/issues/17335)) From fc1a43740549f04b7b4c5498c512807f42c4a0a2 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Thu, 4 Feb 2021 15:13:34 -0300 Subject: [PATCH 0813/1208] Add security_group_ids parameter. --- aws/resource_aws_transfer_server.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 7b455f00fff3..3750be1faf8f 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -268,6 +268,9 @@ func resourceAwsTransferServerCreate(d *schema.ResourceData, meta interface{}) e if err := stopTransferServer(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return err } + updateEndPoint := d.Get("endpoint_details") + // delete(updateEndPoint, "SecurityGroupIds") + // updateEndPoint.SecurityGroupIds = {} input := &transfer.UpdateServerInput{ ServerId: aws.String(d.Id()), From 2d4c47c9274d3529e3aaec73c250fcea77168925 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Thu, 4 Feb 2021 18:18:03 -0300 Subject: [PATCH 0814/1208] change --- .goreleaser.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index fe1eb97fe8c6..999f7af3d857 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -11,15 +11,15 @@ builds: flags: - -trimpath goarch: - - '386' - - amd64 - - arm +# - '386' +# - amd64 +# - arm - arm64 goos: - darwin - - freebsd - - linux - - windows +# - freebsd +# - linux +# - windows ignore: - goarch: '386' goos: darwin From 8d2dd00a5b05d1e694db5fa7129ccfbd46a1f9bb Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Thu, 4 Feb 2021 18:18:58 -0300 Subject: [PATCH 0815/1208] change --- .goreleaser.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 999f7af3d857..6b174af7874c 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -18,7 +18,7 @@ builds: goos: - darwin # - freebsd -# - linux + - linux # - windows ignore: - goarch: '386' From 708b2671f891aa526eb06f82a76df0764878c4e8 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Thu, 4 Feb 2021 18:35:20 -0300 Subject: [PATCH 0816/1208] Change --- .goreleaser.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 6b174af7874c..fe1eb97fe8c6 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -11,15 +11,15 @@ builds: flags: - -trimpath goarch: -# - '386' -# - amd64 -# - arm + - '386' + - amd64 + - arm - arm64 goos: - darwin -# - freebsd + - freebsd - linux -# - windows + - windows ignore: - goarch: '386' goos: darwin From e1751a8fe5953853026575d5800b280962f48e01 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Thu, 4 Feb 2021 19:15:55 -0300 Subject: [PATCH 0817/1208] Change --- .github/workflows/release.yml | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 90969c0596bd..5ed1b05a5020 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,4 @@ +<<<<<<< HEAD name: Post Publish on: release: @@ -52,3 +53,56 @@ jobs: git add CHANGELOG.md git commit -m "Update CHANGELOG.md after ${{ github.event.release.tag_name }}" git push +======= +# This GitHub action can publish assets for release when a tag is created. +# Currently its setup to run on any tag that matches the pattern "v*" (ie. v0.1.0). +# +# This uses an action (paultyng/ghaction-import-gpg) that assumes you set your +# private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `PASSPHRASE` +# secret. If you would rather own your own GPG handling, please fork this action +# or use an alternative one for key handling. +# +# You will need to pass the `--batch` flag to `gpg` in your signing step +# in `goreleaser` to indicate this is being used in a non-interactive mode. +# +name: release +on: + push: + tags: + - 'v*' +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Unshallow + run: git fetch --prune --unshallow + - + name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.14 + - + name: Import GPG key + id: import_gpg + # TODO: move this to HashiCorp namespace or find alternative that is just simple gpg commands + # see https://github.com/hashicorp/terraform-provider-scaffolding/issues/22 + uses: paultyng/ghaction-import-gpg@v2.1.0 + env: + # These secrets will need to be configured for the repository: + GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + PASSPHRASE: ${{ secrets.PASSPHRASE }} + - + name: Run GoReleaser + uses: goreleaser/goreleaser-action@v2 + with: + version: latest + args: release --rm-dist + env: + GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} + # GitHub sets this automatically + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +>>>>>>> 19bf7eb9c (Change) From 82f0197fcd53d92c1db54e0db0563030d4b67b2d Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Fri, 5 Feb 2021 21:52:10 -0300 Subject: [PATCH 0818/1208] Update --- aws/resource_aws_transfer_server.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 3750be1faf8f..2ed9554e5be6 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -268,9 +268,8 @@ func resourceAwsTransferServerCreate(d *schema.ResourceData, meta interface{}) e if err := stopTransferServer(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return err } - updateEndPoint := d.Get("endpoint_details") - // delete(updateEndPoint, "SecurityGroupIds") - // updateEndPoint.SecurityGroupIds = {} + // Here we ansure that SecurityGroupsids is nil. We can't update this + createOpts.EndpointDetails.SecurityGroupIds = nil input := &transfer.UpdateServerInput{ ServerId: aws.String(d.Id()), From 240e4456efd6e7cd0c09c903362f1bb90d842f25 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Fri, 5 Feb 2021 22:03:12 -0300 Subject: [PATCH 0819/1208] Update Doc --- website/docs/r/transfer_server.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index 6b172348db8a..ef4616f87e52 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -108,6 +108,7 @@ The following arguments are supported: * `address_allocation_ids` - (Optional) A list of address allocation IDs that are required to attach an Elastic IP address to your SFTP server's endpoint. This property can only be used when `endpoint_type` is set to `VPC`. * `subnet_ids` - (Optional) A list of subnet IDs that are required to host your SFTP server endpoint in your VPC. This property can only be used when `endpoint_type` is set to `VPC`. * `vpc_id` - (Optional) The VPC ID of the virtual private cloud in which the SFTP server's endpoint will be hosted. This property can only be used when `endpoint_type` is set to `VPC`. +* `security_group_ids` - (Optional) A list of Security Groups Ids. This property can only be used when `endpoint_type` is set to `VPC`. It can't be change after transfer server creation. ## Attributes Reference In addition to all arguments above, the following attributes are exported: From f8a62376bdb9f7be9e5a1285869168d01ad35483 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 9 Feb 2021 17:43:16 -0300 Subject: [PATCH 0820/1208] Add go.yaml --- .github/workflows/go.yml | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/go.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 000000000000..7fe92da0143d --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,40 @@ +name: release +on: + push: + tags: + - 'v*' +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Unshallow + run: git fetch --prune --unshallow + - + name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.14 + - + name: Import GPG key + id: import_gpg + # TODO: move this to HashiCorp namespace or find alternative that is just simple gpg commands + # see https://github.com/hashicorp/terraform-provider-scaffolding/issues/22 + uses: paultyng/ghaction-import-gpg@v2.1.0 + env: + # These secrets will need to be configured for the repository: + GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + PASSPHRASE: ${{ secrets.PASSPHRASE }} + - + name: Run GoReleaser + uses: goreleaser/goreleaser-action@v2 + with: + version: latest + args: release --rm-dist + env: + GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} + # GitHub sets this automatically + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 4b191fb2f384eb8e303de820897967c317a61e75 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 9 Feb 2021 19:04:02 -0300 Subject: [PATCH 0821/1208] Change --- .goreleaser.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index fe1eb97fe8c6..17ec99994b2d 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -11,15 +11,15 @@ builds: flags: - -trimpath goarch: - - '386' +# - '386' - amd64 - - arm +# - arm - arm64 goos: - darwin - - freebsd +# - freebsd - linux - - windows +# - windows ignore: - goarch: '386' goos: darwin From 54698e8999ea81ad257593245b48acf8b4252a9d Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 9 Feb 2021 19:05:05 -0300 Subject: [PATCH 0822/1208] Change --- .goreleaser.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 17ec99994b2d..a98c6242ceb3 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -27,7 +27,7 @@ builds: - -s -w -X version.ProviderVersion={{.Version}} mod_timestamp: '{{ .CommitTimestamp }}' changelog: - skip: true + skip: false checksum: name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' algorithm: sha256 From 1183799c04a30b5a615c10eca56f30c598c122ab Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 9 Feb 2021 19:13:30 -0300 Subject: [PATCH 0823/1208] Change --- .goreleaser.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index a98c6242ceb3..3fae370f305a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -12,7 +12,7 @@ builds: - -trimpath goarch: # - '386' - - amd64 +# - amd64 # - arm - arm64 goos: @@ -34,7 +34,7 @@ checksum: env: - CGO_ENABLED=0 release: - disable: true + disable: false signs: - artifacts: checksum args: From 18f986ab726b69fc213ec212388fcbd89c0f82d5 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 9 Feb 2021 19:18:31 -0300 Subject: [PATCH 0824/1208] Change --- .goreleaser.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index 3fae370f305a..84a1671a58ba 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -35,6 +35,12 @@ env: - CGO_ENABLED=0 release: disable: false + github: + owner: amadureira + name: terraform-provider-aws + + + signs: - artifacts: checksum args: From c439ede8c7b0eee78a63aab7587941f4cfb964fc Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 9 Feb 2021 19:40:34 -0300 Subject: [PATCH 0825/1208] Change only one line --- .goreleaser.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index 84a1671a58ba..194a26e93532 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -6,6 +6,7 @@ archives: before: hooks: - go mod download + builds: - binary: '{{ .ProjectName }}_{{ .Version }}' flags: From 471c29e41751369384cbc48fb9c236043aab229d Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 9 Feb 2021 20:00:54 -0300 Subject: [PATCH 0826/1208] Change --- .goreleaser.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 194a26e93532..a16b9e5bbc9b 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -13,14 +13,14 @@ builds: - -trimpath goarch: # - '386' -# - amd64 -# - arm + - amd64 + - arm - arm64 goos: - darwin -# - freebsd + - freebsd - linux -# - windows + - windows ignore: - goarch: '386' goos: darwin From f96aaa9464aa64bf6cde612d086cbd83726c1a07 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 9 Feb 2021 23:37:02 -0300 Subject: [PATCH 0827/1208] Add changelog --- .changelog/17496.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/17496.txt diff --git a/.changelog/17496.txt b/.changelog/17496.txt new file mode 100644 index 000000000000..70e1bc075d30 --- /dev/null +++ b/.changelog/17496.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_transfer_server: Add security_group_ids for endpoint_details block +``` From 8ab5322e57cc93a2654aac0d6034387e5a55ed34 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 16 Feb 2021 15:20:10 -0300 Subject: [PATCH 0828/1208] Add changelog, reset .goreleaser.yml and fix aws/resource_aws_transfer_server.go --- .changelog/17539.txt | 3 +++ .goreleaser.yml | 13 +++---------- aws/resource_aws_transfer_server.go | 1 + 3 files changed, 7 insertions(+), 10 deletions(-) create mode 100644 .changelog/17539.txt diff --git a/.changelog/17539.txt b/.changelog/17539.txt new file mode 100644 index 000000000000..3961f2085c94 --- /dev/null +++ b/.changelog/17539.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_transfer_server: Add security_group_ids parameter +``` diff --git a/.goreleaser.yml b/.goreleaser.yml index a16b9e5bbc9b..fe1eb97fe8c6 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -6,13 +6,12 @@ archives: before: hooks: - go mod download - builds: - binary: '{{ .ProjectName }}_{{ .Version }}' flags: - -trimpath goarch: -# - '386' + - '386' - amd64 - arm - arm64 @@ -28,20 +27,14 @@ builds: - -s -w -X version.ProviderVersion={{.Version}} mod_timestamp: '{{ .CommitTimestamp }}' changelog: - skip: false + skip: true checksum: name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' algorithm: sha256 env: - CGO_ENABLED=0 release: - disable: false - github: - owner: amadureira - name: terraform-provider-aws - - - + disable: true signs: - artifacts: checksum args: diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 2ed9554e5be6..2831f0520769 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -268,6 +268,7 @@ func resourceAwsTransferServerCreate(d *schema.ResourceData, meta interface{}) e if err := stopTransferServer(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return err } + // Here we ansure that SecurityGroupsids is nil. We can't update this createOpts.EndpointDetails.SecurityGroupIds = nil From 083b5188bb014a73bd87c6254931a6094532196e Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Fri, 19 Feb 2021 10:34:04 -0300 Subject: [PATCH 0829/1208] A little change --- .changelog/17539.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/17539.txt b/.changelog/17539.txt index 3961f2085c94..085b0471cb72 100644 --- a/.changelog/17539.txt +++ b/.changelog/17539.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_transfer_server: Add security_group_ids parameter +resource/aws_transfer_server: Add security_group_ids parameter. ``` From 3660eb6323ab51a537a8ea7c126e2e9da980db19 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 16 Feb 2021 21:54:14 -0300 Subject: [PATCH 0830/1208] Return .goreleaser.yml and CHANGELOG.md to original state --- .goreleaser.yml | 2 +- CHANGELOG.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index fe1eb97fe8c6..8d1a78155dd9 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -24,7 +24,7 @@ builds: - goarch: '386' goos: darwin ldflags: - - -s -w -X version.ProviderVersion={{.Version}} + - -s -w -X aws/version.ProviderVersion={{.Version}} mod_timestamp: '{{ .CommitTimestamp }}' changelog: skip: true diff --git a/CHANGELOG.md b/CHANGELOG.md index c836d55f1921..9470fd018ef0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -836,7 +836,6 @@ FEATURES: ENHANCEMENTS: - * data-source/aws_subnet: Add `customer_owned_ipv4_pool` and `map_customer_owned_ip_on_launch` attributes ([#16676](https://github.com/hashicorp/terraform-provider-aws/issues/16676)) * resource/aws_glacier_vault: Add plan-time validation for `notification` configuration block `events` and `sns_topic_arn` arguments ([#12645](https://github.com/hashicorp/terraform-provider-aws/issues/12645)) * resource/aws_glue_catalog_table: Adds support for specifying schema from schema registry. ([#17335](https://github.com/hashicorp/terraform-provider-aws/issues/17335)) From e6d232091bba6851783572f45cf38fedd2b788ff Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Tue, 16 Feb 2021 21:55:11 -0300 Subject: [PATCH 0831/1208] Remove Custom workflow files --- .github/workflows/go.yml | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 .github/workflows/go.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index 7fe92da0143d..000000000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: release -on: - push: - tags: - - 'v*' -jobs: - goreleaser: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Unshallow - run: git fetch --prune --unshallow - - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: 1.14 - - - name: Import GPG key - id: import_gpg - # TODO: move this to HashiCorp namespace or find alternative that is just simple gpg commands - # see https://github.com/hashicorp/terraform-provider-scaffolding/issues/22 - uses: paultyng/ghaction-import-gpg@v2.1.0 - env: - # These secrets will need to be configured for the repository: - GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} - PASSPHRASE: ${{ secrets.PASSPHRASE }} - - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v2 - with: - version: latest - args: release --rm-dist - env: - GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} - # GitHub sets this automatically - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 9c72f21c098a1ec41230c5e1354b8ecad3f785c6 Mon Sep 17 00:00:00 2001 From: Anderson Madureira Date: Fri, 26 Feb 2021 10:34:56 -0300 Subject: [PATCH 0832/1208] Change --- .changelog/17496.txt | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .changelog/17496.txt diff --git a/.changelog/17496.txt b/.changelog/17496.txt deleted file mode 100644 index 70e1bc075d30..000000000000 --- a/.changelog/17496.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:enhancement -resource/aws_transfer_server: Add security_group_ids for endpoint_details block -``` From 64d2c2b494d9dc9017c0edead923b48e876f39f7 Mon Sep 17 00:00:00 2001 From: amadureira Date: Fri, 26 Feb 2021 10:34:32 -0300 Subject: [PATCH 0833/1208] Update .changelog/17539.txt Co-authored-by: Kit Ewbank --- .changelog/17539.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/17539.txt b/.changelog/17539.txt index 085b0471cb72..8f9455ff51b3 100644 --- a/.changelog/17539.txt +++ b/.changelog/17539.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_transfer_server: Add security_group_ids parameter. +resource/aws_transfer_server: Add `security_group_ids` attribute. ``` From 5a01d013cc9fc368b9f9a5f9fb419c4182613c34 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 28 Jun 2021 15:46:17 -0400 Subject: [PATCH 0834/1208] Tidy up after rebase. --- .changelog/17539.txt | 2 +- aws/resource_aws_transfer_server.go | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.changelog/17539.txt b/.changelog/17539.txt index 8f9455ff51b3..4ea42cc41558 100644 --- a/.changelog/17539.txt +++ b/.changelog/17539.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_transfer_server: Add `security_group_ids` attribute. +resource/aws_transfer_server: Add `security_group_ids` argument to `endpoint_details` configuration block. ``` diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 2831f0520769..7b455f00fff3 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -269,9 +269,6 @@ func resourceAwsTransferServerCreate(d *schema.ResourceData, meta interface{}) e return err } - // Here we ansure that SecurityGroupsids is nil. We can't update this - createOpts.EndpointDetails.SecurityGroupIds = nil - input := &transfer.UpdateServerInput{ ServerId: aws.String(d.Id()), EndpointDetails: expandTransferEndpointDetails(d.Get("endpoint_details").([]interface{})[0].(map[string]interface{})), From 0b55299cb7fb033460c7e339c7a7524f163f655d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 28 Jun 2021 16:23:43 -0400 Subject: [PATCH 0835/1208] r/aws_transfer_server: Add TODOs for security group ID updates. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSTransferServer_vpc' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSTransferServer_vpc -timeout 180m === RUN TestAccAWSTransferServer_vpc === PAUSE TestAccAWSTransferServer_vpc === RUN TestAccAWSTransferServer_vpcEndpointId === PAUSE TestAccAWSTransferServer_vpcEndpointId === CONT TestAccAWSTransferServer_vpc === CONT TestAccAWSTransferServer_vpcEndpointId --- PASS: TestAccAWSTransferServer_vpcEndpointId (55.36s) --- PASS: TestAccAWSTransferServer_vpc (230.58s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 235.878s --- aws/resource_aws_transfer_server.go | 17 +++++++++++++++++ website/docs/r/transfer_server.html.markdown | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 7b455f00fff3..c19d62e809b1 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -40,6 +40,7 @@ func resourceAwsTransferServer() *schema.Resource { Optional: true, ValidateFunc: validateArn, }, + "domain": { Type: schema.TypeString, Optional: true, @@ -269,6 +270,10 @@ func resourceAwsTransferServerCreate(d *schema.ResourceData, meta interface{}) e return err } + // TODO + // TODO You can edit the SecurityGroupIds property in the UpdateServer API only if you are changing the EndpointType from PUBLIC or VPC_ENDPOINT to VPC. To change security groups associated with your server's VPC endpoint after creation, use the Amazon EC2 ModifyVpcEndpoint API. + // TODO + input := &transfer.UpdateServerInput{ ServerId: aws.String(d.Id()), EndpointDetails: expandTransferEndpointDetails(d.Get("endpoint_details").([]interface{})[0].(map[string]interface{})), @@ -398,6 +403,10 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e if d.HasChange("endpoint_details.0.address_allocation_ids") { stopFlag = true } + + // TODO + // TODO You can edit the SecurityGroupIds property in the UpdateServer API only if you are changing the EndpointType from PUBLIC or VPC_ENDPOINT to VPC. To change security groups associated with your server's VPC endpoint after creation, use the Amazon EC2 ModifyVpcEndpoint API. + // TODO } if d.HasChange("host_key") { @@ -509,6 +518,10 @@ func expandTransferEndpointDetails(tfMap map[string]interface{}) *transfer.Endpo apiObject.AddressAllocationIds = expandStringSet(v) } + if v, ok := tfMap["security_group_ids"].(*schema.Set); ok && v.Len() > 0 { + apiObject.SecurityGroupIds = expandStringSet(v) + } + if v, ok := tfMap["subnet_ids"].(*schema.Set); ok && v.Len() > 0 { apiObject.SubnetIds = expandStringSet(v) } @@ -535,6 +548,10 @@ func flattenTransferEndpointDetails(apiObject *transfer.EndpointDetails) map[str tfMap["address_allocation_ids"] = aws.StringValueSlice(v) } + if v := apiObject.SecurityGroupIds; v != nil { + tfMap["security_group_ids"] = aws.StringValueSlice(v) + } + if v := apiObject.SubnetIds; v != nil { tfMap["subnet_ids"] = aws.StringValueSlice(v) } diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index ef4616f87e52..5ca1f12a3dea 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -104,11 +104,11 @@ The following arguments are supported: **endpoint_details** requires the following: -* `vpc_endpoint_id` - (Optional) The ID of the VPC endpoint. This property can only be used when `endpoint_type` is set to `VPC_ENDPOINT` * `address_allocation_ids` - (Optional) A list of address allocation IDs that are required to attach an Elastic IP address to your SFTP server's endpoint. This property can only be used when `endpoint_type` is set to `VPC`. +* `security_group_ids` - (Optional) A list of security groups IDs that are available to attach to your server's endpoint. If no security groups are specified, the VPC's default security groups are automatically assigned to your endpoint. This property can only be used when `endpoint_type` is set to `VPC`. * `subnet_ids` - (Optional) A list of subnet IDs that are required to host your SFTP server endpoint in your VPC. This property can only be used when `endpoint_type` is set to `VPC`. +* `vpc_endpoint_id` - (Optional) The ID of the VPC endpoint. This property can only be used when `endpoint_type` is set to `VPC_ENDPOINT` * `vpc_id` - (Optional) The VPC ID of the virtual private cloud in which the SFTP server's endpoint will be hosted. This property can only be used when `endpoint_type` is set to `VPC`. -* `security_group_ids` - (Optional) A list of Security Groups Ids. This property can only be used when `endpoint_type` is set to `VPC`. It can't be change after transfer server creation. ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 3a38e51cbbda88f6aaf55b7eed440cc924a96c54 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Mon, 28 Jun 2021 20:26:14 +0000 Subject: [PATCH 0836/1208] Update CHANGELOG.md for #19957 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9470fd018ef0..23b16151287f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ ## 3.48.0 (Unreleased) + +FEATURES: + +* **New Data Source:** `aws_iam_session_context` ([#19957](https://github.com/hashicorp/terraform-provider-aws/issues/19957)) + +BUG FIXES: + +* resource/aws_cloudwatch_event_target: Don't crash if `sqs_target` configuration block is empty. ([#19946](https://github.com/hashicorp/terraform-provider-aws/issues/19946)) + ## 3.47.0 (June 24, 2021) FEATURES: From a470bb6cef96cec15b5d5c72424f1f8e9e1faa56 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 28 Jun 2021 17:17:15 -0400 Subject: [PATCH 0837/1208] r/aws_transfer_server: Enhance 'TestAccAWSTransferServer_vpc'. --- aws/resource_aws_transfer_server_test.go | 42 +++++++++++++++++++----- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index 1480ef6872c6..1d924260e0a6 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -228,6 +228,11 @@ func TestAccAWSTransferServer_securityPolicy(t *testing.T) { func TestAccAWSTransferServer_vpc(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" + eip1ResourceName := "aws_eip.test.0" + eip2ResourceName := "aws_eip.test.0" + defaultSecurityGroupResourceName := "aws_default_security_group.test" + subnetResourceName := "aws_subnet.test" + vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -237,12 +242,17 @@ func TestAccAWSTransferServer_vpc(t *testing.T) { CheckDestroy: testAccCheckAWSTransferServerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSTransferServerVpcConfig(rName), + Config: testAccAWSTransferServerVpcNoSecurityGroupsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip1ResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, { @@ -252,11 +262,17 @@ func TestAccAWSTransferServer_vpc(t *testing.T) { ImportStateVerifyIgnore: []string{"force_destroy"}, }, { - Config: testAccAWSTransferServerVpcUpdateConfig(rName), + Config: testAccAWSTransferServerVpcNoSecurityGroupsUpdateConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip2ResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, }, @@ -468,7 +484,7 @@ func TestAccAWSTransferServer_vpcEndpointId(t *testing.T) { CheckDestroy: testAccCheckAWSTransferServerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSTransferServerVpcEndPointConfig(rName), + Config: testAccAWSTransferServerVpcEndpointConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), @@ -804,7 +820,7 @@ resource "aws_transfer_ssh_key" "test" { `, rName) } -func testAccAWSTransferServerVpcEndPointConfig(rName string) string { +func testAccAWSTransferServerVpcEndpointConfig(rName string) string { return composeConfig( testAccAWSTransferServerConfigBaseVpc(rName), fmt.Sprintf(` @@ -836,7 +852,7 @@ resource "aws_transfer_server" "test" { `, rName)) } -func testAccAWSTransferServerVpcConfig(rName string) string { +func testAccAWSTransferServerVpcNoSecurityGroupsConfig(rName string) string { return composeConfig( testAccAWSTransferServerConfigBaseVpc(rName), fmt.Sprintf(` @@ -850,19 +866,23 @@ resource "aws_eip" "test" { } } +resource "aws_default_security_group" "test" { + vpc_id = aws_vpc.test.id +} + resource "aws_transfer_server" "test" { endpoint_type = "VPC" endpoint_details { address_allocation_ids = [aws_eip.test[0].id] subnet_ids = [aws_subnet.test.id] - vpc_id = aws_vpc.test.id + vpc_id = aws_default_security_group.test.vpc_id } } `, rName)) } -func testAccAWSTransferServerVpcUpdateConfig(rName string) string { +func testAccAWSTransferServerVpcNoSecurityGroupsUpdateConfig(rName string) string { return composeConfig( testAccAWSTransferServerConfigBaseVpc(rName), fmt.Sprintf(` @@ -876,13 +896,17 @@ resource "aws_eip" "test" { } } +resource "aws_default_security_group" "test" { + vpc_id = aws_vpc.test.id +} + resource "aws_transfer_server" "test" { endpoint_type = "VPC" endpoint_details { address_allocation_ids = [aws_eip.test[1].id] subnet_ids = [aws_subnet.test.id] - vpc_id = aws_vpc.test.id + vpc_id = aws_default_security_group.test.vpc_id } } `, rName)) From 5374d7c76669df292114aa8232ac29298b362426 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Tue, 29 Jun 2021 09:42:59 +0300 Subject: [PATCH 0838/1208] fmt --- aws/resource_aws_cloudwatch_event_target.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_cloudwatch_event_target.go b/aws/resource_aws_cloudwatch_event_target.go index f793498ddb0c..eae0046ad53b 100644 --- a/aws/resource_aws_cloudwatch_event_target.go +++ b/aws/resource_aws_cloudwatch_event_target.go @@ -367,7 +367,7 @@ func resourceAwsCloudWatchEventTargetCreate(d *schema.ResourceData, meta interfa busName = v.(string) } - input := buildPutTargetInputStruct(d, meta) + input := buildPutTargetInputStruct(d) log.Printf("[DEBUG] Creating CloudWatch Events Target: %s", input) out, err := conn.PutTargets(input) @@ -474,7 +474,7 @@ func resourceAwsCloudWatchEventTargetRead(d *schema.ResourceData, meta interface func resourceAwsCloudWatchEventTargetUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).cloudwatcheventsconn - input := buildPutTargetInputStruct(d, meta) + input := buildPutTargetInputStruct(d) log.Printf("[DEBUG] Updating CloudWatch Events Target: %s", input) _, err := conn.PutTargets(input) @@ -513,7 +513,7 @@ func resourceAwsCloudWatchEventTargetDelete(d *schema.ResourceData, meta interfa return nil } -func buildPutTargetInputStruct(d *schema.ResourceData, meta interface{}) *events.PutTargetsInput { +func buildPutTargetInputStruct(d *schema.ResourceData) *events.PutTargetsInput { e := &events.Target{ Arn: aws.String(d.Get("arn").(string)), Id: aws.String(d.Get("target_id").(string)), From 3ebf3a27db02a4fbf35468200be95ff3a61b57b6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Jun 2021 09:13:27 -0400 Subject: [PATCH 0839/1208] r/aws_transfer_server: Security Group IDs are not Computed. --- aws/internal/service/transfer/enum.go | 15 +++++++++++++++ aws/resource_aws_transfer_server.go | 18 +++++------------- aws/resource_aws_transfer_server_test.go | 21 +++++---------------- 3 files changed, 25 insertions(+), 29 deletions(-) create mode 100644 aws/internal/service/transfer/enum.go diff --git a/aws/internal/service/transfer/enum.go b/aws/internal/service/transfer/enum.go new file mode 100644 index 000000000000..880b435fa838 --- /dev/null +++ b/aws/internal/service/transfer/enum.go @@ -0,0 +1,15 @@ +package transfer + +const ( + SecurityPolicyName2018_11 = "TransferSecurityPolicy-2018-11" + SecurityPolicyName2020_06 = "TransferSecurityPolicy-2020-06" + SecurityPolicyNameFIPS_2020_06 = "TransferSecurityPolicy-FIPS-2020-06" +) + +func SecurityPolicyName_Values() []string { + return []string{ + SecurityPolicyName2018_11, + SecurityPolicyName2020_06, + SecurityPolicyNameFIPS_2020_06, + } +} diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index c19d62e809b1..207cec30cbae 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -64,29 +64,25 @@ func resourceAwsTransferServer() *schema.Resource { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, ConflictsWith: []string{"endpoint_details.0.vpc_endpoint_id"}, }, "security_group_ids": { Type: schema.TypeSet, Optional: true, - Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, ConflictsWith: []string{"endpoint_details.0.vpc_endpoint_id"}, }, "subnet_ids": { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, ConflictsWith: []string{"endpoint_details.0.vpc_endpoint_id"}, }, "vpc_endpoint_id": { Type: schema.TypeString, Optional: true, - ConflictsWith: []string{"endpoint_details.0.address_allocation_ids", "endpoint_details.0.security_group_ids", "endpoint_details.0.subnet_ids", "endpoint_details.0.vpc_id"}, Computed: true, + ConflictsWith: []string{"endpoint_details.0.address_allocation_ids", "endpoint_details.0.security_group_ids", "endpoint_details.0.subnet_ids", "endpoint_details.0.vpc_id"}, }, "vpc_id": { Type: schema.TypeString, @@ -156,14 +152,10 @@ func resourceAwsTransferServer() *schema.Resource { }, "security_policy_name": { - Type: schema.TypeString, - Optional: true, - Default: "TransferSecurityPolicy-2018-11", - ValidateFunc: validation.StringInSlice([]string{ - "TransferSecurityPolicy-2018-11", - "TransferSecurityPolicy-2020-06", - "TransferSecurityPolicy-FIPS-2020-06", - }, false), + Type: schema.TypeString, + Optional: true, + Default: tftransfer.SecurityPolicyName2018_11, + ValidateFunc: validation.StringInSlice(tftransfer.SecurityPolicyName_Values(), false), }, "tags": tagsSchema(), diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index 1d924260e0a6..fc02972f6419 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -229,8 +229,7 @@ func TestAccAWSTransferServer_vpc(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" eip1ResourceName := "aws_eip.test.0" - eip2ResourceName := "aws_eip.test.0" - defaultSecurityGroupResourceName := "aws_default_security_group.test" + eip2ResourceName := "aws_eip.test.1" subnetResourceName := "aws_subnet.test" vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -248,8 +247,7 @@ func TestAccAWSTransferServer_vpc(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip1ResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), @@ -268,8 +266,7 @@ func TestAccAWSTransferServer_vpc(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip2ResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), @@ -866,17 +863,13 @@ resource "aws_eip" "test" { } } -resource "aws_default_security_group" "test" { - vpc_id = aws_vpc.test.id -} - resource "aws_transfer_server" "test" { endpoint_type = "VPC" endpoint_details { address_allocation_ids = [aws_eip.test[0].id] subnet_ids = [aws_subnet.test.id] - vpc_id = aws_default_security_group.test.vpc_id + vpc_id = aws_vpc.test.id } } `, rName)) @@ -896,17 +889,13 @@ resource "aws_eip" "test" { } } -resource "aws_default_security_group" "test" { - vpc_id = aws_vpc.test.id -} - resource "aws_transfer_server" "test" { endpoint_type = "VPC" endpoint_details { address_allocation_ids = [aws_eip.test[1].id] subnet_ids = [aws_subnet.test.id] - vpc_id = aws_default_security_group.test.vpc_id + vpc_id = aws_vpc.test.id } } `, rName)) From d320a06afe2f5c14aa64778911b13d5223974e4e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 15:13:27 -0400 Subject: [PATCH 0840/1208] r/aws_transfer_server: 'force_destroy' only applies to SERVICE_MANAGED identity providers. Acceptance test output: % TEST=./aws SWEEP=us-east-1,us-east-2,us-west-1,us-west-2 SWEEPARGS=-sweep-run=aws_transfer_server make sweep WARNING: This will destroy infrastructure. Use only in development accounts. go test ./aws -v -sweep=us-east-1,us-east-2,us-west-1,us-west-2 -sweep-run=aws_transfer_server -timeout 60m 2021/06/17 15:10:15 [DEBUG] Running Sweepers for region (us-east-1): 2021/06/17 15:10:15 [DEBUG] Running Sweeper (aws_transfer_server) in region (us-east-1) 2021/06/17 15:10:15 [INFO] AWS Auth provider used: "EnvProvider" 2021/06/17 15:10:15 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/17 15:10:15 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/17 15:10:15 Sweeper Tests ran successfully: - aws_transfer_server 2021/06/17 15:10:15 [DEBUG] Running Sweepers for region (us-east-2): 2021/06/17 15:10:15 [DEBUG] Running Sweeper (aws_transfer_server) in region (us-east-2) 2021/06/17 15:10:15 [INFO] AWS Auth provider used: "EnvProvider" 2021/06/17 15:10:15 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/17 15:10:15 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/17 15:10:16 Sweeper Tests ran successfully: - aws_transfer_server 2021/06/17 15:10:16 [DEBUG] Running Sweepers for region (us-west-1): 2021/06/17 15:10:16 [DEBUG] Running Sweeper (aws_transfer_server) in region (us-west-1) 2021/06/17 15:10:16 [INFO] AWS Auth provider used: "EnvProvider" 2021/06/17 15:10:16 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/17 15:10:16 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/17 15:10:17 Sweeper Tests ran successfully: - aws_transfer_server 2021/06/17 15:10:17 [DEBUG] Running Sweepers for region (us-west-2): 2021/06/17 15:10:17 [DEBUG] Running Sweeper (aws_transfer_server) in region (us-west-2) 2021/06/17 15:10:17 [INFO] AWS Auth provider used: "EnvProvider" 2021/06/17 15:10:17 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/17 15:10:17 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2021/06/17 15:10:19 [DEBUG] Deleting Transfer Server: (s-b61cc3bc5a0e40888) 2021/06/17 15:10:19 [DEBUG] Deleting Transfer Server: (s-a26280943c9345d0b) 2021/06/17 15:10:20 [DEBUG] Waiting for state to become: [] 2021/06/17 15:10:20 [DEBUG] Waiting for state to become: [] 2021/06/17 15:10:21 Sweeper Tests ran successfully: - aws_transfer_server ok github.com/terraform-providers/terraform-provider-aws/aws 8.971s --- aws/resource_aws_transfer_server.go | 18 ++---- aws/resource_aws_transfer_server_test.go | 68 +++++++++++++++----- aws/resource_aws_transfer_user.go | 28 +++++--- website/docs/r/transfer_server.html.markdown | 2 +- 4 files changed, 80 insertions(+), 36 deletions(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 207cec30cbae..628cd9173c9d 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -8,12 +8,11 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/transfer" "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/go-multierror" + multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" - tftransfer "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" @@ -438,7 +437,7 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e func resourceAwsTransferServerDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).transferconn - if d.Get("force_destroy").(bool) { + if d.Get("force_destroy").(bool) && d.Get("identity_provider_type").(string) == transfer.IdentityProviderTypeServiceManaged { input := &transfer.ListUsersInput{ ServerId: aws.String(d.Id()), } @@ -450,15 +449,12 @@ func resourceAwsTransferServerDelete(d *schema.ResourceData, meta interface{}) e } for _, user := range page.Users { - resourceID := tftransfer.UserCreateResourceID(d.Id(), aws.StringValue(user.UserName)) - - r := resourceAwsTransferUser() - d := r.Data(nil) - d.SetId(resourceID) - err := r.Delete(d, meta) + err := transferUserDelete(conn, d.Id(), aws.StringValue(user.UserName)) if err != nil { - deletionErrs = multierror.Append(deletionErrs, fmt.Errorf("error deleting Transfer User (%s): %w", resourceID, err)) + log.Printf("[ERROR] %s", err) + deletionErrs = multierror.Append(deletionErrs, err) + continue } } @@ -477,7 +473,7 @@ func resourceAwsTransferServerDelete(d *schema.ResourceData, meta interface{}) e } } - log.Printf("[DEBUG] Deleting Transfer Server (%s)", d.Id()) + log.Printf("[DEBUG] Deleting Transfer Server: (%s)", d.Id()) _, err := conn.DeleteServer(&transfer.DeleteServerInput{ ServerId: aws.String(d.Id()), }) diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index fc02972f6419..d00b4ff9c3f2 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -9,7 +9,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/acmpca" "github.com/aws/aws-sdk-go/service/transfer" - "github.com/hashicorp/go-multierror" "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" @@ -33,7 +32,7 @@ func testSweepTransferServers(region string) error { } conn := client.(*AWSClient).transferconn input := &transfer.ListServersInput{} - var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) err = conn.ListServersPages(input, func(page *transfer.ListServersOutput, lastPage bool) bool { if page == nil { @@ -45,13 +44,9 @@ func testSweepTransferServers(region string) error { d := r.Data(nil) d.SetId(aws.StringValue(server.ServerId)) d.Set("force_destroy", true) // In lieu of an aws_transfer_user sweeper. - err = r.Delete(d, client) + d.Set("identity_provider_type", server.IdentityProviderType) - if err != nil { - log.Printf("[ERROR] %s", err) - sweeperErrs = multierror.Append(sweeperErrs, err) - continue - } + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } return !lastPage @@ -59,14 +54,20 @@ func testSweepTransferServers(region string) error { if testSweepSkipSweepError(err) { log.Printf("[WARN] Skipping Transfer Server sweep for %s: %s", region, err) - return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors + return nil + } + + if err != nil { + return fmt.Errorf("error listing Transfer Servers (%s): %w", region, err) } + err = testSweepResourceOrchestrator(sweepResources) + if err != nil { - sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Transfer Servers: %w", err)) + return fmt.Errorf("error sweeping Transfer Servers (%s): %w", region, err) } - return sweeperErrs.ErrorOrNil() + return nil } func testAccErrorCheckSkipTransfer(t *testing.T) resource.ErrorCheckFunc { @@ -392,13 +393,48 @@ func TestAccAWSTransferServer_apiGateway(t *testing.T) { CheckDestroy: testAccCheckAWSTransferServerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSTransferServerApiGatewayIdentityProviderTypeConfig(rName), + Config: testAccAWSTransferServerApiGatewayIdentityProviderTypeConfig(rName, false), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "identity_provider_type", "API_GATEWAY"), resource.TestCheckResourceAttrPair(resourceName, "invocation_role", "aws_iam_role.test", "arn"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + +func TestAccAWSTransferServer_apiGateway_forceDestroy(t *testing.T) { + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccAPIGatewayTypeEDGEPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferServerApiGatewayIdentityProviderTypeConfig(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "identity_provider_type", "API_GATEWAY"), + resource.TestCheckResourceAttrPair(resourceName, "invocation_role", "aws_iam_role.test", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, }, }) } @@ -747,18 +783,20 @@ resource "aws_transfer_server" "test" { `) } -func testAccAWSTransferServerApiGatewayIdentityProviderTypeConfig(rName string) string { +func testAccAWSTransferServerApiGatewayIdentityProviderTypeConfig(rName string, forceDestroy bool) string { return composeConfig( testAccAWSTransferServerConfigBaseApiGateway(rName), testAccAWSTransferServerConfigBaseLoggingRole(rName), - ` + fmt.Sprintf(` resource "aws_transfer_server" "test" { identity_provider_type = "API_GATEWAY" url = "${aws_api_gateway_deployment.test.invoke_url}${aws_api_gateway_resource.test.path}" invocation_role = aws_iam_role.test.arn logging_role = aws_iam_role.test.arn + + force_destroy = %[1]t } -`) +`, forceDestroy)) } func testAccAWSTransferServerForceDestroyConfig(rName string) string { diff --git a/aws/resource_aws_transfer_user.go b/aws/resource_aws_transfer_user.go index 61f8fdc5fd3e..b34f1ea9b59a 100644 --- a/aws/resource_aws_transfer_user.go +++ b/aws/resource_aws_transfer_user.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/transfer" + "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" @@ -288,30 +289,39 @@ func resourceAwsTransferUserUpdate(d *schema.ResourceData, meta interface{}) err func resourceAwsTransferUserDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).transferconn + serverID, userName, err := tftransfer.UserParseResourceID(d.Id()) + if err != nil { return fmt.Errorf("error parsing Transfer User ID: %w", err) } - delOpts := &transfer.DeleteUserInput{ - UserName: aws.String(userName), + return transferUserDelete(conn, serverID, userName) +} + +// transferUserDelete attempts to delete a transfer user. +func transferUserDelete(conn *transfer.Transfer, serverID, userName string) error { + id := fmt.Sprintf("%s/%s", serverID, userName) + input := &transfer.DeleteUserInput{ ServerId: aws.String(serverID), + UserName: aws.String(userName), } - log.Printf("[DEBUG] Delete Transfer User Option: %#v", delOpts) + log.Printf("[INFO] Deleting Transfer User: %s", id) + _, err := conn.DeleteUser(input) + + if tfawserr.ErrCodeEquals(err, transfer.ErrCodeResourceNotFoundException) { + return nil + } - _, err = conn.DeleteUser(delOpts) if err != nil { - if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { - return nil - } - return fmt.Errorf("error deleting Transfer User (%s) for Server(%s): %w", userName, serverID, err) + return fmt.Errorf("error deleting Transfer User (%s): %w", id, err) } _, err = waiter.UserDeleted(conn, serverID, userName) if err != nil { - return fmt.Errorf("error waiting for Transfer User (%s) delete: %w", d.Id(), err) + return fmt.Errorf("error waiting for Transfer User (%s) delete: %w", id, err) } return nil diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index 5ca1f12a3dea..257f4703b11c 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -98,7 +98,7 @@ The following arguments are supported: * `url` - (Optional) - URL of the service endpoint used to authenticate users with an `identity_provider_type` of `API_GATEWAY`. * `identity_provider_type` - (Optional) The mode of authentication enabled for this service. The default value is `SERVICE_MANAGED`, which allows you to store and access SFTP user credentials within the service. `API_GATEWAY` indicates that user authentication requires a call to an API Gateway endpoint URL provided by you to integrate an identity provider of your choice. * `logging_role` - (Optional) Amazon Resource Name (ARN) of an IAM role that allows the service to write your SFTP users’ activity to your Amazon CloudWatch logs for monitoring and auditing purposes. -* `force_destroy` - (Optional) A boolean that indicates all users associated with the server should be deleted so that the Server can be destroyed without error. The default value is `false`. +* `force_destroy` - (Optional) A boolean that indicates all users associated with the server should be deleted so that the Server can be destroyed without error. The default value is `false`. This option only applies to servers configured with a `SERVICE_MANAGED` `identity_provider_type`. * `security_policy_name` - (Optional) Specifies the name of the security policy that is attached to the server. Possible values are `TransferSecurityPolicy-2018-11`, `TransferSecurityPolicy-2020-06`, and `TransferSecurityPolicy-FIPS-2020-06`. Default value is: `TransferSecurityPolicy-2018-11`. * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. From 4a36d75bfe0f3f5be2fae083e0c0d569750e8588 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 17:03:27 -0400 Subject: [PATCH 0841/1208] Serialize Transfer acceptance tests. --- aws/resource_aws_transfer_server_test.go | 48 +++++++++++------------ aws/resource_aws_transfer_ssh_key_test.go | 4 +- aws/resource_aws_transfer_test.go | 46 ++++++++++++++++++++++ aws/resource_aws_transfer_user_test.go | 24 ++++++------ 4 files changed, 84 insertions(+), 38 deletions(-) create mode 100644 aws/resource_aws_transfer_test.go diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index d00b4ff9c3f2..efd9601cd4ac 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -76,13 +76,13 @@ func testAccErrorCheckSkipTransfer(t *testing.T) resource.ErrorCheckFunc { ) } -func TestAccAWSTransferServer_basic(t *testing.T) { +func testAccAWSTransferServer_basic(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" iamRoleResourceName := "aws_iam_role.test" rName := acctest.RandomWithPrefix("tf-acc-test") - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -143,11 +143,11 @@ func TestAccAWSTransferServer_basic(t *testing.T) { }) } -func TestAccAWSTransferServer_domain(t *testing.T) { +func testAccAWSTransferServer_domain(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -170,11 +170,11 @@ func TestAccAWSTransferServer_domain(t *testing.T) { }) } -func TestAccAWSTransferServer_disappears(t *testing.T) { +func testAccAWSTransferServer_disappears(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -192,11 +192,11 @@ func TestAccAWSTransferServer_disappears(t *testing.T) { }) } -func TestAccAWSTransferServer_securityPolicy(t *testing.T) { +func testAccAWSTransferServer_securityPolicy(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -226,7 +226,7 @@ func TestAccAWSTransferServer_securityPolicy(t *testing.T) { }) } -func TestAccAWSTransferServer_vpc(t *testing.T) { +func testAccAWSTransferServer_vpc(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" eip1ResourceName := "aws_eip.test.0" @@ -235,7 +235,7 @@ func TestAccAWSTransferServer_vpc(t *testing.T) { vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -279,12 +279,12 @@ func TestAccAWSTransferServer_vpc(t *testing.T) { // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/16556 /* -func TestAccAWSTransferServer_updateEndpointType(t *testing.T) { +func testAccAWSTransferServer_updateEndpointType(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" rName := acctest.RandomWithPrefix("tf-acc-test") - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -318,7 +318,7 @@ func TestAccAWSTransferServer_updateEndpointType(t *testing.T) { } */ -func TestAccAWSTransferServer_protocols(t *testing.T) { +func testAccAWSTransferServer_protocols(t *testing.T) { var s transfer.DescribedServer var ca acmpca.CertificateAuthority resourceName := "aws_transfer_server.test" @@ -326,7 +326,7 @@ func TestAccAWSTransferServer_protocols(t *testing.T) { acmCertificateResourceName := "aws_acm_certificate.test" rName := acctest.RandomWithPrefix("tf-acc-test") - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccAPIGatewayTypeEDGEPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -381,12 +381,12 @@ func TestAccAWSTransferServer_protocols(t *testing.T) { }) } -func TestAccAWSTransferServer_apiGateway(t *testing.T) { +func testAccAWSTransferServer_apiGateway(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" rName := acctest.RandomWithPrefix("tf-acc-test") - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccAPIGatewayTypeEDGEPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -410,12 +410,12 @@ func TestAccAWSTransferServer_apiGateway(t *testing.T) { }) } -func TestAccAWSTransferServer_apiGateway_forceDestroy(t *testing.T) { +func testAccAWSTransferServer_apiGateway_forceDestroy(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" rName := acctest.RandomWithPrefix("tf-acc-test") - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccAPIGatewayTypeEDGEPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -439,7 +439,7 @@ func TestAccAWSTransferServer_apiGateway_forceDestroy(t *testing.T) { }) } -func TestAccAWSTransferServer_forceDestroy(t *testing.T) { +func testAccAWSTransferServer_forceDestroy(t *testing.T) { var s transfer.DescribedServer var u transfer.DescribedUser var k transfer.SshPublicKey @@ -448,7 +448,7 @@ func TestAccAWSTransferServer_forceDestroy(t *testing.T) { sshKeyResourceName := "aws_transfer_ssh_key.test" rName := acctest.RandomWithPrefix("tf-acc-test") - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -473,12 +473,12 @@ func TestAccAWSTransferServer_forceDestroy(t *testing.T) { }) } -func TestAccAWSTransferServer_hostKey(t *testing.T) { +func testAccAWSTransferServer_hostKey(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" hostKey := "test-fixtures/transfer-ssh-rsa-key" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -501,7 +501,7 @@ func TestAccAWSTransferServer_hostKey(t *testing.T) { }) } -func TestAccAWSTransferServer_vpcEndpointId(t *testing.T) { +func testAccAWSTransferServer_vpcEndpointId(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -510,7 +510,7 @@ func TestAccAWSTransferServer_vpcEndpointId(t *testing.T) { t.Skip("Transfer Server VPC_ENDPOINT endpoint type is not supported in GovCloud partition") } - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, diff --git a/aws/resource_aws_transfer_ssh_key_test.go b/aws/resource_aws_transfer_ssh_key_test.go index 9437daee8f8d..c7bc79c9c8d5 100644 --- a/aws/resource_aws_transfer_ssh_key_test.go +++ b/aws/resource_aws_transfer_ssh_key_test.go @@ -11,11 +11,11 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func TestAccAWSTransferSshKey_basic(t *testing.T) { +func testAccAWSTransferSshKey_basic(t *testing.T) { var conf transfer.SshPublicKey rName := acctest.RandString(5) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, diff --git a/aws/resource_aws_transfer_test.go b/aws/resource_aws_transfer_test.go new file mode 100644 index 000000000000..49a5ef44dad2 --- /dev/null +++ b/aws/resource_aws_transfer_test.go @@ -0,0 +1,46 @@ +package aws + +import ( + "testing" +) + +func TestAccAWSTransfer_serial(t *testing.T) { + testCases := map[string]map[string]func(t *testing.T){ + "Server": { + "basic": testAccAWSTransferServer_basic, + "disappears": testAccAWSTransferServer_disappears, + "APIGateway": testAccAWSTransferServer_apiGateway, + "APIGatewayForceDestroy": testAccAWSTransferServer_apiGateway_forceDestroy, + "Domain": testAccAWSTransferServer_domain, + "ForceDestroy": testAccAWSTransferServer_forceDestroy, + "HostKey": testAccAWSTransferServer_hostKey, + "Protocols": testAccAWSTransferServer_protocols, + "SecurityPolicy": testAccAWSTransferServer_securityPolicy, + "VPC": testAccAWSTransferServer_vpc, + "VPCEndpointID": testAccAWSTransferServer_vpcEndpointId, + }, + "SSHKey": { + "basic": testAccAWSTransferSshKey_basic, + }, + "User": { + "basic": testAccAWSTransferUser_basic, + "disappears": testAccAWSTransferUser_disappears, + "HomeDirectoryMappings": testAccAWSTransferUser_homeDirectoryMappings, + "ModifyWithOptions": testAccAWSTransferUser_modifyWithOptions, + "Posix": testAccAWSTransferUser_posix, + "UserNameValidation": testAccAWSTransferUser_UserName_Validation, + }, + } + + for group, m := range testCases { + m := m + t.Run(group, func(t *testing.T) { + for name, tc := range m { + tc := tc + t.Run(name, func(t *testing.T) { + tc(t) + }) + } + }) + } +} diff --git a/aws/resource_aws_transfer_user_test.go b/aws/resource_aws_transfer_user_test.go index c92e735b503f..def98d4f7532 100644 --- a/aws/resource_aws_transfer_user_test.go +++ b/aws/resource_aws_transfer_user_test.go @@ -13,12 +13,12 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -func TestAccAWSTransferUser_basic(t *testing.T) { +func testAccAWSTransferUser_basic(t *testing.T) { var conf transfer.DescribedUser resourceName := "aws_transfer_user.test" rName := acctest.RandString(10) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -43,12 +43,12 @@ func TestAccAWSTransferUser_basic(t *testing.T) { }) } -func TestAccAWSTransferUser_posix(t *testing.T) { +func testAccAWSTransferUser_posix(t *testing.T) { var conf transfer.DescribedUser resourceName := "aws_transfer_user.test" rName := acctest.RandString(10) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -82,13 +82,13 @@ func TestAccAWSTransferUser_posix(t *testing.T) { }) } -func TestAccAWSTransferUser_modifyWithOptions(t *testing.T) { +func testAccAWSTransferUser_modifyWithOptions(t *testing.T) { var conf transfer.DescribedUser resourceName := "aws_transfer_user.test" rName := acctest.RandString(10) rName2 := acctest.RandString(10) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -129,13 +129,13 @@ func TestAccAWSTransferUser_modifyWithOptions(t *testing.T) { }) } -func TestAccAWSTransferUser_disappears(t *testing.T) { +func testAccAWSTransferUser_disappears(t *testing.T) { var serverConf transfer.DescribedServer var userConf transfer.DescribedUser rName := acctest.RandString(10) resourceName := "aws_transfer_user.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -154,8 +154,8 @@ func TestAccAWSTransferUser_disappears(t *testing.T) { }) } -func TestAccAWSTransferUser_UserName_Validation(t *testing.T) { - resource.ParallelTest(t, resource.TestCase{ +func testAccAWSTransferUser_UserName_Validation(t *testing.T) { + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, @@ -191,12 +191,12 @@ func TestAccAWSTransferUser_UserName_Validation(t *testing.T) { }) } -func TestAccAWSTransferUser_homeDirectoryMappings(t *testing.T) { +func testAccAWSTransferUser_homeDirectoryMappings(t *testing.T) { var conf transfer.DescribedUser rName := acctest.RandString(10) resourceName := "aws_transfer_user.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), Providers: testAccProviders, From 47f3107079149fc42d4fd3e06f15a7293c563352 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Jun 2021 09:59:31 -0400 Subject: [PATCH 0842/1208] r/aws_transfer_server: Prevent "InvalidRequestException: Changing VpcId is not supported". --- aws/resource_aws_transfer_server.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 628cd9173c9d..7d91952c85f3 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -1,6 +1,7 @@ package aws import ( + "context" "fmt" "log" "time" @@ -9,10 +10,12 @@ import ( "github.com/aws/aws-sdk-go/service/transfer" "github.com/hashicorp/aws-sdk-go-base/tfawserr" multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" + tftransfer "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" @@ -28,6 +31,18 @@ func resourceAwsTransferServer() *schema.Resource { State: schema.ImportStatePassthrough, }, + CustomizeDiff: customdiff.Sequence( + SetTagsDiff, + customdiff.ForceNewIfChange("endpoint_details.0.vpc_id", func(_ context.Context, old, new, meta interface{}) bool { + // "InvalidRequestException: Changing VpcId is not supported". + if old, new := old.(string), new.(string); old != "" && new != old { + return true + } + + return false + }), + ), + Schema: map[string]*schema.Schema{ "arn": { Type: schema.TypeString, @@ -165,8 +180,6 @@ func resourceAwsTransferServer() *schema.Resource { Optional: true, }, }, - - CustomizeDiff: SetTagsDiff, } } From d8c9b285b71561a7e2571d0172de11302027bbd1 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 29 Jun 2021 14:29:34 +0000 Subject: [PATCH 0843/1208] Update CHANGELOG.md for #19982 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23b16151287f..7b858d4b4e8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ FEATURES: * **New Data Source:** `aws_iam_session_context` ([#19957](https://github.com/hashicorp/terraform-provider-aws/issues/19957)) +ENHANCEMENTS: + +* resource/aws_fsx_windows_file_system: Add `audit_log_configuration` argument. ([#19970](https://github.com/hashicorp/terraform-provider-aws/issues/19970)) + BUG FIXES: * resource/aws_cloudwatch_event_target: Don't crash if `sqs_target` configuration block is empty. ([#19946](https://github.com/hashicorp/terraform-provider-aws/issues/19946)) From 32f31e5ce2795ef2abe7d5ad729ba18e79ff1eae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jun 2021 14:36:37 +0000 Subject: [PATCH 0844/1208] build(deps): bump github.com/hashicorp/terraform-plugin-sdk/v2 Bumps [github.com/hashicorp/terraform-plugin-sdk/v2](https://github.com/hashicorp/terraform-plugin-sdk) from 2.6.1 to 2.7.0. - [Release notes](https://github.com/hashicorp/terraform-plugin-sdk/releases) - [Changelog](https://github.com/hashicorp/terraform-plugin-sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/terraform-plugin-sdk/compare/v2.6.1...v2.7.0) --- updated-dependencies: - dependency-name: github.com/hashicorp/terraform-plugin-sdk/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 52 +- .../github.com/hashicorp/go-plugin/client.go | 11 +- .../github.com/hashicorp/go-plugin/server.go | 9 +- .../internal/version/version.go | 2 +- .../terraform-exec/tfexec/exit_errors.go | 13 +- .../hashicorp/terraform-exec/tfexec/get.go | 52 + .../terraform-exec/tfexec/options.go | 17 +- .../terraform-exec/tfexec/upgrade013.go | 68 + .../terraform-exec/tfexec/version.go | 3 +- .../hashicorp/terraform-json/.go-version | 1 + .../hashicorp/terraform-json/go.mod | 2 + .../hashicorp/terraform-json/go.sum | 12 + .../hashicorp/terraform-json/plan.go | 20 +- .../hashicorp/terraform-json/schemas.go | 17 +- .../hashicorp/terraform-json/state.go | 20 +- .../tfprotov6/data_source.go | 98 + .../tfprotov6/diagnostic.go | 58 + .../terraform-plugin-go/tfprotov6/doc.go | 29 + .../tfprotov6/dynamic_value.go | 87 + .../internal/fromproto/attribute_path.go | 63 + .../internal/fromproto/data_source.go | 53 + .../internal/fromproto/diagnostic.go | 42 + .../tfprotov6/internal/fromproto/provider.go | 106 + .../tfprotov6/internal/fromproto/resource.go | 206 + .../tfprotov6/internal/fromproto/schema.go | 146 + .../tfprotov6/internal/fromproto/state.go | 13 + .../internal/fromproto/string_kind.go | 10 + .../tfprotov6/internal/fromproto/types.go | 13 + .../tfprotov6/internal/tfplugin6/generate.sh | 16 + .../internal/tfplugin6/tfplugin6.pb.go | 4123 +++++++++++++++++ .../internal/tfplugin6/tfplugin6.proto | 321 ++ .../internal/tfplugin6/tfplugin6_grpc.pb.go | 505 ++ .../internal/toproto/attribute_path.go | 98 + .../tfprotov6/internal/toproto/data_source.go | 61 + .../tfprotov6/internal/toproto/diagnostic.go | 50 + .../internal/toproto/dynamic_value.go | 35 + .../tfprotov6/internal/toproto/provider.go | 117 + .../tfprotov6/internal/toproto/resource.go | 212 + .../tfprotov6/internal/toproto/schema.go | 149 + .../tfprotov6/internal/toproto/state.go | 21 + .../tfprotov6/internal/toproto/string_kind.go | 18 + .../terraform-plugin-go/tfprotov6/provider.go | 181 + .../terraform-plugin-go/tfprotov6/resource.go | 451 ++ .../terraform-plugin-go/tfprotov6/schema.go | 293 ++ .../tfprotov6/server/doc.go | 6 + .../tfprotov6/server/plugin.go | 45 + .../tfprotov6/server/server.go | 357 ++ .../terraform-plugin-go/tfprotov6/state.go | 79 + .../tfprotov6/string_kind.go | 25 + .../v2/helper/resource/plugin.go | 104 +- .../v2/helper/resource/testing.go | 8 + .../v2/helper/resource/testing_new.go | 25 +- .../v2/helper/resource/testing_new_config.go | 70 +- .../resource/testing_new_import_state.go | 20 +- .../v2/helper/schema/schema.go | 34 +- .../terraform-plugin-sdk/v2/meta/meta.go | 2 +- .../terraform-plugin-sdk/v2/plugin/debug.go | 16 +- .../terraform-plugin-sdk/v2/plugin/serve.go | 44 +- .../mitchellh/copystructure/.travis.yml | 12 - .../mitchellh/copystructure/README.md | 42 +- .../mitchellh/copystructure/copystructure.go | 93 +- .../github.com/mitchellh/copystructure/go.mod | 4 +- .../github.com/mitchellh/copystructure/go.sum | 4 +- .../mitchellh/reflectwalk/reflectwalk.go | 18 + .../go-cty/cty/function/stdlib/collection.go | 77 +- .../go-cty/cty/function/stdlib/sequence.go | 4 + .../golang.org/x/sys/unix/asm_aix_ppc64.s | 1 + .../golang.org/x/sys/unix/asm_linux_386.s | 1 + .../golang.org/x/sys/unix/asm_linux_amd64.s | 1 + .../golang.org/x/sys/unix/asm_linux_arm.s | 1 + .../golang.org/x/sys/unix/asm_linux_arm64.s | 1 + .../golang.org/x/sys/unix/asm_linux_mips64x.s | 1 + .../golang.org/x/sys/unix/asm_linux_mipsx.s | 1 + .../golang.org/x/sys/unix/asm_linux_ppc64x.s | 1 + .../golang.org/x/sys/unix/asm_linux_riscv64.s | 4 +- .../golang.org/x/sys/unix/asm_linux_s390x.s | 3 +- .../x/sys/unix/asm_openbsd_mips64.s | 1 + .../golang.org/x/sys/unix/asm_solaris_amd64.s | 1 + .../x/sys/unix/fcntl_linux_32bit.go | 4 +- .../vendor/golang.org/x/sys/unix/fdset.go | 4 +- .../golang.org/x/sys/unix/ioctl_linux.go | 196 + .../vendor/golang.org/x/sys/unix/mkerrors.sh | 7 +- .../golang.org/x/sys/unix/syscall_darwin.go | 11 + .../golang.org/x/sys/unix/syscall_illumos.go | 51 +- .../golang.org/x/sys/unix/syscall_linux.go | 182 +- .../x/sys/unix/syscall_linux_ppc.go | 272 ++ .../x/sys/unix/syscall_zos_s390x.go | 52 +- .../x/sys/unix/zerrors_freebsd_arm.go | 9 + .../golang.org/x/sys/unix/zerrors_linux.go | 27 +- .../x/sys/unix/zerrors_linux_ppc.go | 860 ++++ .../x/sys/unix/zerrors_linux_s390x.go | 2 + .../x/sys/unix/zerrors_solaris_amd64.go | 3 + .../x/sys/unix/zerrors_zos_s390x.go | 29 + .../x/sys/unix/zsyscall_darwin_386.1_13.s | 1 + .../x/sys/unix/zsyscall_darwin_386.s | 1 + .../x/sys/unix/zsyscall_darwin_amd64.1_13.s | 1 + .../x/sys/unix/zsyscall_darwin_amd64.s | 1 + .../x/sys/unix/zsyscall_darwin_arm.1_13.s | 1 + .../x/sys/unix/zsyscall_darwin_arm.s | 1 + .../x/sys/unix/zsyscall_darwin_arm64.1_13.s | 1 + .../x/sys/unix/zsyscall_darwin_arm64.s | 1 + .../x/sys/unix/zsyscall_linux_ppc.go | 762 +++ .../x/sys/unix/zsyscall_zos_s390x.go | 42 +- .../x/sys/unix/zsysnum_linux_386.go | 1 + .../x/sys/unix/zsysnum_linux_amd64.go | 1 + .../x/sys/unix/zsysnum_linux_arm.go | 1 + .../x/sys/unix/zsysnum_linux_arm64.go | 1 + .../x/sys/unix/zsysnum_linux_mips.go | 1 + .../x/sys/unix/zsysnum_linux_mips64.go | 1 + .../x/sys/unix/zsysnum_linux_mips64le.go | 1 + .../x/sys/unix/zsysnum_linux_mipsle.go | 1 + .../x/sys/unix/zsysnum_linux_ppc.go | 434 ++ .../x/sys/unix/zsysnum_linux_ppc64.go | 1 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 1 + .../x/sys/unix/zsysnum_linux_riscv64.go | 1 + .../x/sys/unix/zsysnum_linux_s390x.go | 1 + .../x/sys/unix/zsysnum_linux_sparc64.go | 1 + .../x/sys/unix/ztypes_darwin_386.go | 7 + .../x/sys/unix/ztypes_darwin_amd64.go | 7 + .../x/sys/unix/ztypes_darwin_arm.go | 7 + .../x/sys/unix/ztypes_darwin_arm64.go | 7 + .../x/sys/unix/ztypes_illumos_amd64.go | 4 +- .../golang.org/x/sys/unix/ztypes_linux.go | 30 +- .../golang.org/x/sys/unix/ztypes_linux_ppc.go | 627 +++ .../golang.org/x/sys/unix/ztypes_zos_s390x.go | 4 + awsproviderlint/vendor/modules.txt | 23 +- 127 files changed, 12276 insertions(+), 390 deletions(-) create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/get.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/upgrade013.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-json/.go-version create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/data_source.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/diagnostic.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/doc.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/dynamic_value.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/attribute_path.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/data_source.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/diagnostic.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/provider.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/resource.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/schema.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/state.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/string_kind.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/types.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/generate.sh create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6.pb.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6.proto create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6_grpc.pb.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/attribute_path.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/data_source.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/diagnostic.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/dynamic_value.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/provider.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/resource.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/schema.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/state.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/string_kind.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/provider.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/resource.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/schema.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/doc.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/plugin.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/server.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/state.go create mode 100644 awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/string_kind.go delete mode 100644 awsproviderlint/vendor/github.com/mitchellh/copystructure/.travis.yml create mode 100644 awsproviderlint/vendor/golang.org/x/sys/unix/ioctl_linux.go create mode 100644 awsproviderlint/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go create mode 100644 awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go create mode 100644 awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go create mode 100644 awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go create mode 100644 awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 398220035ce7..e5c3fcf0a8ec 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -5,6 +5,6 @@ go 1.16 require ( github.com/aws/aws-sdk-go v1.38.68 github.com/bflad/tfproviderlint v0.26.0 - github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 + github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb ) diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index bb2008b449fe..744b783008c1 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -42,6 +42,10 @@ github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuN github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= @@ -99,13 +103,14 @@ github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.1.0 h1:4pl5BV4o7ZG/lterP4S6WzJ6xr49Ba5ET9ygheTYahk= -github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= -github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc= -github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= +github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -149,8 +154,8 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs= @@ -191,8 +196,9 @@ github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39 github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= -github.com/hashicorp/go-plugin v1.4.0 h1:b0O7rs5uiJ99Iu9HugEzsM67afboErkHUWddUSpUO3A= github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= +github.com/hashicorp/go-plugin v1.4.1 h1:6UltRQlLN9iZO513VveELp5xyaFxVD2+1OVylE+2E+w= +github.com/hashicorp/go-plugin v1.4.1/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -216,20 +222,20 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A= github.com/hashicorp/terraform-exec v0.10.0/go.mod h1:tOT8j1J8rP05bZBGWXfMyU3HkLi1LWyqL3Bzsc3CJjo= github.com/hashicorp/terraform-exec v0.13.0/go.mod h1:SGhto91bVRlgXQWcJ5znSz+29UZIa8kpBbkGwQ+g9E8= -github.com/hashicorp/terraform-exec v0.13.3 h1:R6L2mNpDGSEqtLrSONN8Xth0xYwNrnEVzDz6LF/oJPk= -github.com/hashicorp/terraform-exec v0.13.3/go.mod h1:SSg6lbUsVB3DmFyCPjBPklqf6EYGX0TlQ6QTxOlikDU= +github.com/hashicorp/terraform-exec v0.14.0 h1:UQoUcxKTZZXhyyK68Cwn4mApT4mnFPmEXPiqaHL9r+w= +github.com/hashicorp/terraform-exec v0.14.0/go.mod h1:qrAASDq28KZiMPDnQ02sFS9udcqEkRly002EA2izXTA= github.com/hashicorp/terraform-json v0.5.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU= github.com/hashicorp/terraform-json v0.8.0/go.mod h1:3defM4kkMfttwiE7VakJDwCd4R+umhSQnvJwORXbprE= -github.com/hashicorp/terraform-json v0.10.0 h1:9syPD/Y5t+3uFjG8AiWVPu1bklJD8QB8iTCaJASc8oQ= -github.com/hashicorp/terraform-json v0.10.0/go.mod h1:3defM4kkMfttwiE7VakJDwCd4R+umhSQnvJwORXbprE= +github.com/hashicorp/terraform-json v0.12.0 h1:8czPgEEWWPROStjkWPUnTQDXmpmZPlkQAwYYLETaTvw= +github.com/hashicorp/terraform-json v0.12.0/go.mod h1:pmbq9o4EuL43db5+0ogX10Yofv1nozM+wskr/bGFJpI= github.com/hashicorp/terraform-plugin-go v0.2.1/go.mod h1:10V6F3taeDWVAoLlkmArKttR3IULlRWFAGtQIQTIDr4= github.com/hashicorp/terraform-plugin-go v0.3.0 h1:AJqYzP52JFYl9NABRI7smXI1pNjgR5Q/y2WyVJ/BOZA= github.com/hashicorp/terraform-plugin-go v0.3.0/go.mod h1:dFHsQMaTLpON2gWhVWT96fvtlc/MF1vSy3OdMhWBzdM= github.com/hashicorp/terraform-plugin-sdk v1.16.1 h1:G2iK7MBT4LuNcVASPXWS1ciBUuIm8oIY0zRfCmi3xy4= github.com/hashicorp/terraform-plugin-sdk v1.16.1/go.mod h1:KSsGcuZ1JRqnmYzz+sWIiUwNvJkzXbGRIdefwFfOdyY= github.com/hashicorp/terraform-plugin-sdk/v2 v2.5.0/go.mod h1:z+cMZ0iswzZOahBJ3XmNWgWkVnAd2bl8g+FhyyuPDH4= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 h1:OZ+Q7irJBDhb71XzMSPGJvTIW101sOmbDg5i5qV1odY= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1/go.mod h1:72j8cKfs9IirGhPMXJJWLTvRUK4zATtrCOvs2avDlo8= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 h1:SuI59MqNjYDrL7EfqHX9V6P/24isgqYx/FdglwVs9bg= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0/go.mod h1:grseeRo9g3yNkYW09iFlV8LG78jTa1ssBgouogQg/RU= github.com/hashicorp/terraform-plugin-test/v2 v2.1.3/go.mod h1:pmaUHiUtDL/8Mz3FuyZ/vRDb0LpaOWQjVRW9ORF7FHs= github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= @@ -274,6 +280,7 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= @@ -288,8 +295,9 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mitchellh/cli v1.1.1/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -303,8 +311,9 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= @@ -319,6 +328,7 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= @@ -356,8 +366,8 @@ github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLE github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.7.1/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o= -github.com/zclconf/go-cty v1.8.2 h1:u+xZfBKgpycDnTNjPhGiTEYZS5qS/Sb5MqSfm7vzcjg= -github.com/zclconf/go-cty v1.8.2/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.8.4 h1:pwhhz5P+Fjxse7S7UriBrMu6AUJSZM5pKqGem1PjGAs= +github.com/zclconf/go-cty v1.8.4/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zclconf/go-cty-yaml v1.0.2/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -375,8 +385,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -495,8 +506,9 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 h1:RX8C8PRZc2hTIod4ds8ij+/4RQX3AqhYj3uOHmyaz4E= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/awsproviderlint/vendor/github.com/hashicorp/go-plugin/client.go b/awsproviderlint/vendor/github.com/hashicorp/go-plugin/client.go index 780a3121da33..6b42975b399f 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/go-plugin/client.go +++ b/awsproviderlint/vendor/github.com/hashicorp/go-plugin/client.go @@ -209,9 +209,10 @@ type ClientConfig struct { // already-running plugin process. You can retrieve this information by // calling ReattachConfig on Client. type ReattachConfig struct { - Protocol Protocol - Addr net.Addr - Pid int + Protocol Protocol + ProtocolVersion int + Addr net.Addr + Pid int // Test is set to true if this is reattaching to to a plugin in "test mode" // (see ServeConfig.Test). In this mode, client.Kill will NOT kill the @@ -839,6 +840,10 @@ func (c *Client) reattach() (net.Addr, error) { c.protocol = ProtocolNetRPC } + if c.config.Reattach.Test { + c.negotiatedVersion = c.config.Reattach.ProtocolVersion + } + // If we're in test mode, we do NOT set the process. This avoids the // process being killed (the only purpose we have for c.process), since // in test mode the process is responsible for exiting on its own. diff --git a/awsproviderlint/vendor/github.com/hashicorp/go-plugin/server.go b/awsproviderlint/vendor/github.com/hashicorp/go-plugin/server.go index 80f0ac396a4d..7a58cc391975 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/go-plugin/server.go +++ b/awsproviderlint/vendor/github.com/hashicorp/go-plugin/server.go @@ -415,10 +415,11 @@ func Serve(opts *ServeConfig) { // quite ready if they connect immediately but the client should // retry a few times. ch <- &ReattachConfig{ - Protocol: protoType, - Addr: listener.Addr(), - Pid: os.Getpid(), - Test: true, + Protocol: protoType, + ProtocolVersion: protoVersion, + Addr: listener.Addr(), + Pid: os.Getpid(), + Test: true, } } diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/internal/version/version.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/internal/version/version.go index 4f26db7fb041..4d43e000bbb9 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/internal/version/version.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/internal/version/version.go @@ -1,6 +1,6 @@ package version -const version = "0.13.3" +const version = "0.14.0" // ModuleVersion returns the current version of the github.com/hashicorp/terraform-exec Go module. // This is a function to allow for future possible enhancement using debug.BuildInfo. diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/exit_errors.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/exit_errors.go index 5596fa2a136c..359e6ad0e174 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/exit_errors.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/exit_errors.go @@ -243,5 +243,16 @@ type ErrTFVersionMismatch struct { } func (e *ErrTFVersionMismatch) Error() string { - return "terraform core version not supported by configuration" + version := "version" + if e.TFVersion != "" { + version = e.TFVersion + } + + requirement := "" + if e.Constraint != "" { + requirement = fmt.Sprintf(" (%s required)", e.Constraint) + } + + return fmt.Sprintf("terraform %s not supported by configuration%s", + version, requirement) } diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/get.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/get.go new file mode 100644 index 000000000000..5bac9b1976d4 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/get.go @@ -0,0 +1,52 @@ +package tfexec + +import ( + "context" + "fmt" + "os/exec" +) + +type getCmdConfig struct { + dir string + update bool +} + +// GetCmdOption represents options used in the Get method. +type GetCmdOption interface { + configureGet(*getCmdConfig) +} + +func (opt *DirOption) configureGet(conf *getCmdConfig) { + conf.dir = opt.path +} + +func (opt *UpdateOption) configureGet(conf *getCmdConfig) { + conf.update = opt.update +} + +// Get represents the terraform get subcommand. +func (tf *Terraform) Get(ctx context.Context, opts ...GetCmdOption) error { + cmd, err := tf.getCmd(ctx, opts...) + if err != nil { + return err + } + return tf.runTerraformCmd(ctx, cmd) +} + +func (tf *Terraform) getCmd(ctx context.Context, opts ...GetCmdOption) (*exec.Cmd, error) { + c := getCmdConfig{} + + for _, o := range opts { + o.configureGet(&c) + } + + args := []string{"get", "-no-color"} + + args = append(args, "-update="+fmt.Sprint(c.update)) + + if c.dir != "" { + args = append(args, c.dir) + } + + return tf.buildTerraformCmd(ctx, nil, args...), nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/options.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/options.go index 6d20869bd46e..d78901071b80 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/options.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/options.go @@ -207,10 +207,11 @@ type ReattachInfo map[string]ReattachConfig // ReattachConfig holds the information Terraform needs to be able to attach // itself to a provider process, so it can drive the process. type ReattachConfig struct { - Protocol string - Pid int - Test bool - Addr ReattachConfigAddr + Protocol string + ProtocolVersion int + Pid int + Test bool + Addr ReattachConfigAddr } // ReattachConfigAddr is a JSON-encoding friendly version of net.Addr. @@ -289,6 +290,14 @@ func Target(resource string) *TargetOption { return &TargetOption{resource} } +type UpdateOption struct { + update bool +} + +func Update(update bool) *UpdateOption { + return &UpdateOption{update} +} + type UpgradeOption struct { upgrade bool } diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/upgrade013.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/upgrade013.go new file mode 100644 index 000000000000..f1f444e2f422 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/upgrade013.go @@ -0,0 +1,68 @@ +package tfexec + +import ( + "context" + "fmt" + "os/exec" +) + +type upgrade013Config struct { + dir string + + reattachInfo ReattachInfo +} + +var defaultUpgrade013Options = upgrade013Config{} + +// Upgrade013Option represents options used in the Destroy method. +type Upgrade013Option interface { + configureUpgrade013(*upgrade013Config) +} + +func (opt *DirOption) configureUpgrade013(conf *upgrade013Config) { + conf.dir = opt.path +} + +func (opt *ReattachOption) configureUpgrade013(conf *upgrade013Config) { + conf.reattachInfo = opt.info +} + +// Upgrade013 represents the terraform 0.13upgrade subcommand. +func (tf *Terraform) Upgrade013(ctx context.Context, opts ...Upgrade013Option) error { + cmd, err := tf.upgrade013Cmd(ctx, opts...) + if err != nil { + return err + } + return tf.runTerraformCmd(ctx, cmd) +} + +func (tf *Terraform) upgrade013Cmd(ctx context.Context, opts ...Upgrade013Option) (*exec.Cmd, error) { + err := tf.compatible(ctx, tf0_13_0, tf0_14_0) + if err != nil { + return nil, fmt.Errorf("terraform 0.13upgrade is only supported in 0.13 releases: %w", err) + } + + c := defaultUpgrade013Options + + for _, o := range opts { + o.configureUpgrade013(&c) + } + + args := []string{"0.13upgrade", "-no-color", "-yes"} + + // optional positional argument + if c.dir != "" { + args = append(args, c.dir) + } + + mergeEnv := map[string]string{} + if c.reattachInfo != nil { + reattachStr, err := c.reattachInfo.marshalString() + if err != nil { + return nil, err + } + mergeEnv[reattachEnvVar] = reattachStr + } + + return tf.buildTerraformCmd(ctx, mergeEnv, args...), nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/version.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/version.go index b6496ab6e943..2e842a8758fe 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/version.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-exec/tfexec/version.go @@ -10,13 +10,14 @@ import ( "strings" "github.com/hashicorp/go-version" - "github.com/hashicorp/terraform-json" + tfjson "github.com/hashicorp/terraform-json" ) var ( tf0_7_7 = version.Must(version.NewVersion("0.7.7")) tf0_12_0 = version.Must(version.NewVersion("0.12.0")) tf0_13_0 = version.Must(version.NewVersion("0.13.0")) + tf0_14_0 = version.Must(version.NewVersion("0.14.0")) tf0_15_0 = version.Must(version.NewVersion("0.15.0")) ) diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/.go-version b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/.go-version new file mode 100644 index 000000000000..e71519696fb2 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/.go-version @@ -0,0 +1 @@ +1.16 diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/go.mod b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/go.mod index 415bf18bf3b1..785dea4e7b7c 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/go.mod +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/go.mod @@ -5,5 +5,7 @@ go 1.13 require ( github.com/davecgh/go-spew v1.1.1 github.com/google/go-cmp v0.3.1 + github.com/mitchellh/copystructure v1.2.0 + github.com/sebdah/goldie v1.0.0 github.com/zclconf/go-cty v1.2.1 ) diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/go.sum b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/go.sum index 1bb69979c3e3..ae4024519275 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/go.sum +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/go.sum @@ -1,4 +1,5 @@ github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -8,6 +9,17 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sebdah/goldie v1.0.0 h1:9GNhIat69MSlz/ndaBg48vl9dF5fI+NBB6kfOxgfkMc= +github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/zclconf/go-cty v1.2.1 h1:vGMsygfmeCl4Xb6OA5U5XVAaQZ69FvoG7X2jUtQujb8= github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/plan.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/plan.go index 7e44c5c42007..97635bd4733b 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/plan.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/plan.go @@ -6,9 +6,9 @@ import ( "fmt" ) -// PlanFormatVersion is the version of the JSON plan format that is -// supported by this package. -const PlanFormatVersion = "0.1" +// PlanFormatVersions represents versions of the JSON plan format that +// are supported by this package. +var PlanFormatVersions = []string{"0.1", "0.2"} // ResourceMode is a string representation of the resource type found // in certain fields in the plan. @@ -66,13 +66,23 @@ func (p *Plan) Validate() error { return errors.New("unexpected plan input, format version is missing") } - if PlanFormatVersion != p.FormatVersion { - return fmt.Errorf("unsupported plan format version: expected %q, got %q", PlanFormatVersion, p.FormatVersion) + if !isStringInSlice(PlanFormatVersions, p.FormatVersion) { + return fmt.Errorf("unsupported plan format version: expected %q, got %q", + PlanFormatVersions, p.FormatVersion) } return nil } +func isStringInSlice(slice []string, s string) bool { + for _, el := range slice { + if el == s { + return true + } + } + return false +} + func (p *Plan) UnmarshalJSON(b []byte) error { type rawPlan Plan var plan rawPlan diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/schemas.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/schemas.go index 494c359f270d..88c2c94bb43e 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/schemas.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/schemas.go @@ -8,15 +8,15 @@ import ( "github.com/zclconf/go-cty/cty" ) -// ProviderSchemasFormatVersion is the version of the JSON provider -// schema format that is supported by this package. -const ProviderSchemasFormatVersion = "0.2" +// ProviderSchemasFormatVersions represents the versions of +// the JSON provider schema format that are supported by this package. +var ProviderSchemasFormatVersions = []string{"0.1", "0.2"} // ProviderSchemas represents the schemas of all providers and // resources in use by the configuration. type ProviderSchemas struct { - // The version of the plan format. This should always match the - // ProviderSchemasFormatVersion constant in this package, or else + // The version of the plan format. This should always match one of + // ProviderSchemasFormatVersions in this package, or else // an unmarshal will be unstable. FormatVersion string `json:"format_version,omitempty"` @@ -38,10 +38,9 @@ func (p *ProviderSchemas) Validate() error { return errors.New("unexpected provider schema data, format version is missing") } - oldVersion := "0.1" - if p.FormatVersion != ProviderSchemasFormatVersion && p.FormatVersion != oldVersion { - return fmt.Errorf("unsupported provider schema data format version: expected %q or %q, got %q", - PlanFormatVersion, oldVersion, p.FormatVersion) + if !isStringInSlice(ProviderSchemasFormatVersions, p.FormatVersion) { + return fmt.Errorf("unsupported provider schema data format version: expected %q, got %q", + ProviderSchemasFormatVersions, p.FormatVersion) } return nil diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/state.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/state.go index e1a9149c1591..ad632e49d5ce 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-json/state.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-json/state.go @@ -7,9 +7,9 @@ import ( "fmt" ) -// StateFormatVersion is the version of the JSON state format that is -// supported by this package. -const StateFormatVersion = "0.1" +// StateFormatVersions represents the versions of the JSON state format +// that are supported by this package. +var StateFormatVersions = []string{"0.1", "0.2"} // State is the top-level representation of a Terraform state. type State struct { @@ -50,8 +50,9 @@ func (s *State) Validate() error { return errors.New("unexpected state input, format version is missing") } - if StateFormatVersion != s.FormatVersion { - return fmt.Errorf("unsupported state format version: expected %q, got %q", StateFormatVersion, s.FormatVersion) + if !isStringInSlice(StateFormatVersions, s.FormatVersion) { + return fmt.Errorf("unsupported state format version: expected %q, got %q", + StateFormatVersions, s.FormatVersion) } return nil @@ -127,8 +128,8 @@ type StateResource struct { // provider offering "google_compute_instance". ProviderName string `json:"provider_name,omitempty"` - // The version of the resource type schema the "values" property - // conforms to. + // The version of the resource type schema the "values" property + // conforms to. SchemaVersion uint64 `json:"schema_version,"` // The JSON representation of the attribute values of the resource, @@ -137,6 +138,11 @@ type StateResource struct { // from absent values. AttributeValues map[string]interface{} `json:"values,omitempty"` + // The JSON representation of the sensitivity of the resource's + // attribute values. Only attributes which are sensitive + // are included in this structure. + SensitiveValues json.RawMessage `json:"sensitive_values,omitempty"` + // The addresses of the resources that this resource depends on. DependsOn []string `json:"depends_on,omitempty"` diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/data_source.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/data_source.go new file mode 100644 index 000000000000..1feb2cf34500 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/data_source.go @@ -0,0 +1,98 @@ +package tfprotov6 + +import ( + "context" +) + +// DataSourceServer is an interface containing the methods a data source +// implementation needs to fill. +type DataSourceServer interface { + // ValidateDataResourceConfig is called when Terraform is checking that a + // data source's configuration is valid. It is guaranteed to have types + // conforming to your schema, but it is not guaranteed that all values + // will be known. This is your opportunity to do custom or advanced + // validation prior to a plan being generated. + ValidateDataResourceConfig(context.Context, *ValidateDataResourceConfigRequest) (*ValidateDataResourceConfigResponse, error) + + // ReadDataSource is called when Terraform is refreshing a data + // source's state. + ReadDataSource(context.Context, *ReadDataSourceRequest) (*ReadDataSourceResponse, error) +} + +// ValidateDataResourceConfigRequest is the request Terraform sends when it wants +// to validate a data source's configuration. +type ValidateDataResourceConfigRequest struct { + // TypeName is the type of data source Terraform is validating. + TypeName string + + // Config is the configuration the user supplied for that data source. + // See the documentation on `DynamicValue` for more information about + // safely accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // This configuration may contain unknown values if a user uses + // interpolation or other functionality that would prevent Terraform + // from knowing the value at request time. + Config *DynamicValue +} + +// ValidateDataResourceConfigResponse is the response from the provider about the +// validity of a data source's configuration. +type ValidateDataResourceConfigResponse struct { + // Diagnostics report errors or warnings related to the given + // configuration. Returning an empty slice indicates a successful + // validation with no warnings or errors generated. + Diagnostics []*Diagnostic +} + +// ReadDataSourceRequest is the request Terraform sends when it wants to get +// the latest state for a data source. +type ReadDataSourceRequest struct { + // TypeName is the type of data source Terraform is requesting an + // updated state for. + TypeName string + + // Config is the configuration the user supplied for that data source. + // See the documentation on `DynamicValue` for information about safely + // accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // This configuration may have unknown values. + Config *DynamicValue + + // ProviderMeta supplies the provider metadata configuration for the + // module this data source is in. Module-specific provider metadata is + // an advanced feature and usage of it should be coordinated with the + // Terraform Core team by raising an issue at + // https://github.com/hashicorp/terraform/issues/new/choose. See the + // documentation on `DynamicValue` for information about safely + // accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // This configuration will have known values for all fields. + ProviderMeta *DynamicValue +} + +// ReadDataSourceResponse is the response from the provider about the current +// state of the requested data source. +type ReadDataSourceResponse struct { + // State is the current state of the data source, represented as a + // `DynamicValue`. See the documentation on `DynamicValue` for + // information about safely creating the `DynamicValue`. + // + // The state should be represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + State *DynamicValue + + // Diagnostics report errors or warnings related to retrieving the + // current state of the requested data source. Returning an empty slice + // indicates a successful validation with no warnings or errors + // generated. + Diagnostics []*Diagnostic +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/diagnostic.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/diagnostic.go new file mode 100644 index 000000000000..c40d52ad07c7 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/diagnostic.go @@ -0,0 +1,58 @@ +package tfprotov6 + +import "github.com/hashicorp/terraform-plugin-go/tftypes" + +const ( + // DiagnosticSeverityInvalid is used to indicate an invalid + // `DiagnosticSeverity`. Provider developers should not use it. + DiagnosticSeverityInvalid DiagnosticSeverity = 0 + + // DiagnosticSeverityError is used to indicate that a `Diagnostic` + // represents an error and should halt Terraform execution. + DiagnosticSeverityError DiagnosticSeverity = 1 + + // DiagnosticSeverityWarning is used to indicate that a `Diagnostic` + // represents a warning and should not halt Terraform's execution, but + // it should be surfaced to the user. + DiagnosticSeverityWarning DiagnosticSeverity = 2 +) + +// Diagnostic is used to convey information back the user running Terraform. +type Diagnostic struct { + // Severity indicates how Terraform should handle the Diagnostic. + Severity DiagnosticSeverity + + // Summary is a brief description of the problem, roughly + // sentence-sized, and should provide a concise description of what + // went wrong. For example, a Summary could be as simple as "Invalid + // value.". + Summary string + + // Detail is a lengthier, more complete description of the problem. + // Detail should provide enough information that a user can resolve the + // problem entirely. For example, a Detail could be "Values must be + // alphanumeric and lowercase only." + Detail string + + // Attribute indicates which field, specifically, has the problem. Not + // setting this will indicate the entire resource; setting it will + // indicate that the problem is with a certain field in the resource, + // which helps users find the source of the problem. + Attribute *tftypes.AttributePath +} + +// DiagnosticSeverity represents different classes of Diagnostic which affect +// how Terraform handles the Diagnostics. +type DiagnosticSeverity int32 + +func (d DiagnosticSeverity) String() string { + switch d { + case 0: + return "INVALID" + case 1: + return "ERROR" + case 2: + return "WARNING" + } + return "UNKNOWN" +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/doc.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/doc.go new file mode 100644 index 000000000000..875120cba380 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/doc.go @@ -0,0 +1,29 @@ +// Package tfprotov6 provides the interfaces and types needed to build a +// Terraform provider server. +// +// All Terraform provider servers should be built on +// these types, to take advantage of the ecosystem and tooling built around +// them. +// +// These types are small wrappers around the Terraform protocol. It is assumed +// that developers using tfprotov6 are familiar with the protocol, its +// requirements, and its semantics. Developers not comfortable working with the +// raw protocol should use the github.com/hashicorp/terraform-plugin-sdk/v2 Go +// module instead, which offers a less verbose, safer way to develop a +// Terraform provider, albeit with less flexibility and power. +// +// Provider developers should start by defining a type that implements the +// `ProviderServer` interface. A struct is recommended, as it will allow you to +// store the configuration information attached to your provider for use in +// requests, but any type is technically possible. +// +// `ProviderServer` implementations will need to implement the composed +// interfaces, `ResourceServer` and `DataSourceServer`. It is recommended, but +// not required, to use an embedded `ResourceRouter` and `DataSourceRouter` in +// your `ProviderServer` to achieve this, which will let you handle requests +// for each resource and data source in a resource-specific or data +// source-specific function. +// +// To serve the `ProviderServer` implementation as a gRPC server that Terraform +// can connect to, use the `tfprotov6/server.Serve` function. +package tfprotov6 diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/dynamic_value.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/dynamic_value.go new file mode 100644 index 000000000000..a9fd78420a30 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/dynamic_value.go @@ -0,0 +1,87 @@ +package tfprotov6 + +import ( + "errors" + + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +// ErrUnknownDynamicValueType is returned when a DynamicValue has no MsgPack or +// JSON bytes set. This should never be returned during the normal operation of +// a provider, and indicates one of the following: +// +// 1. terraform-plugin-go is out of sync with the protocol and should be +// updated. +// +// 2. terrafrom-plugin-go has a bug. +// +// 3. The `DynamicValue` was generated or modified by something other than +// terraform-plugin-go and is no longer a valid value. +var ErrUnknownDynamicValueType = errors.New("DynamicValue had no JSON or msgpack data set") + +// NewDynamicValue creates a DynamicValue from a tftypes.Value. You must +// specify the tftype.Type you want to send the value as, and it must be a type +// that is compatible with the Type of the Value. Usually it should just be the +// Type of the Value, but it can also be the DynamicPseudoType. +func NewDynamicValue(t tftypes.Type, v tftypes.Value) (DynamicValue, error) { + b, err := v.MarshalMsgPack(t) //nolint:staticcheck + if err != nil { + return DynamicValue{}, err + } + return DynamicValue{ + MsgPack: b, + }, nil +} + +// DynamicValue represents a nested encoding value that came from the protocol. +// The only way providers should ever interact with it is by calling its +// `Unmarshal` method to retrive a `tftypes.Value`. Although the type system +// allows for other interactions, they are explicitly not supported, and will +// not be considered when evaluating for breaking changes. Treat this type as +// an opaque value, and *only* call its `Unmarshal` method. +type DynamicValue struct { + MsgPack []byte + JSON []byte +} + +// Unmarshal returns a `tftypes.Value` that represents the information +// contained in the DynamicValue in an easy-to-interact-with way. It is the +// main purpose of the DynamicValue type, and is how provider developers should +// obtain config, state, and other values from the protocol. +// +// Pass in the type you want the `Value` to be interpreted as. Terraform's type +// system encodes in a lossy manner, meaning the type information is not +// preserved losslessly when going over the wire. Sets, lists, and tuples all +// look the same, as do user-specified values when the provider has a +// DynamicPseudoType in its schema. Objects and maps all look the same, as +// well, as do DynamicPseudoType values sometimes. Fortunately, the provider +// should already know the type; it should be the type of the schema, or +// PseudoDynamicType if that's what's in the schema. `Unmarshal` will then +// parse the value as though it belongs to that type, if possible, and return a +// `tftypes.Value` with the appropriate information. If the data can't be +// interpreted as that type, an error will be returned saying so. In these +// cases, double check to make sure the schema is declaring the same type being +// passed into `Unmarshal`. +// +// In the event an ErrUnknownDynamicValueType is returned, one of three things +// has happened: +// +// 1. terraform-plugin-go is out of date and out of sync with the protocol, and +// an issue should be opened on its repo to get it updated. +// +// 2. terraform-plugin-go has a bug somewhere, and an issue should be opened on +// its repo to get it fixed. +// +// 3. The provider or a dependency has modified the `DynamicValue` in an +// unsupported way, or has created one from scratch, and should treat it as +// opaque and not modify it, only calling `Unmarshal` on `DynamicValue`s +// received from RPC requests. +func (d DynamicValue) Unmarshal(typ tftypes.Type) (tftypes.Value, error) { + if d.JSON != nil { + return tftypes.ValueFromJSON(d.JSON, typ) //nolint:staticcheck + } + if d.MsgPack != nil { + return tftypes.ValueFromMsgPack(d.MsgPack, typ) //nolint:staticcheck + } + return tftypes.Value{}, ErrUnknownDynamicValueType +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/attribute_path.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/attribute_path.go new file mode 100644 index 000000000000..c25c3cb0d95c --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/attribute_path.go @@ -0,0 +1,63 @@ +package fromproto + +import ( + "errors" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +var ErrUnknownAttributePathStepType = errors.New("unknown type of AttributePath_Step") + +func AttributePath(in *tfplugin6.AttributePath) (*tftypes.AttributePath, error) { + steps, err := AttributePathSteps(in.Steps) + if err != nil { + return nil, err + } + return tftypes.NewAttributePathWithSteps(steps), nil +} + +func AttributePaths(in []*tfplugin6.AttributePath) ([]*tftypes.AttributePath, error) { + resp := make([]*tftypes.AttributePath, 0, len(in)) + for _, a := range in { + if a == nil { + resp = append(resp, nil) + continue + } + attr, err := AttributePath(a) + if err != nil { + return resp, err + } + resp = append(resp, attr) + } + return resp, nil +} + +func AttributePathStep(step *tfplugin6.AttributePath_Step) (tftypes.AttributePathStep, error) { + selector := step.GetSelector() + if v, ok := selector.(*tfplugin6.AttributePath_Step_AttributeName); ok { + return tftypes.AttributeName(v.AttributeName), nil + } + if v, ok := selector.(*tfplugin6.AttributePath_Step_ElementKeyString); ok { + return tftypes.ElementKeyString(v.ElementKeyString), nil + } + if v, ok := selector.(*tfplugin6.AttributePath_Step_ElementKeyInt); ok { + return tftypes.ElementKeyInt(v.ElementKeyInt), nil + } + return nil, ErrUnknownAttributePathStepType +} + +func AttributePathSteps(in []*tfplugin6.AttributePath_Step) ([]tftypes.AttributePathStep, error) { + resp := make([]tftypes.AttributePathStep, 0, len(in)) + for _, step := range in { + if step == nil { + continue + } + s, err := AttributePathStep(step) + if err != nil { + return resp, err + } + resp = append(resp, s) + } + return resp, nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/data_source.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/data_source.go new file mode 100644 index 000000000000..130f6a821982 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/data_source.go @@ -0,0 +1,53 @@ +package fromproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func ValidateDataResourceConfigRequest(in *tfplugin6.ValidateDataResourceConfig_Request) (*tfprotov6.ValidateDataResourceConfigRequest, error) { + resp := &tfprotov6.ValidateDataResourceConfigRequest{ + TypeName: in.TypeName, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + return resp, nil +} + +func ValidateDataResourceConfigResponse(in *tfplugin6.ValidateDataResourceConfig_Response) (*tfprotov6.ValidateDataResourceConfigResponse, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + return &tfprotov6.ValidateDataResourceConfigResponse{ + Diagnostics: diags, + }, nil +} + +func ReadDataSourceRequest(in *tfplugin6.ReadDataSource_Request) (*tfprotov6.ReadDataSourceRequest, error) { + resp := &tfprotov6.ReadDataSourceRequest{ + TypeName: in.TypeName, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + if in.ProviderMeta != nil { + resp.ProviderMeta = DynamicValue(in.ProviderMeta) + } + return resp, nil +} + +func ReadDataSourceResponse(in *tfplugin6.ReadDataSource_Response) (*tfprotov6.ReadDataSourceResponse, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + resp := &tfprotov6.ReadDataSourceResponse{ + Diagnostics: diags, + } + if in.State != nil { + resp.State = DynamicValue(in.State) + } + return resp, nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/diagnostic.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/diagnostic.go new file mode 100644 index 000000000000..ac92796fb1fa --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/diagnostic.go @@ -0,0 +1,42 @@ +package fromproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func Diagnostic(in *tfplugin6.Diagnostic) (*tfprotov6.Diagnostic, error) { + diag := &tfprotov6.Diagnostic{ + Severity: DiagnosticSeverity(in.Severity), + Summary: in.Summary, + Detail: in.Detail, + } + if in.Attribute != nil { + attr, err := AttributePath(in.Attribute) + if err != nil { + return diag, err + } + diag.Attribute = attr + } + return diag, nil +} + +func DiagnosticSeverity(in tfplugin6.Diagnostic_Severity) tfprotov6.DiagnosticSeverity { + return tfprotov6.DiagnosticSeverity(in) +} + +func Diagnostics(in []*tfplugin6.Diagnostic) ([]*tfprotov6.Diagnostic, error) { + diagnostics := make([]*tfprotov6.Diagnostic, 0, len(in)) + for _, diag := range in { + if diag == nil { + diagnostics = append(diagnostics, nil) + continue + } + d, err := Diagnostic(diag) + if err != nil { + return diagnostics, err + } + diagnostics = append(diagnostics, d) + } + return diagnostics, nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/provider.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/provider.go new file mode 100644 index 000000000000..2000b9bb0c45 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/provider.go @@ -0,0 +1,106 @@ +package fromproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func GetProviderSchemaRequest(in *tfplugin6.GetProviderSchema_Request) (*tfprotov6.GetProviderSchemaRequest, error) { + return &tfprotov6.GetProviderSchemaRequest{}, nil +} + +func GetProviderSchemaResponse(in *tfplugin6.GetProviderSchema_Response) (*tfprotov6.GetProviderSchemaResponse, error) { + var resp tfprotov6.GetProviderSchemaResponse + if in.Provider != nil { + schema, err := Schema(in.Provider) + if err != nil { + return &resp, err + } + resp.Provider = schema + } + if in.ProviderMeta != nil { + schema, err := Schema(in.ProviderMeta) + if err != nil { + return &resp, err + } + resp.ProviderMeta = schema + } + resp.ResourceSchemas = make(map[string]*tfprotov6.Schema, len(in.ResourceSchemas)) + for k, v := range in.ResourceSchemas { + if v == nil { + resp.ResourceSchemas[k] = nil + continue + } + schema, err := Schema(v) + if err != nil { + return &resp, err + } + resp.ResourceSchemas[k] = schema + } + resp.DataSourceSchemas = make(map[string]*tfprotov6.Schema, len(in.DataSourceSchemas)) + for k, v := range in.DataSourceSchemas { + if v == nil { + resp.DataSourceSchemas[k] = nil + continue + } + schema, err := Schema(v) + if err != nil { + return &resp, err + } + resp.DataSourceSchemas[k] = schema + } + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return &resp, err + } + resp.Diagnostics = diags + return &resp, nil +} + +func ValidateProviderConfigRequest(in *tfplugin6.ValidateProviderConfig_Request) (*tfprotov6.ValidateProviderConfigRequest, error) { + var resp tfprotov6.ValidateProviderConfigRequest + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + return &resp, nil +} + +func ValidateProviderConfigResponse(in *tfplugin6.ValidateProviderConfig_Response) (*tfprotov6.ValidateProviderConfigResponse, error) { + var resp tfprotov6.ValidateProviderConfigResponse + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + resp.Diagnostics = diags + return &resp, nil +} + +func ConfigureProviderRequest(in *tfplugin6.ConfigureProvider_Request) (*tfprotov6.ConfigureProviderRequest, error) { + resp := &tfprotov6.ConfigureProviderRequest{ + TerraformVersion: in.TerraformVersion, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + return resp, nil +} + +func ConfigureProviderResponse(in *tfplugin6.ConfigureProvider_Response) (*tfprotov6.ConfigureProviderResponse, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + return &tfprotov6.ConfigureProviderResponse{ + Diagnostics: diags, + }, nil +} + +func StopProviderRequest(in *tfplugin6.StopProvider_Request) (*tfprotov6.StopProviderRequest, error) { + return &tfprotov6.StopProviderRequest{}, nil +} + +func StopProviderResponse(in *tfplugin6.StopProvider_Response) (*tfprotov6.StopProviderResponse, error) { + return &tfprotov6.StopProviderResponse{ + Error: in.Error, + }, nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/resource.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/resource.go new file mode 100644 index 000000000000..1f8deed34c01 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/resource.go @@ -0,0 +1,206 @@ +package fromproto + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func ValidateResourceConfigRequest(in *tfplugin6.ValidateResourceConfig_Request) (*tfprotov6.ValidateResourceConfigRequest, error) { + resp := &tfprotov6.ValidateResourceConfigRequest{ + TypeName: in.TypeName, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + return resp, nil +} + +func ValidateResourceConfigResponse(in *tfplugin6.ValidateResourceConfig_Response) (*tfprotov6.ValidateResourceConfigResponse, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + return &tfprotov6.ValidateResourceConfigResponse{ + Diagnostics: diags, + }, nil +} + +func UpgradeResourceStateRequest(in *tfplugin6.UpgradeResourceState_Request) (*tfprotov6.UpgradeResourceStateRequest, error) { + resp := &tfprotov6.UpgradeResourceStateRequest{ + TypeName: in.TypeName, + Version: in.Version, + } + if in.RawState != nil { + resp.RawState = RawState(in.RawState) + } + return resp, nil +} + +func UpgradeResourceStateResponse(in *tfplugin6.UpgradeResourceState_Response) (*tfprotov6.UpgradeResourceStateResponse, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + resp := &tfprotov6.UpgradeResourceStateResponse{ + Diagnostics: diags, + } + if in.UpgradedState != nil { + resp.UpgradedState = DynamicValue(in.UpgradedState) + } + return resp, nil +} + +func ReadResourceRequest(in *tfplugin6.ReadResource_Request) (*tfprotov6.ReadResourceRequest, error) { + resp := &tfprotov6.ReadResourceRequest{ + TypeName: in.TypeName, + Private: in.Private, + } + if in.CurrentState != nil { + resp.CurrentState = DynamicValue(in.CurrentState) + } + if in.ProviderMeta != nil { + resp.ProviderMeta = DynamicValue(in.ProviderMeta) + } + return resp, nil +} + +func ReadResourceResponse(in *tfplugin6.ReadResource_Response) (*tfprotov6.ReadResourceResponse, error) { + resp := &tfprotov6.ReadResourceResponse{ + Private: in.Private, + } + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return resp, err + } + resp.Diagnostics = diags + if in.NewState != nil { + resp.NewState = DynamicValue(in.NewState) + } + return resp, nil +} + +func PlanResourceChangeRequest(in *tfplugin6.PlanResourceChange_Request) (*tfprotov6.PlanResourceChangeRequest, error) { + resp := &tfprotov6.PlanResourceChangeRequest{ + TypeName: in.TypeName, + PriorPrivate: in.PriorPrivate, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + if in.PriorState != nil { + resp.PriorState = DynamicValue(in.PriorState) + } + if in.ProposedNewState != nil { + resp.ProposedNewState = DynamicValue(in.ProposedNewState) + } + if in.ProviderMeta != nil { + resp.ProviderMeta = DynamicValue(in.ProviderMeta) + } + return resp, nil +} + +func PlanResourceChangeResponse(in *tfplugin6.PlanResourceChange_Response) (*tfprotov6.PlanResourceChangeResponse, error) { + resp := &tfprotov6.PlanResourceChangeResponse{ + PlannedPrivate: in.PlannedPrivate, + } + attributePaths, err := AttributePaths(in.RequiresReplace) + if err != nil { + return resp, err + } + resp.RequiresReplace = attributePaths + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return resp, err + } + resp.Diagnostics = diags + if in.PlannedState != nil { + resp.PlannedState = DynamicValue(in.PlannedState) + } + return resp, nil +} + +func ApplyResourceChangeRequest(in *tfplugin6.ApplyResourceChange_Request) (*tfprotov6.ApplyResourceChangeRequest, error) { + resp := &tfprotov6.ApplyResourceChangeRequest{ + TypeName: in.TypeName, + PlannedPrivate: in.PlannedPrivate, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + if in.PriorState != nil { + resp.PriorState = DynamicValue(in.PriorState) + } + if in.PlannedState != nil { + resp.PlannedState = DynamicValue(in.PlannedState) + } + if in.ProviderMeta != nil { + resp.ProviderMeta = DynamicValue(in.ProviderMeta) + } + return resp, nil +} + +func ApplyResourceChangeResponse(in *tfplugin6.ApplyResourceChange_Response) (*tfprotov6.ApplyResourceChangeResponse, error) { + resp := &tfprotov6.ApplyResourceChangeResponse{ + Private: in.Private, + } + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return resp, err + } + resp.Diagnostics = diags + if in.NewState != nil { + resp.NewState = DynamicValue(in.NewState) + } + return resp, nil +} + +func ImportResourceStateRequest(in *tfplugin6.ImportResourceState_Request) (*tfprotov6.ImportResourceStateRequest, error) { + return &tfprotov6.ImportResourceStateRequest{ + TypeName: in.TypeName, + ID: in.Id, + }, nil +} + +func ImportResourceStateResponse(in *tfplugin6.ImportResourceState_Response) (*tfprotov6.ImportResourceStateResponse, error) { + imported, err := ImportedResources(in.ImportedResources) + if err != nil { + return nil, err + } + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + return &tfprotov6.ImportResourceStateResponse{ + ImportedResources: imported, + Diagnostics: diags, + }, nil +} + +func ImportedResource(in *tfplugin6.ImportResourceState_ImportedResource) (*tfprotov6.ImportedResource, error) { + resp := &tfprotov6.ImportedResource{ + TypeName: in.TypeName, + Private: in.Private, + } + if in.State != nil { + resp.State = DynamicValue(in.State) + } + return resp, nil +} + +func ImportedResources(in []*tfplugin6.ImportResourceState_ImportedResource) ([]*tfprotov6.ImportedResource, error) { + resp := make([]*tfprotov6.ImportedResource, 0, len(in)) + for pos, i := range in { + if i == nil { + resp = append(resp, nil) + continue + } + r, err := ImportedResource(i) + if err != nil { + return resp, fmt.Errorf("Error converting imported resource %d/%d: %w", pos+1, len(in), err) + } + resp = append(resp, r) + } + return resp, nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/schema.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/schema.go new file mode 100644 index 000000000000..388a0193cf2e --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/schema.go @@ -0,0 +1,146 @@ +package fromproto + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +func Schema(in *tfplugin6.Schema) (*tfprotov6.Schema, error) { + var resp tfprotov6.Schema + resp.Version = in.Version + if in.Block != nil { + block, err := SchemaBlock(in.Block) + if err != nil { + return &resp, err + } + resp.Block = block + } + return &resp, nil +} + +func SchemaBlock(in *tfplugin6.Schema_Block) (*tfprotov6.SchemaBlock, error) { + resp := &tfprotov6.SchemaBlock{ + Version: in.Version, + Description: in.Description, + DescriptionKind: StringKind(in.DescriptionKind), + Deprecated: in.Deprecated, + } + attrs, err := SchemaAttributes(in.Attributes) + if err != nil { + return resp, err + } + resp.Attributes = attrs + blocks, err := SchemaNestedBlocks(in.BlockTypes) + if err != nil { + return resp, err + } + resp.BlockTypes = blocks + return resp, nil +} + +func SchemaAttribute(in *tfplugin6.Schema_Attribute) (*tfprotov6.SchemaAttribute, error) { + resp := &tfprotov6.SchemaAttribute{ + Name: in.Name, + Description: in.Description, + Required: in.Required, + Optional: in.Optional, + Computed: in.Computed, + Sensitive: in.Sensitive, + DescriptionKind: StringKind(in.DescriptionKind), + Deprecated: in.Deprecated, + } + + if in.Type != nil { + typ, err := tftypes.ParseJSONType(in.Type) //nolint:staticcheck + if err != nil { + return resp, err + } + resp.Type = typ + } + + if in.NestedType != nil { + nb, err := SchemaObject(in.NestedType) + if err != nil { + return resp, err + } + resp.NestedType = nb + } + + return resp, nil +} + +func SchemaAttributes(in []*tfplugin6.Schema_Attribute) ([]*tfprotov6.SchemaAttribute, error) { + resp := make([]*tfprotov6.SchemaAttribute, 0, len(in)) + for pos, a := range in { + if a == nil { + resp = append(resp, nil) + continue + } + attr, err := SchemaAttribute(a) + if err != nil { + return resp, fmt.Errorf("error converting schema attribute %d: %w", pos, err) + } + resp = append(resp, attr) + } + return resp, nil +} + +func SchemaNestedBlock(in *tfplugin6.Schema_NestedBlock) (*tfprotov6.SchemaNestedBlock, error) { + resp := &tfprotov6.SchemaNestedBlock{ + TypeName: in.TypeName, + Nesting: SchemaNestedBlockNestingMode(in.Nesting), + MinItems: in.MinItems, + MaxItems: in.MaxItems, + } + if in.Block != nil { + block, err := SchemaBlock(in.Block) + if err != nil { + return resp, err + } + resp.Block = block + } + return resp, nil +} + +func SchemaNestedBlocks(in []*tfplugin6.Schema_NestedBlock) ([]*tfprotov6.SchemaNestedBlock, error) { + resp := make([]*tfprotov6.SchemaNestedBlock, 0, len(in)) + for pos, b := range in { + if b == nil { + resp = append(resp, nil) + continue + } + block, err := SchemaNestedBlock(b) + if err != nil { + return resp, fmt.Errorf("error converting nested block %d: %w", pos, err) + } + resp = append(resp, block) + } + return resp, nil +} + +func SchemaNestedBlockNestingMode(in tfplugin6.Schema_NestedBlock_NestingMode) tfprotov6.SchemaNestedBlockNestingMode { + return tfprotov6.SchemaNestedBlockNestingMode(in) +} + +func SchemaObjectNestingMode(in tfplugin6.Schema_Object_NestingMode) tfprotov6.SchemaObjectNestingMode { + return tfprotov6.SchemaObjectNestingMode(in) +} + +func SchemaObject(in *tfplugin6.Schema_Object) (*tfprotov6.SchemaObject, error) { + resp := &tfprotov6.SchemaObject{ + Nesting: SchemaObjectNestingMode(in.Nesting), + MinItems: in.MinItems, + MaxItems: in.MaxItems, + } + + attrs, err := SchemaAttributes(in.Attributes) + if err != nil { + return nil, err + } + + resp.Attributes = attrs + return resp, nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/state.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/state.go new file mode 100644 index 000000000000..0aa2a5a6a06a --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/state.go @@ -0,0 +1,13 @@ +package fromproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func RawState(in *tfplugin6.RawState) *tfprotov6.RawState { + return &tfprotov6.RawState{ + JSON: in.Json, + Flatmap: in.Flatmap, + } +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/string_kind.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/string_kind.go new file mode 100644 index 000000000000..f2b1107538ab --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/string_kind.go @@ -0,0 +1,10 @@ +package fromproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func StringKind(in tfplugin6.StringKind) tfprotov6.StringKind { + return tfprotov6.StringKind(in) +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/types.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/types.go new file mode 100644 index 000000000000..87127f4a6df2 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto/types.go @@ -0,0 +1,13 @@ +package fromproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func DynamicValue(in *tfplugin6.DynamicValue) *tfprotov6.DynamicValue { + return &tfprotov6.DynamicValue{ + MsgPack: in.Msgpack, + JSON: in.Json, + } +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/generate.sh b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/generate.sh new file mode 100644 index 000000000000..ca2a04688838 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/generate.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# We do not run protoc under go:generate because we want to ensure that all +# dependencies of go:generate are "go get"-able for general dev environment +# usability. To compile all protobuf files in this repository, run +# "make protobuf" at the top-level. + +set -eu + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done +DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +cd "$DIR" + +protoc --proto_path=. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative tfplugin6.proto diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6.pb.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6.pb.go new file mode 100644 index 000000000000..332ece40ec8f --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6.pb.go @@ -0,0 +1,4123 @@ +// Terraform Plugin RPC protocol version 6.0 +// +// This file defines version 6.0 of the RPC protocol. To implement a plugin +// against this protocol, copy this definition into your own codebase and +// use protoc to generate stubs for your target language. +// +// This file will not be updated. Any minor versions of protocol 6 to follow +// should copy this file and modify the copy while maintaing backwards +// compatibility. Breaking changes, if any are required, will come +// in a subsequent major version with its own separate proto definition. +// +// Note that only the proto files included in a release tag of Terraform are +// official protocol releases. Proto files taken from other commits may include +// incomplete changes or features that did not make it into a final release. +// In all reasonable cases, plugin developers should take the proto file from +// the tag of the most recent release of Terraform, and not from the main +// branch or any other development branch. +// + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.15.6 +// source: tfplugin6.proto + +package tfplugin6 + +import ( + proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type StringKind int32 + +const ( + StringKind_PLAIN StringKind = 0 + StringKind_MARKDOWN StringKind = 1 +) + +// Enum value maps for StringKind. +var ( + StringKind_name = map[int32]string{ + 0: "PLAIN", + 1: "MARKDOWN", + } + StringKind_value = map[string]int32{ + "PLAIN": 0, + "MARKDOWN": 1, + } +) + +func (x StringKind) Enum() *StringKind { + p := new(StringKind) + *p = x + return p +} + +func (x StringKind) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (StringKind) Descriptor() protoreflect.EnumDescriptor { + return file_tfplugin6_proto_enumTypes[0].Descriptor() +} + +func (StringKind) Type() protoreflect.EnumType { + return &file_tfplugin6_proto_enumTypes[0] +} + +func (x StringKind) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use StringKind.Descriptor instead. +func (StringKind) EnumDescriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{0} +} + +type Diagnostic_Severity int32 + +const ( + Diagnostic_INVALID Diagnostic_Severity = 0 + Diagnostic_ERROR Diagnostic_Severity = 1 + Diagnostic_WARNING Diagnostic_Severity = 2 +) + +// Enum value maps for Diagnostic_Severity. +var ( + Diagnostic_Severity_name = map[int32]string{ + 0: "INVALID", + 1: "ERROR", + 2: "WARNING", + } + Diagnostic_Severity_value = map[string]int32{ + "INVALID": 0, + "ERROR": 1, + "WARNING": 2, + } +) + +func (x Diagnostic_Severity) Enum() *Diagnostic_Severity { + p := new(Diagnostic_Severity) + *p = x + return p +} + +func (x Diagnostic_Severity) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Diagnostic_Severity) Descriptor() protoreflect.EnumDescriptor { + return file_tfplugin6_proto_enumTypes[1].Descriptor() +} + +func (Diagnostic_Severity) Type() protoreflect.EnumType { + return &file_tfplugin6_proto_enumTypes[1] +} + +func (x Diagnostic_Severity) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Diagnostic_Severity.Descriptor instead. +func (Diagnostic_Severity) EnumDescriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{1, 0} +} + +type Schema_NestedBlock_NestingMode int32 + +const ( + Schema_NestedBlock_INVALID Schema_NestedBlock_NestingMode = 0 + Schema_NestedBlock_SINGLE Schema_NestedBlock_NestingMode = 1 + Schema_NestedBlock_LIST Schema_NestedBlock_NestingMode = 2 + Schema_NestedBlock_SET Schema_NestedBlock_NestingMode = 3 + Schema_NestedBlock_MAP Schema_NestedBlock_NestingMode = 4 + Schema_NestedBlock_GROUP Schema_NestedBlock_NestingMode = 5 +) + +// Enum value maps for Schema_NestedBlock_NestingMode. +var ( + Schema_NestedBlock_NestingMode_name = map[int32]string{ + 0: "INVALID", + 1: "SINGLE", + 2: "LIST", + 3: "SET", + 4: "MAP", + 5: "GROUP", + } + Schema_NestedBlock_NestingMode_value = map[string]int32{ + "INVALID": 0, + "SINGLE": 1, + "LIST": 2, + "SET": 3, + "MAP": 4, + "GROUP": 5, + } +) + +func (x Schema_NestedBlock_NestingMode) Enum() *Schema_NestedBlock_NestingMode { + p := new(Schema_NestedBlock_NestingMode) + *p = x + return p +} + +func (x Schema_NestedBlock_NestingMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Schema_NestedBlock_NestingMode) Descriptor() protoreflect.EnumDescriptor { + return file_tfplugin6_proto_enumTypes[2].Descriptor() +} + +func (Schema_NestedBlock_NestingMode) Type() protoreflect.EnumType { + return &file_tfplugin6_proto_enumTypes[2] +} + +func (x Schema_NestedBlock_NestingMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Schema_NestedBlock_NestingMode.Descriptor instead. +func (Schema_NestedBlock_NestingMode) EnumDescriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{5, 2, 0} +} + +type Schema_Object_NestingMode int32 + +const ( + Schema_Object_INVALID Schema_Object_NestingMode = 0 + Schema_Object_SINGLE Schema_Object_NestingMode = 1 + Schema_Object_LIST Schema_Object_NestingMode = 2 + Schema_Object_SET Schema_Object_NestingMode = 3 + Schema_Object_MAP Schema_Object_NestingMode = 4 +) + +// Enum value maps for Schema_Object_NestingMode. +var ( + Schema_Object_NestingMode_name = map[int32]string{ + 0: "INVALID", + 1: "SINGLE", + 2: "LIST", + 3: "SET", + 4: "MAP", + } + Schema_Object_NestingMode_value = map[string]int32{ + "INVALID": 0, + "SINGLE": 1, + "LIST": 2, + "SET": 3, + "MAP": 4, + } +) + +func (x Schema_Object_NestingMode) Enum() *Schema_Object_NestingMode { + p := new(Schema_Object_NestingMode) + *p = x + return p +} + +func (x Schema_Object_NestingMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Schema_Object_NestingMode) Descriptor() protoreflect.EnumDescriptor { + return file_tfplugin6_proto_enumTypes[3].Descriptor() +} + +func (Schema_Object_NestingMode) Type() protoreflect.EnumType { + return &file_tfplugin6_proto_enumTypes[3] +} + +func (x Schema_Object_NestingMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Schema_Object_NestingMode.Descriptor instead. +func (Schema_Object_NestingMode) EnumDescriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{5, 3, 0} +} + +// DynamicValue is an opaque encoding of terraform data, with the field name +// indicating the encoding scheme used. +type DynamicValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Msgpack []byte `protobuf:"bytes,1,opt,name=msgpack,proto3" json:"msgpack,omitempty"` + Json []byte `protobuf:"bytes,2,opt,name=json,proto3" json:"json,omitempty"` +} + +func (x *DynamicValue) Reset() { + *x = DynamicValue{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DynamicValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DynamicValue) ProtoMessage() {} + +func (x *DynamicValue) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DynamicValue.ProtoReflect.Descriptor instead. +func (*DynamicValue) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{0} +} + +func (x *DynamicValue) GetMsgpack() []byte { + if x != nil { + return x.Msgpack + } + return nil +} + +func (x *DynamicValue) GetJson() []byte { + if x != nil { + return x.Json + } + return nil +} + +type Diagnostic struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Severity Diagnostic_Severity `protobuf:"varint,1,opt,name=severity,proto3,enum=tfplugin6.Diagnostic_Severity" json:"severity,omitempty"` + Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + Detail string `protobuf:"bytes,3,opt,name=detail,proto3" json:"detail,omitempty"` + Attribute *AttributePath `protobuf:"bytes,4,opt,name=attribute,proto3" json:"attribute,omitempty"` +} + +func (x *Diagnostic) Reset() { + *x = Diagnostic{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Diagnostic) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Diagnostic) ProtoMessage() {} + +func (x *Diagnostic) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Diagnostic.ProtoReflect.Descriptor instead. +func (*Diagnostic) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{1} +} + +func (x *Diagnostic) GetSeverity() Diagnostic_Severity { + if x != nil { + return x.Severity + } + return Diagnostic_INVALID +} + +func (x *Diagnostic) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +func (x *Diagnostic) GetDetail() string { + if x != nil { + return x.Detail + } + return "" +} + +func (x *Diagnostic) GetAttribute() *AttributePath { + if x != nil { + return x.Attribute + } + return nil +} + +type AttributePath struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Steps []*AttributePath_Step `protobuf:"bytes,1,rep,name=steps,proto3" json:"steps,omitempty"` +} + +func (x *AttributePath) Reset() { + *x = AttributePath{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AttributePath) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AttributePath) ProtoMessage() {} + +func (x *AttributePath) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AttributePath.ProtoReflect.Descriptor instead. +func (*AttributePath) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{2} +} + +func (x *AttributePath) GetSteps() []*AttributePath_Step { + if x != nil { + return x.Steps + } + return nil +} + +type StopProvider struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StopProvider) Reset() { + *x = StopProvider{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StopProvider) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StopProvider) ProtoMessage() {} + +func (x *StopProvider) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StopProvider.ProtoReflect.Descriptor instead. +func (*StopProvider) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{3} +} + +// RawState holds the stored state for a resource to be upgraded by the +// provider. It can be in one of two formats, the current json encoded format +// in bytes, or the legacy flatmap format as a map of strings. +type RawState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Json []byte `protobuf:"bytes,1,opt,name=json,proto3" json:"json,omitempty"` + Flatmap map[string]string `protobuf:"bytes,2,rep,name=flatmap,proto3" json:"flatmap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *RawState) Reset() { + *x = RawState{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RawState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RawState) ProtoMessage() {} + +func (x *RawState) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RawState.ProtoReflect.Descriptor instead. +func (*RawState) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{4} +} + +func (x *RawState) GetJson() []byte { + if x != nil { + return x.Json + } + return nil +} + +func (x *RawState) GetFlatmap() map[string]string { + if x != nil { + return x.Flatmap + } + return nil +} + +// Schema is the configuration schema for a Resource or Provider. +type Schema struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The version of the schema. + // Schemas are versioned, so that providers can upgrade a saved resource + // state when the schema is changed. + Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + // Block is the top level configuration block for this schema. + Block *Schema_Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"` +} + +func (x *Schema) Reset() { + *x = Schema{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Schema) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Schema) ProtoMessage() {} + +func (x *Schema) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Schema.ProtoReflect.Descriptor instead. +func (*Schema) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{5} +} + +func (x *Schema) GetVersion() int64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *Schema) GetBlock() *Schema_Block { + if x != nil { + return x.Block + } + return nil +} + +type GetProviderSchema struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetProviderSchema) Reset() { + *x = GetProviderSchema{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetProviderSchema) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetProviderSchema) ProtoMessage() {} + +func (x *GetProviderSchema) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetProviderSchema.ProtoReflect.Descriptor instead. +func (*GetProviderSchema) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{6} +} + +type ValidateProviderConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ValidateProviderConfig) Reset() { + *x = ValidateProviderConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateProviderConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateProviderConfig) ProtoMessage() {} + +func (x *ValidateProviderConfig) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateProviderConfig.ProtoReflect.Descriptor instead. +func (*ValidateProviderConfig) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{7} +} + +type UpgradeResourceState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpgradeResourceState) Reset() { + *x = UpgradeResourceState{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpgradeResourceState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpgradeResourceState) ProtoMessage() {} + +func (x *UpgradeResourceState) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpgradeResourceState.ProtoReflect.Descriptor instead. +func (*UpgradeResourceState) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{8} +} + +type ValidateResourceConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ValidateResourceConfig) Reset() { + *x = ValidateResourceConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateResourceConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateResourceConfig) ProtoMessage() {} + +func (x *ValidateResourceConfig) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateResourceConfig.ProtoReflect.Descriptor instead. +func (*ValidateResourceConfig) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{9} +} + +type ValidateDataResourceConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ValidateDataResourceConfig) Reset() { + *x = ValidateDataResourceConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateDataResourceConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateDataResourceConfig) ProtoMessage() {} + +func (x *ValidateDataResourceConfig) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateDataResourceConfig.ProtoReflect.Descriptor instead. +func (*ValidateDataResourceConfig) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{10} +} + +type ConfigureProvider struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ConfigureProvider) Reset() { + *x = ConfigureProvider{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ConfigureProvider) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfigureProvider) ProtoMessage() {} + +func (x *ConfigureProvider) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConfigureProvider.ProtoReflect.Descriptor instead. +func (*ConfigureProvider) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{11} +} + +type ReadResource struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ReadResource) Reset() { + *x = ReadResource{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadResource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadResource) ProtoMessage() {} + +func (x *ReadResource) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadResource.ProtoReflect.Descriptor instead. +func (*ReadResource) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{12} +} + +type PlanResourceChange struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *PlanResourceChange) Reset() { + *x = PlanResourceChange{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PlanResourceChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlanResourceChange) ProtoMessage() {} + +func (x *PlanResourceChange) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlanResourceChange.ProtoReflect.Descriptor instead. +func (*PlanResourceChange) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{13} +} + +type ApplyResourceChange struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ApplyResourceChange) Reset() { + *x = ApplyResourceChange{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyResourceChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyResourceChange) ProtoMessage() {} + +func (x *ApplyResourceChange) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyResourceChange.ProtoReflect.Descriptor instead. +func (*ApplyResourceChange) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{14} +} + +type ImportResourceState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ImportResourceState) Reset() { + *x = ImportResourceState{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ImportResourceState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImportResourceState) ProtoMessage() {} + +func (x *ImportResourceState) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImportResourceState.ProtoReflect.Descriptor instead. +func (*ImportResourceState) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{15} +} + +type ReadDataSource struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ReadDataSource) Reset() { + *x = ReadDataSource{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadDataSource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadDataSource) ProtoMessage() {} + +func (x *ReadDataSource) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadDataSource.ProtoReflect.Descriptor instead. +func (*ReadDataSource) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{16} +} + +type AttributePath_Step struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Selector: + // *AttributePath_Step_AttributeName + // *AttributePath_Step_ElementKeyString + // *AttributePath_Step_ElementKeyInt + Selector isAttributePath_Step_Selector `protobuf_oneof:"selector"` +} + +func (x *AttributePath_Step) Reset() { + *x = AttributePath_Step{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AttributePath_Step) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AttributePath_Step) ProtoMessage() {} + +func (x *AttributePath_Step) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AttributePath_Step.ProtoReflect.Descriptor instead. +func (*AttributePath_Step) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{2, 0} +} + +func (m *AttributePath_Step) GetSelector() isAttributePath_Step_Selector { + if m != nil { + return m.Selector + } + return nil +} + +func (x *AttributePath_Step) GetAttributeName() string { + if x, ok := x.GetSelector().(*AttributePath_Step_AttributeName); ok { + return x.AttributeName + } + return "" +} + +func (x *AttributePath_Step) GetElementKeyString() string { + if x, ok := x.GetSelector().(*AttributePath_Step_ElementKeyString); ok { + return x.ElementKeyString + } + return "" +} + +func (x *AttributePath_Step) GetElementKeyInt() int64 { + if x, ok := x.GetSelector().(*AttributePath_Step_ElementKeyInt); ok { + return x.ElementKeyInt + } + return 0 +} + +type isAttributePath_Step_Selector interface { + isAttributePath_Step_Selector() +} + +type AttributePath_Step_AttributeName struct { + // Set "attribute_name" to represent looking up an attribute + // in the current object value. + AttributeName string `protobuf:"bytes,1,opt,name=attribute_name,json=attributeName,proto3,oneof"` +} + +type AttributePath_Step_ElementKeyString struct { + // Set "element_key_*" to represent looking up an element in + // an indexable collection type. + ElementKeyString string `protobuf:"bytes,2,opt,name=element_key_string,json=elementKeyString,proto3,oneof"` +} + +type AttributePath_Step_ElementKeyInt struct { + ElementKeyInt int64 `protobuf:"varint,3,opt,name=element_key_int,json=elementKeyInt,proto3,oneof"` +} + +func (*AttributePath_Step_AttributeName) isAttributePath_Step_Selector() {} + +func (*AttributePath_Step_ElementKeyString) isAttributePath_Step_Selector() {} + +func (*AttributePath_Step_ElementKeyInt) isAttributePath_Step_Selector() {} + +type StopProvider_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StopProvider_Request) Reset() { + *x = StopProvider_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StopProvider_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StopProvider_Request) ProtoMessage() {} + +func (x *StopProvider_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StopProvider_Request.ProtoReflect.Descriptor instead. +func (*StopProvider_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{3, 0} +} + +type StopProvider_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error string `protobuf:"bytes,1,opt,name=Error,proto3" json:"Error,omitempty"` +} + +func (x *StopProvider_Response) Reset() { + *x = StopProvider_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StopProvider_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StopProvider_Response) ProtoMessage() {} + +func (x *StopProvider_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StopProvider_Response.ProtoReflect.Descriptor instead. +func (*StopProvider_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{3, 1} +} + +func (x *StopProvider_Response) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +type Schema_Block struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version int64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Attributes []*Schema_Attribute `protobuf:"bytes,2,rep,name=attributes,proto3" json:"attributes,omitempty"` + BlockTypes []*Schema_NestedBlock `protobuf:"bytes,3,rep,name=block_types,json=blockTypes,proto3" json:"block_types,omitempty"` + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` + DescriptionKind StringKind `protobuf:"varint,5,opt,name=description_kind,json=descriptionKind,proto3,enum=tfplugin6.StringKind" json:"description_kind,omitempty"` + Deprecated bool `protobuf:"varint,6,opt,name=deprecated,proto3" json:"deprecated,omitempty"` +} + +func (x *Schema_Block) Reset() { + *x = Schema_Block{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Schema_Block) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Schema_Block) ProtoMessage() {} + +func (x *Schema_Block) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Schema_Block.ProtoReflect.Descriptor instead. +func (*Schema_Block) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{5, 0} +} + +func (x *Schema_Block) GetVersion() int64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *Schema_Block) GetAttributes() []*Schema_Attribute { + if x != nil { + return x.Attributes + } + return nil +} + +func (x *Schema_Block) GetBlockTypes() []*Schema_NestedBlock { + if x != nil { + return x.BlockTypes + } + return nil +} + +func (x *Schema_Block) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Schema_Block) GetDescriptionKind() StringKind { + if x != nil { + return x.DescriptionKind + } + return StringKind_PLAIN +} + +func (x *Schema_Block) GetDeprecated() bool { + if x != nil { + return x.Deprecated + } + return false +} + +type Schema_Attribute struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Type []byte `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + NestedType *Schema_Object `protobuf:"bytes,10,opt,name=nested_type,json=nestedType,proto3" json:"nested_type,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + Required bool `protobuf:"varint,4,opt,name=required,proto3" json:"required,omitempty"` + Optional bool `protobuf:"varint,5,opt,name=optional,proto3" json:"optional,omitempty"` + Computed bool `protobuf:"varint,6,opt,name=computed,proto3" json:"computed,omitempty"` + Sensitive bool `protobuf:"varint,7,opt,name=sensitive,proto3" json:"sensitive,omitempty"` + DescriptionKind StringKind `protobuf:"varint,8,opt,name=description_kind,json=descriptionKind,proto3,enum=tfplugin6.StringKind" json:"description_kind,omitempty"` + Deprecated bool `protobuf:"varint,9,opt,name=deprecated,proto3" json:"deprecated,omitempty"` +} + +func (x *Schema_Attribute) Reset() { + *x = Schema_Attribute{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Schema_Attribute) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Schema_Attribute) ProtoMessage() {} + +func (x *Schema_Attribute) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Schema_Attribute.ProtoReflect.Descriptor instead. +func (*Schema_Attribute) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{5, 1} +} + +func (x *Schema_Attribute) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Schema_Attribute) GetType() []byte { + if x != nil { + return x.Type + } + return nil +} + +func (x *Schema_Attribute) GetNestedType() *Schema_Object { + if x != nil { + return x.NestedType + } + return nil +} + +func (x *Schema_Attribute) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Schema_Attribute) GetRequired() bool { + if x != nil { + return x.Required + } + return false +} + +func (x *Schema_Attribute) GetOptional() bool { + if x != nil { + return x.Optional + } + return false +} + +func (x *Schema_Attribute) GetComputed() bool { + if x != nil { + return x.Computed + } + return false +} + +func (x *Schema_Attribute) GetSensitive() bool { + if x != nil { + return x.Sensitive + } + return false +} + +func (x *Schema_Attribute) GetDescriptionKind() StringKind { + if x != nil { + return x.DescriptionKind + } + return StringKind_PLAIN +} + +func (x *Schema_Attribute) GetDeprecated() bool { + if x != nil { + return x.Deprecated + } + return false +} + +type Schema_NestedBlock struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` + Block *Schema_Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"` + Nesting Schema_NestedBlock_NestingMode `protobuf:"varint,3,opt,name=nesting,proto3,enum=tfplugin6.Schema_NestedBlock_NestingMode" json:"nesting,omitempty"` + MinItems int64 `protobuf:"varint,4,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"` + MaxItems int64 `protobuf:"varint,5,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"` +} + +func (x *Schema_NestedBlock) Reset() { + *x = Schema_NestedBlock{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Schema_NestedBlock) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Schema_NestedBlock) ProtoMessage() {} + +func (x *Schema_NestedBlock) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Schema_NestedBlock.ProtoReflect.Descriptor instead. +func (*Schema_NestedBlock) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{5, 2} +} + +func (x *Schema_NestedBlock) GetTypeName() string { + if x != nil { + return x.TypeName + } + return "" +} + +func (x *Schema_NestedBlock) GetBlock() *Schema_Block { + if x != nil { + return x.Block + } + return nil +} + +func (x *Schema_NestedBlock) GetNesting() Schema_NestedBlock_NestingMode { + if x != nil { + return x.Nesting + } + return Schema_NestedBlock_INVALID +} + +func (x *Schema_NestedBlock) GetMinItems() int64 { + if x != nil { + return x.MinItems + } + return 0 +} + +func (x *Schema_NestedBlock) GetMaxItems() int64 { + if x != nil { + return x.MaxItems + } + return 0 +} + +type Schema_Object struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Attributes []*Schema_Attribute `protobuf:"bytes,1,rep,name=attributes,proto3" json:"attributes,omitempty"` + Nesting Schema_Object_NestingMode `protobuf:"varint,3,opt,name=nesting,proto3,enum=tfplugin6.Schema_Object_NestingMode" json:"nesting,omitempty"` + MinItems int64 `protobuf:"varint,4,opt,name=min_items,json=minItems,proto3" json:"min_items,omitempty"` + MaxItems int64 `protobuf:"varint,5,opt,name=max_items,json=maxItems,proto3" json:"max_items,omitempty"` +} + +func (x *Schema_Object) Reset() { + *x = Schema_Object{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Schema_Object) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Schema_Object) ProtoMessage() {} + +func (x *Schema_Object) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Schema_Object.ProtoReflect.Descriptor instead. +func (*Schema_Object) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{5, 3} +} + +func (x *Schema_Object) GetAttributes() []*Schema_Attribute { + if x != nil { + return x.Attributes + } + return nil +} + +func (x *Schema_Object) GetNesting() Schema_Object_NestingMode { + if x != nil { + return x.Nesting + } + return Schema_Object_INVALID +} + +func (x *Schema_Object) GetMinItems() int64 { + if x != nil { + return x.MinItems + } + return 0 +} + +func (x *Schema_Object) GetMaxItems() int64 { + if x != nil { + return x.MaxItems + } + return 0 +} + +type GetProviderSchema_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetProviderSchema_Request) Reset() { + *x = GetProviderSchema_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetProviderSchema_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetProviderSchema_Request) ProtoMessage() {} + +func (x *GetProviderSchema_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetProviderSchema_Request.ProtoReflect.Descriptor instead. +func (*GetProviderSchema_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{6, 0} +} + +type GetProviderSchema_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Provider *Schema `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"` + ResourceSchemas map[string]*Schema `protobuf:"bytes,2,rep,name=resource_schemas,json=resourceSchemas,proto3" json:"resource_schemas,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + DataSourceSchemas map[string]*Schema `protobuf:"bytes,3,rep,name=data_source_schemas,json=dataSourceSchemas,proto3" json:"data_source_schemas,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Diagnostics []*Diagnostic `protobuf:"bytes,4,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` + ProviderMeta *Schema `protobuf:"bytes,5,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"` +} + +func (x *GetProviderSchema_Response) Reset() { + *x = GetProviderSchema_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetProviderSchema_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetProviderSchema_Response) ProtoMessage() {} + +func (x *GetProviderSchema_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetProviderSchema_Response.ProtoReflect.Descriptor instead. +func (*GetProviderSchema_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{6, 1} +} + +func (x *GetProviderSchema_Response) GetProvider() *Schema { + if x != nil { + return x.Provider + } + return nil +} + +func (x *GetProviderSchema_Response) GetResourceSchemas() map[string]*Schema { + if x != nil { + return x.ResourceSchemas + } + return nil +} + +func (x *GetProviderSchema_Response) GetDataSourceSchemas() map[string]*Schema { + if x != nil { + return x.DataSourceSchemas + } + return nil +} + +func (x *GetProviderSchema_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +func (x *GetProviderSchema_Response) GetProviderMeta() *Schema { + if x != nil { + return x.ProviderMeta + } + return nil +} + +type ValidateProviderConfig_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config *DynamicValue `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` +} + +func (x *ValidateProviderConfig_Request) Reset() { + *x = ValidateProviderConfig_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateProviderConfig_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateProviderConfig_Request) ProtoMessage() {} + +func (x *ValidateProviderConfig_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateProviderConfig_Request.ProtoReflect.Descriptor instead. +func (*ValidateProviderConfig_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{7, 0} +} + +func (x *ValidateProviderConfig_Request) GetConfig() *DynamicValue { + if x != nil { + return x.Config + } + return nil +} + +type ValidateProviderConfig_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` +} + +func (x *ValidateProviderConfig_Response) Reset() { + *x = ValidateProviderConfig_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateProviderConfig_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateProviderConfig_Response) ProtoMessage() {} + +func (x *ValidateProviderConfig_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateProviderConfig_Response.ProtoReflect.Descriptor instead. +func (*ValidateProviderConfig_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{7, 1} +} + +func (x *ValidateProviderConfig_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +type UpgradeResourceState_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` + // version is the schema_version number recorded in the state file + Version int64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + // raw_state is the raw states as stored for the resource. Core does + // not have access to the schema of prior_version, so it's the + // provider's responsibility to interpret this value using the + // appropriate older schema. The raw_state will be the json encoded + // state, or a legacy flat-mapped format. + RawState *RawState `protobuf:"bytes,3,opt,name=raw_state,json=rawState,proto3" json:"raw_state,omitempty"` +} + +func (x *UpgradeResourceState_Request) Reset() { + *x = UpgradeResourceState_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpgradeResourceState_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpgradeResourceState_Request) ProtoMessage() {} + +func (x *UpgradeResourceState_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpgradeResourceState_Request.ProtoReflect.Descriptor instead. +func (*UpgradeResourceState_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{8, 0} +} + +func (x *UpgradeResourceState_Request) GetTypeName() string { + if x != nil { + return x.TypeName + } + return "" +} + +func (x *UpgradeResourceState_Request) GetVersion() int64 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *UpgradeResourceState_Request) GetRawState() *RawState { + if x != nil { + return x.RawState + } + return nil +} + +type UpgradeResourceState_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // new_state is a msgpack-encoded data structure that, when interpreted with + // the _current_ schema for this resource type, is functionally equivalent to + // that which was given in prior_state_raw. + UpgradedState *DynamicValue `protobuf:"bytes,1,opt,name=upgraded_state,json=upgradedState,proto3" json:"upgraded_state,omitempty"` + // diagnostics describes any errors encountered during migration that could not + // be safely resolved, and warnings about any possibly-risky assumptions made + // in the upgrade process. + Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` +} + +func (x *UpgradeResourceState_Response) Reset() { + *x = UpgradeResourceState_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpgradeResourceState_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpgradeResourceState_Response) ProtoMessage() {} + +func (x *UpgradeResourceState_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpgradeResourceState_Response.ProtoReflect.Descriptor instead. +func (*UpgradeResourceState_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{8, 1} +} + +func (x *UpgradeResourceState_Response) GetUpgradedState() *DynamicValue { + if x != nil { + return x.UpgradedState + } + return nil +} + +func (x *UpgradeResourceState_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +type ValidateResourceConfig_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` + Config *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` +} + +func (x *ValidateResourceConfig_Request) Reset() { + *x = ValidateResourceConfig_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateResourceConfig_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateResourceConfig_Request) ProtoMessage() {} + +func (x *ValidateResourceConfig_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateResourceConfig_Request.ProtoReflect.Descriptor instead. +func (*ValidateResourceConfig_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{9, 0} +} + +func (x *ValidateResourceConfig_Request) GetTypeName() string { + if x != nil { + return x.TypeName + } + return "" +} + +func (x *ValidateResourceConfig_Request) GetConfig() *DynamicValue { + if x != nil { + return x.Config + } + return nil +} + +type ValidateResourceConfig_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Diagnostics []*Diagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` +} + +func (x *ValidateResourceConfig_Response) Reset() { + *x = ValidateResourceConfig_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateResourceConfig_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateResourceConfig_Response) ProtoMessage() {} + +func (x *ValidateResourceConfig_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateResourceConfig_Response.ProtoReflect.Descriptor instead. +func (*ValidateResourceConfig_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{9, 1} +} + +func (x *ValidateResourceConfig_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +type ValidateDataResourceConfig_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` + Config *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` +} + +func (x *ValidateDataResourceConfig_Request) Reset() { + *x = ValidateDataResourceConfig_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateDataResourceConfig_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateDataResourceConfig_Request) ProtoMessage() {} + +func (x *ValidateDataResourceConfig_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateDataResourceConfig_Request.ProtoReflect.Descriptor instead. +func (*ValidateDataResourceConfig_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{10, 0} +} + +func (x *ValidateDataResourceConfig_Request) GetTypeName() string { + if x != nil { + return x.TypeName + } + return "" +} + +func (x *ValidateDataResourceConfig_Request) GetConfig() *DynamicValue { + if x != nil { + return x.Config + } + return nil +} + +type ValidateDataResourceConfig_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Diagnostics []*Diagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` +} + +func (x *ValidateDataResourceConfig_Response) Reset() { + *x = ValidateDataResourceConfig_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateDataResourceConfig_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateDataResourceConfig_Response) ProtoMessage() {} + +func (x *ValidateDataResourceConfig_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateDataResourceConfig_Response.ProtoReflect.Descriptor instead. +func (*ValidateDataResourceConfig_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{10, 1} +} + +func (x *ValidateDataResourceConfig_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +type ConfigureProvider_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TerraformVersion string `protobuf:"bytes,1,opt,name=terraform_version,json=terraformVersion,proto3" json:"terraform_version,omitempty"` + Config *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` +} + +func (x *ConfigureProvider_Request) Reset() { + *x = ConfigureProvider_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ConfigureProvider_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfigureProvider_Request) ProtoMessage() {} + +func (x *ConfigureProvider_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConfigureProvider_Request.ProtoReflect.Descriptor instead. +func (*ConfigureProvider_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{11, 0} +} + +func (x *ConfigureProvider_Request) GetTerraformVersion() string { + if x != nil { + return x.TerraformVersion + } + return "" +} + +func (x *ConfigureProvider_Request) GetConfig() *DynamicValue { + if x != nil { + return x.Config + } + return nil +} + +type ConfigureProvider_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Diagnostics []*Diagnostic `protobuf:"bytes,1,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` +} + +func (x *ConfigureProvider_Response) Reset() { + *x = ConfigureProvider_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ConfigureProvider_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfigureProvider_Response) ProtoMessage() {} + +func (x *ConfigureProvider_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[38] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConfigureProvider_Response.ProtoReflect.Descriptor instead. +func (*ConfigureProvider_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{11, 1} +} + +func (x *ConfigureProvider_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +type ReadResource_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` + CurrentState *DynamicValue `protobuf:"bytes,2,opt,name=current_state,json=currentState,proto3" json:"current_state,omitempty"` + Private []byte `protobuf:"bytes,3,opt,name=private,proto3" json:"private,omitempty"` + ProviderMeta *DynamicValue `protobuf:"bytes,4,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"` +} + +func (x *ReadResource_Request) Reset() { + *x = ReadResource_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadResource_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadResource_Request) ProtoMessage() {} + +func (x *ReadResource_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[39] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadResource_Request.ProtoReflect.Descriptor instead. +func (*ReadResource_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{12, 0} +} + +func (x *ReadResource_Request) GetTypeName() string { + if x != nil { + return x.TypeName + } + return "" +} + +func (x *ReadResource_Request) GetCurrentState() *DynamicValue { + if x != nil { + return x.CurrentState + } + return nil +} + +func (x *ReadResource_Request) GetPrivate() []byte { + if x != nil { + return x.Private + } + return nil +} + +func (x *ReadResource_Request) GetProviderMeta() *DynamicValue { + if x != nil { + return x.ProviderMeta + } + return nil +} + +type ReadResource_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NewState *DynamicValue `protobuf:"bytes,1,opt,name=new_state,json=newState,proto3" json:"new_state,omitempty"` + Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` + Private []byte `protobuf:"bytes,3,opt,name=private,proto3" json:"private,omitempty"` +} + +func (x *ReadResource_Response) Reset() { + *x = ReadResource_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadResource_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadResource_Response) ProtoMessage() {} + +func (x *ReadResource_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadResource_Response.ProtoReflect.Descriptor instead. +func (*ReadResource_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{12, 1} +} + +func (x *ReadResource_Response) GetNewState() *DynamicValue { + if x != nil { + return x.NewState + } + return nil +} + +func (x *ReadResource_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +func (x *ReadResource_Response) GetPrivate() []byte { + if x != nil { + return x.Private + } + return nil +} + +type PlanResourceChange_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` + PriorState *DynamicValue `protobuf:"bytes,2,opt,name=prior_state,json=priorState,proto3" json:"prior_state,omitempty"` + ProposedNewState *DynamicValue `protobuf:"bytes,3,opt,name=proposed_new_state,json=proposedNewState,proto3" json:"proposed_new_state,omitempty"` + Config *DynamicValue `protobuf:"bytes,4,opt,name=config,proto3" json:"config,omitempty"` + PriorPrivate []byte `protobuf:"bytes,5,opt,name=prior_private,json=priorPrivate,proto3" json:"prior_private,omitempty"` + ProviderMeta *DynamicValue `protobuf:"bytes,6,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"` +} + +func (x *PlanResourceChange_Request) Reset() { + *x = PlanResourceChange_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PlanResourceChange_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlanResourceChange_Request) ProtoMessage() {} + +func (x *PlanResourceChange_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[41] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlanResourceChange_Request.ProtoReflect.Descriptor instead. +func (*PlanResourceChange_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{13, 0} +} + +func (x *PlanResourceChange_Request) GetTypeName() string { + if x != nil { + return x.TypeName + } + return "" +} + +func (x *PlanResourceChange_Request) GetPriorState() *DynamicValue { + if x != nil { + return x.PriorState + } + return nil +} + +func (x *PlanResourceChange_Request) GetProposedNewState() *DynamicValue { + if x != nil { + return x.ProposedNewState + } + return nil +} + +func (x *PlanResourceChange_Request) GetConfig() *DynamicValue { + if x != nil { + return x.Config + } + return nil +} + +func (x *PlanResourceChange_Request) GetPriorPrivate() []byte { + if x != nil { + return x.PriorPrivate + } + return nil +} + +func (x *PlanResourceChange_Request) GetProviderMeta() *DynamicValue { + if x != nil { + return x.ProviderMeta + } + return nil +} + +type PlanResourceChange_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PlannedState *DynamicValue `protobuf:"bytes,1,opt,name=planned_state,json=plannedState,proto3" json:"planned_state,omitempty"` + RequiresReplace []*AttributePath `protobuf:"bytes,2,rep,name=requires_replace,json=requiresReplace,proto3" json:"requires_replace,omitempty"` + PlannedPrivate []byte `protobuf:"bytes,3,opt,name=planned_private,json=plannedPrivate,proto3" json:"planned_private,omitempty"` + Diagnostics []*Diagnostic `protobuf:"bytes,4,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` +} + +func (x *PlanResourceChange_Response) Reset() { + *x = PlanResourceChange_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PlanResourceChange_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlanResourceChange_Response) ProtoMessage() {} + +func (x *PlanResourceChange_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[42] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PlanResourceChange_Response.ProtoReflect.Descriptor instead. +func (*PlanResourceChange_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{13, 1} +} + +func (x *PlanResourceChange_Response) GetPlannedState() *DynamicValue { + if x != nil { + return x.PlannedState + } + return nil +} + +func (x *PlanResourceChange_Response) GetRequiresReplace() []*AttributePath { + if x != nil { + return x.RequiresReplace + } + return nil +} + +func (x *PlanResourceChange_Response) GetPlannedPrivate() []byte { + if x != nil { + return x.PlannedPrivate + } + return nil +} + +func (x *PlanResourceChange_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +type ApplyResourceChange_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` + PriorState *DynamicValue `protobuf:"bytes,2,opt,name=prior_state,json=priorState,proto3" json:"prior_state,omitempty"` + PlannedState *DynamicValue `protobuf:"bytes,3,opt,name=planned_state,json=plannedState,proto3" json:"planned_state,omitempty"` + Config *DynamicValue `protobuf:"bytes,4,opt,name=config,proto3" json:"config,omitempty"` + PlannedPrivate []byte `protobuf:"bytes,5,opt,name=planned_private,json=plannedPrivate,proto3" json:"planned_private,omitempty"` + ProviderMeta *DynamicValue `protobuf:"bytes,6,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"` +} + +func (x *ApplyResourceChange_Request) Reset() { + *x = ApplyResourceChange_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyResourceChange_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyResourceChange_Request) ProtoMessage() {} + +func (x *ApplyResourceChange_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[43] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyResourceChange_Request.ProtoReflect.Descriptor instead. +func (*ApplyResourceChange_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{14, 0} +} + +func (x *ApplyResourceChange_Request) GetTypeName() string { + if x != nil { + return x.TypeName + } + return "" +} + +func (x *ApplyResourceChange_Request) GetPriorState() *DynamicValue { + if x != nil { + return x.PriorState + } + return nil +} + +func (x *ApplyResourceChange_Request) GetPlannedState() *DynamicValue { + if x != nil { + return x.PlannedState + } + return nil +} + +func (x *ApplyResourceChange_Request) GetConfig() *DynamicValue { + if x != nil { + return x.Config + } + return nil +} + +func (x *ApplyResourceChange_Request) GetPlannedPrivate() []byte { + if x != nil { + return x.PlannedPrivate + } + return nil +} + +func (x *ApplyResourceChange_Request) GetProviderMeta() *DynamicValue { + if x != nil { + return x.ProviderMeta + } + return nil +} + +type ApplyResourceChange_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NewState *DynamicValue `protobuf:"bytes,1,opt,name=new_state,json=newState,proto3" json:"new_state,omitempty"` + Private []byte `protobuf:"bytes,2,opt,name=private,proto3" json:"private,omitempty"` + Diagnostics []*Diagnostic `protobuf:"bytes,3,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` +} + +func (x *ApplyResourceChange_Response) Reset() { + *x = ApplyResourceChange_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyResourceChange_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyResourceChange_Response) ProtoMessage() {} + +func (x *ApplyResourceChange_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[44] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyResourceChange_Response.ProtoReflect.Descriptor instead. +func (*ApplyResourceChange_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{14, 1} +} + +func (x *ApplyResourceChange_Response) GetNewState() *DynamicValue { + if x != nil { + return x.NewState + } + return nil +} + +func (x *ApplyResourceChange_Response) GetPrivate() []byte { + if x != nil { + return x.Private + } + return nil +} + +func (x *ApplyResourceChange_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +type ImportResourceState_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *ImportResourceState_Request) Reset() { + *x = ImportResourceState_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ImportResourceState_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImportResourceState_Request) ProtoMessage() {} + +func (x *ImportResourceState_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[45] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImportResourceState_Request.ProtoReflect.Descriptor instead. +func (*ImportResourceState_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{15, 0} +} + +func (x *ImportResourceState_Request) GetTypeName() string { + if x != nil { + return x.TypeName + } + return "" +} + +func (x *ImportResourceState_Request) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type ImportResourceState_ImportedResource struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` + State *DynamicValue `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` + Private []byte `protobuf:"bytes,3,opt,name=private,proto3" json:"private,omitempty"` +} + +func (x *ImportResourceState_ImportedResource) Reset() { + *x = ImportResourceState_ImportedResource{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ImportResourceState_ImportedResource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImportResourceState_ImportedResource) ProtoMessage() {} + +func (x *ImportResourceState_ImportedResource) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[46] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImportResourceState_ImportedResource.ProtoReflect.Descriptor instead. +func (*ImportResourceState_ImportedResource) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{15, 1} +} + +func (x *ImportResourceState_ImportedResource) GetTypeName() string { + if x != nil { + return x.TypeName + } + return "" +} + +func (x *ImportResourceState_ImportedResource) GetState() *DynamicValue { + if x != nil { + return x.State + } + return nil +} + +func (x *ImportResourceState_ImportedResource) GetPrivate() []byte { + if x != nil { + return x.Private + } + return nil +} + +type ImportResourceState_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ImportedResources []*ImportResourceState_ImportedResource `protobuf:"bytes,1,rep,name=imported_resources,json=importedResources,proto3" json:"imported_resources,omitempty"` + Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` +} + +func (x *ImportResourceState_Response) Reset() { + *x = ImportResourceState_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ImportResourceState_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImportResourceState_Response) ProtoMessage() {} + +func (x *ImportResourceState_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[47] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImportResourceState_Response.ProtoReflect.Descriptor instead. +func (*ImportResourceState_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{15, 2} +} + +func (x *ImportResourceState_Response) GetImportedResources() []*ImportResourceState_ImportedResource { + if x != nil { + return x.ImportedResources + } + return nil +} + +func (x *ImportResourceState_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +type ReadDataSource_Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeName string `protobuf:"bytes,1,opt,name=type_name,json=typeName,proto3" json:"type_name,omitempty"` + Config *DynamicValue `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` + ProviderMeta *DynamicValue `protobuf:"bytes,3,opt,name=provider_meta,json=providerMeta,proto3" json:"provider_meta,omitempty"` +} + +func (x *ReadDataSource_Request) Reset() { + *x = ReadDataSource_Request{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadDataSource_Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadDataSource_Request) ProtoMessage() {} + +func (x *ReadDataSource_Request) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[48] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadDataSource_Request.ProtoReflect.Descriptor instead. +func (*ReadDataSource_Request) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{16, 0} +} + +func (x *ReadDataSource_Request) GetTypeName() string { + if x != nil { + return x.TypeName + } + return "" +} + +func (x *ReadDataSource_Request) GetConfig() *DynamicValue { + if x != nil { + return x.Config + } + return nil +} + +func (x *ReadDataSource_Request) GetProviderMeta() *DynamicValue { + if x != nil { + return x.ProviderMeta + } + return nil +} + +type ReadDataSource_Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + State *DynamicValue `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` + Diagnostics []*Diagnostic `protobuf:"bytes,2,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"` +} + +func (x *ReadDataSource_Response) Reset() { + *x = ReadDataSource_Response{} + if protoimpl.UnsafeEnabled { + mi := &file_tfplugin6_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadDataSource_Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadDataSource_Response) ProtoMessage() {} + +func (x *ReadDataSource_Response) ProtoReflect() protoreflect.Message { + mi := &file_tfplugin6_proto_msgTypes[49] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadDataSource_Response.ProtoReflect.Descriptor instead. +func (*ReadDataSource_Response) Descriptor() ([]byte, []int) { + return file_tfplugin6_proto_rawDescGZIP(), []int{16, 1} +} + +func (x *ReadDataSource_Response) GetState() *DynamicValue { + if x != nil { + return x.State + } + return nil +} + +func (x *ReadDataSource_Response) GetDiagnostics() []*Diagnostic { + if x != nil { + return x.Diagnostics + } + return nil +} + +var File_tfplugin6_proto protoreflect.FileDescriptor + +var file_tfplugin6_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x09, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x22, 0x3c, 0x0a, 0x0c, + 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, + 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0xe3, 0x01, 0x0a, 0x0a, 0x44, + 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x12, 0x3a, 0x0a, 0x08, 0x73, 0x65, 0x76, + 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x66, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, + 0x69, 0x63, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, + 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, + 0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x36, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x66, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x50, 0x61, 0x74, 0x68, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x22, + 0x2f, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x49, + 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, + 0x52, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x02, + 0x22, 0xdc, 0x01, 0x0a, 0x0d, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x50, 0x61, + 0x74, 0x68, 0x12, 0x33, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x2e, 0x53, 0x74, 0x65, 0x70, + 0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x1a, 0x95, 0x01, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, + 0x12, 0x27, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x10, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x4b, 0x65, 0x79, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x00, 0x52, 0x0d, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, + 0x49, 0x6e, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, + 0x3b, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x70, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x1a, + 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x0a, 0x08, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x96, 0x01, 0x0a, + 0x08, 0x52, 0x61, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6a, 0x73, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, + 0x07, 0x66, 0x6c, 0x61, 0x74, 0x6d, 0x61, 0x70, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x52, 0x61, 0x77, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x46, 0x6c, 0x61, 0x74, 0x6d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x07, 0x66, 0x6c, 0x61, 0x74, 0x6d, 0x61, 0x70, 0x1a, 0x3a, 0x0a, 0x0c, 0x46, 0x6c, 0x61, + 0x74, 0x6d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8d, 0x0a, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x1a, 0xa2, 0x02, 0x0a, 0x05, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, + 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x0a, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x0a, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x10, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x69, 0x6e, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x36, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x0f, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1e, + 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x1a, 0xe4, + 0x02, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x66, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x52, 0x0a, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x1a, 0x0a, + 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6d, + 0x70, 0x75, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x6f, 0x6d, + 0x70, 0x75, 0x74, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x12, 0x40, 0x0a, 0x10, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, + 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, + 0x74, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x1a, 0xa7, 0x02, 0x0a, 0x0b, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x12, 0x43, 0x0a, 0x07, 0x6e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x07, 0x6e, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x74, + 0x65, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x49, 0x74, + 0x65, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, 0x73, + 0x22, 0x4d, 0x0a, 0x0b, 0x4e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, + 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, + 0x53, 0x49, 0x4e, 0x47, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x49, 0x53, 0x54, + 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x45, 0x54, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x4d, + 0x41, 0x50, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, 0x05, 0x1a, + 0x83, 0x02, 0x0a, 0x06, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x3b, 0x0a, 0x0a, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x07, 0x6e, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x07, + 0x6e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x49, + 0x74, 0x65, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x49, 0x74, 0x65, 0x6d, + 0x73, 0x22, 0x42, 0x0a, 0x0b, 0x4e, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4d, 0x6f, 0x64, 0x65, + 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, + 0x06, 0x53, 0x49, 0x4e, 0x47, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x49, 0x53, + 0x54, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x45, 0x54, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, + 0x4d, 0x41, 0x50, 0x10, 0x04, 0x22, 0xd0, 0x04, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x1a, 0x09, 0x0a, 0x07, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0xaf, 0x04, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x12, 0x65, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x74, + 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x12, 0x6c, 0x0a, 0x13, 0x64, 0x61, 0x74, + 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x36, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, + 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, + 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, + 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x12, 0x36, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x74, + 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x55, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, + 0x57, 0x0a, 0x16, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x99, 0x01, 0x0a, 0x16, 0x56, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x1a, 0x3a, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, + 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, + 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, + 0x43, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, + 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, + 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x22, 0x90, 0x02, 0x0a, 0x14, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x72, 0x0a, + 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x30, 0x0a, 0x09, 0x72, 0x61, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x52, + 0x61, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x08, 0x72, 0x61, 0x77, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x1a, 0x83, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, + 0x0a, 0x0e, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x0d, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x37, + 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, + 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, + 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0xb6, 0x01, 0x0a, 0x16, 0x56, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x1a, 0x57, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, + 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x43, 0x0a, 0x08, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, + 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, + 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, + 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x22, 0xba, 0x01, 0x0a, 0x1a, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, + 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, + 0x57, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, + 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, + 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x43, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, + 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, + 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0xc1, 0x01, + 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x1a, 0x67, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, + 0x0a, 0x11, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x74, 0x65, 0x72, 0x72, 0x61, + 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x43, 0x0a, 0x08, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, + 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, + 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, + 0x73, 0x22, 0xe3, 0x02, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x1a, 0xbc, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, + 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, + 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, + 0x76, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, + 0x61, 0x1a, 0x93, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, + 0x0a, 0x09, 0x6e, 0x65, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, + 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, + 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, + 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x22, 0xc4, 0x04, 0x0a, 0x12, 0x50, 0x6c, 0x61, 0x6e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0xbb, + 0x02, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, + 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, + 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6f, 0x72, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, + 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x45, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x5f, 0x6e, 0x65, + 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, + 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x64, + 0x4e, 0x65, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x69, + 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0c, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x3c, + 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0xef, 0x01, 0x0a, + 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x6c, 0x61, + 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, + 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70, 0x6c, 0x61, 0x6e, 0x6e, + 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x43, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x52, 0x0f, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, + 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x72, + 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, + 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0xe4, + 0x03, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0xb6, 0x02, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x38, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, + 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x70, + 0x72, 0x69, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x6c, 0x61, + 0x6e, 0x6e, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, + 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x70, 0x6c, 0x61, 0x6e, 0x6e, + 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x6c, 0x61, 0x6e, + 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0e, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, + 0x65, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x1a, + 0x93, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09, + 0x6e, 0x65, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, + 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6e, 0x65, 0x77, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, + 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, + 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0xed, 0x02, 0x0a, 0x13, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x36, 0x0a, + 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x1a, 0x78, 0x0a, 0x10, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, + 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x1a, + 0xa3, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x12, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x11, 0x69, 0x6d, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x0b, + 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, + 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0x9c, 0x02, 0x0a, 0x0e, 0x52, 0x65, 0x61, 0x64, 0x44, 0x61, + 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x1a, 0x95, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, + 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x6d, + 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, + 0x1a, 0x72, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x66, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, + 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x44, 0x69, 0x61, + 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x2a, 0x25, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x69, + 0x6e, 0x64, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, + 0x08, 0x4d, 0x41, 0x52, 0x4b, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x01, 0x32, 0xcc, 0x09, 0x0a, 0x08, + 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x60, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x24, 0x2e, + 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, + 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x16, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, + 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2a, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x56, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x16, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x36, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2a, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x56, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x1a, + 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x2e, 0x74, 0x66, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x66, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, + 0x74, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x14, 0x55, 0x70, 0x67, + 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x27, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x55, 0x70, + 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x74, 0x66, 0x70, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x74, 0x66, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x25, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x36, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x36, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x12, 0x50, 0x6c, 0x61, + 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, + 0x25, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x50, 0x6c, 0x61, 0x6e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x36, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, + 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x26, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x36, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, + 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x13, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x2e, + 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x36, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, + 0x0a, 0x0e, 0x52, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x21, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x52, 0x65, 0x61, + 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x2e, + 0x52, 0x65, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0c, 0x53, 0x74, 0x6f, 0x70, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x36, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x66, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x36, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_tfplugin6_proto_rawDescOnce sync.Once + file_tfplugin6_proto_rawDescData = file_tfplugin6_proto_rawDesc +) + +func file_tfplugin6_proto_rawDescGZIP() []byte { + file_tfplugin6_proto_rawDescOnce.Do(func() { + file_tfplugin6_proto_rawDescData = protoimpl.X.CompressGZIP(file_tfplugin6_proto_rawDescData) + }) + return file_tfplugin6_proto_rawDescData +} + +var file_tfplugin6_proto_enumTypes = make([]protoimpl.EnumInfo, 4) +var file_tfplugin6_proto_msgTypes = make([]protoimpl.MessageInfo, 50) +var file_tfplugin6_proto_goTypes = []interface{}{ + (StringKind)(0), // 0: tfplugin6.StringKind + (Diagnostic_Severity)(0), // 1: tfplugin6.Diagnostic.Severity + (Schema_NestedBlock_NestingMode)(0), // 2: tfplugin6.Schema.NestedBlock.NestingMode + (Schema_Object_NestingMode)(0), // 3: tfplugin6.Schema.Object.NestingMode + (*DynamicValue)(nil), // 4: tfplugin6.DynamicValue + (*Diagnostic)(nil), // 5: tfplugin6.Diagnostic + (*AttributePath)(nil), // 6: tfplugin6.AttributePath + (*StopProvider)(nil), // 7: tfplugin6.StopProvider + (*RawState)(nil), // 8: tfplugin6.RawState + (*Schema)(nil), // 9: tfplugin6.Schema + (*GetProviderSchema)(nil), // 10: tfplugin6.GetProviderSchema + (*ValidateProviderConfig)(nil), // 11: tfplugin6.ValidateProviderConfig + (*UpgradeResourceState)(nil), // 12: tfplugin6.UpgradeResourceState + (*ValidateResourceConfig)(nil), // 13: tfplugin6.ValidateResourceConfig + (*ValidateDataResourceConfig)(nil), // 14: tfplugin6.ValidateDataResourceConfig + (*ConfigureProvider)(nil), // 15: tfplugin6.ConfigureProvider + (*ReadResource)(nil), // 16: tfplugin6.ReadResource + (*PlanResourceChange)(nil), // 17: tfplugin6.PlanResourceChange + (*ApplyResourceChange)(nil), // 18: tfplugin6.ApplyResourceChange + (*ImportResourceState)(nil), // 19: tfplugin6.ImportResourceState + (*ReadDataSource)(nil), // 20: tfplugin6.ReadDataSource + (*AttributePath_Step)(nil), // 21: tfplugin6.AttributePath.Step + (*StopProvider_Request)(nil), // 22: tfplugin6.StopProvider.Request + (*StopProvider_Response)(nil), // 23: tfplugin6.StopProvider.Response + nil, // 24: tfplugin6.RawState.FlatmapEntry + (*Schema_Block)(nil), // 25: tfplugin6.Schema.Block + (*Schema_Attribute)(nil), // 26: tfplugin6.Schema.Attribute + (*Schema_NestedBlock)(nil), // 27: tfplugin6.Schema.NestedBlock + (*Schema_Object)(nil), // 28: tfplugin6.Schema.Object + (*GetProviderSchema_Request)(nil), // 29: tfplugin6.GetProviderSchema.Request + (*GetProviderSchema_Response)(nil), // 30: tfplugin6.GetProviderSchema.Response + nil, // 31: tfplugin6.GetProviderSchema.Response.ResourceSchemasEntry + nil, // 32: tfplugin6.GetProviderSchema.Response.DataSourceSchemasEntry + (*ValidateProviderConfig_Request)(nil), // 33: tfplugin6.ValidateProviderConfig.Request + (*ValidateProviderConfig_Response)(nil), // 34: tfplugin6.ValidateProviderConfig.Response + (*UpgradeResourceState_Request)(nil), // 35: tfplugin6.UpgradeResourceState.Request + (*UpgradeResourceState_Response)(nil), // 36: tfplugin6.UpgradeResourceState.Response + (*ValidateResourceConfig_Request)(nil), // 37: tfplugin6.ValidateResourceConfig.Request + (*ValidateResourceConfig_Response)(nil), // 38: tfplugin6.ValidateResourceConfig.Response + (*ValidateDataResourceConfig_Request)(nil), // 39: tfplugin6.ValidateDataResourceConfig.Request + (*ValidateDataResourceConfig_Response)(nil), // 40: tfplugin6.ValidateDataResourceConfig.Response + (*ConfigureProvider_Request)(nil), // 41: tfplugin6.ConfigureProvider.Request + (*ConfigureProvider_Response)(nil), // 42: tfplugin6.ConfigureProvider.Response + (*ReadResource_Request)(nil), // 43: tfplugin6.ReadResource.Request + (*ReadResource_Response)(nil), // 44: tfplugin6.ReadResource.Response + (*PlanResourceChange_Request)(nil), // 45: tfplugin6.PlanResourceChange.Request + (*PlanResourceChange_Response)(nil), // 46: tfplugin6.PlanResourceChange.Response + (*ApplyResourceChange_Request)(nil), // 47: tfplugin6.ApplyResourceChange.Request + (*ApplyResourceChange_Response)(nil), // 48: tfplugin6.ApplyResourceChange.Response + (*ImportResourceState_Request)(nil), // 49: tfplugin6.ImportResourceState.Request + (*ImportResourceState_ImportedResource)(nil), // 50: tfplugin6.ImportResourceState.ImportedResource + (*ImportResourceState_Response)(nil), // 51: tfplugin6.ImportResourceState.Response + (*ReadDataSource_Request)(nil), // 52: tfplugin6.ReadDataSource.Request + (*ReadDataSource_Response)(nil), // 53: tfplugin6.ReadDataSource.Response +} +var file_tfplugin6_proto_depIdxs = []int32{ + 1, // 0: tfplugin6.Diagnostic.severity:type_name -> tfplugin6.Diagnostic.Severity + 6, // 1: tfplugin6.Diagnostic.attribute:type_name -> tfplugin6.AttributePath + 21, // 2: tfplugin6.AttributePath.steps:type_name -> tfplugin6.AttributePath.Step + 24, // 3: tfplugin6.RawState.flatmap:type_name -> tfplugin6.RawState.FlatmapEntry + 25, // 4: tfplugin6.Schema.block:type_name -> tfplugin6.Schema.Block + 26, // 5: tfplugin6.Schema.Block.attributes:type_name -> tfplugin6.Schema.Attribute + 27, // 6: tfplugin6.Schema.Block.block_types:type_name -> tfplugin6.Schema.NestedBlock + 0, // 7: tfplugin6.Schema.Block.description_kind:type_name -> tfplugin6.StringKind + 28, // 8: tfplugin6.Schema.Attribute.nested_type:type_name -> tfplugin6.Schema.Object + 0, // 9: tfplugin6.Schema.Attribute.description_kind:type_name -> tfplugin6.StringKind + 25, // 10: tfplugin6.Schema.NestedBlock.block:type_name -> tfplugin6.Schema.Block + 2, // 11: tfplugin6.Schema.NestedBlock.nesting:type_name -> tfplugin6.Schema.NestedBlock.NestingMode + 26, // 12: tfplugin6.Schema.Object.attributes:type_name -> tfplugin6.Schema.Attribute + 3, // 13: tfplugin6.Schema.Object.nesting:type_name -> tfplugin6.Schema.Object.NestingMode + 9, // 14: tfplugin6.GetProviderSchema.Response.provider:type_name -> tfplugin6.Schema + 31, // 15: tfplugin6.GetProviderSchema.Response.resource_schemas:type_name -> tfplugin6.GetProviderSchema.Response.ResourceSchemasEntry + 32, // 16: tfplugin6.GetProviderSchema.Response.data_source_schemas:type_name -> tfplugin6.GetProviderSchema.Response.DataSourceSchemasEntry + 5, // 17: tfplugin6.GetProviderSchema.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 9, // 18: tfplugin6.GetProviderSchema.Response.provider_meta:type_name -> tfplugin6.Schema + 9, // 19: tfplugin6.GetProviderSchema.Response.ResourceSchemasEntry.value:type_name -> tfplugin6.Schema + 9, // 20: tfplugin6.GetProviderSchema.Response.DataSourceSchemasEntry.value:type_name -> tfplugin6.Schema + 4, // 21: tfplugin6.ValidateProviderConfig.Request.config:type_name -> tfplugin6.DynamicValue + 5, // 22: tfplugin6.ValidateProviderConfig.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 8, // 23: tfplugin6.UpgradeResourceState.Request.raw_state:type_name -> tfplugin6.RawState + 4, // 24: tfplugin6.UpgradeResourceState.Response.upgraded_state:type_name -> tfplugin6.DynamicValue + 5, // 25: tfplugin6.UpgradeResourceState.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 4, // 26: tfplugin6.ValidateResourceConfig.Request.config:type_name -> tfplugin6.DynamicValue + 5, // 27: tfplugin6.ValidateResourceConfig.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 4, // 28: tfplugin6.ValidateDataResourceConfig.Request.config:type_name -> tfplugin6.DynamicValue + 5, // 29: tfplugin6.ValidateDataResourceConfig.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 4, // 30: tfplugin6.ConfigureProvider.Request.config:type_name -> tfplugin6.DynamicValue + 5, // 31: tfplugin6.ConfigureProvider.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 4, // 32: tfplugin6.ReadResource.Request.current_state:type_name -> tfplugin6.DynamicValue + 4, // 33: tfplugin6.ReadResource.Request.provider_meta:type_name -> tfplugin6.DynamicValue + 4, // 34: tfplugin6.ReadResource.Response.new_state:type_name -> tfplugin6.DynamicValue + 5, // 35: tfplugin6.ReadResource.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 4, // 36: tfplugin6.PlanResourceChange.Request.prior_state:type_name -> tfplugin6.DynamicValue + 4, // 37: tfplugin6.PlanResourceChange.Request.proposed_new_state:type_name -> tfplugin6.DynamicValue + 4, // 38: tfplugin6.PlanResourceChange.Request.config:type_name -> tfplugin6.DynamicValue + 4, // 39: tfplugin6.PlanResourceChange.Request.provider_meta:type_name -> tfplugin6.DynamicValue + 4, // 40: tfplugin6.PlanResourceChange.Response.planned_state:type_name -> tfplugin6.DynamicValue + 6, // 41: tfplugin6.PlanResourceChange.Response.requires_replace:type_name -> tfplugin6.AttributePath + 5, // 42: tfplugin6.PlanResourceChange.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 4, // 43: tfplugin6.ApplyResourceChange.Request.prior_state:type_name -> tfplugin6.DynamicValue + 4, // 44: tfplugin6.ApplyResourceChange.Request.planned_state:type_name -> tfplugin6.DynamicValue + 4, // 45: tfplugin6.ApplyResourceChange.Request.config:type_name -> tfplugin6.DynamicValue + 4, // 46: tfplugin6.ApplyResourceChange.Request.provider_meta:type_name -> tfplugin6.DynamicValue + 4, // 47: tfplugin6.ApplyResourceChange.Response.new_state:type_name -> tfplugin6.DynamicValue + 5, // 48: tfplugin6.ApplyResourceChange.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 4, // 49: tfplugin6.ImportResourceState.ImportedResource.state:type_name -> tfplugin6.DynamicValue + 50, // 50: tfplugin6.ImportResourceState.Response.imported_resources:type_name -> tfplugin6.ImportResourceState.ImportedResource + 5, // 51: tfplugin6.ImportResourceState.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 4, // 52: tfplugin6.ReadDataSource.Request.config:type_name -> tfplugin6.DynamicValue + 4, // 53: tfplugin6.ReadDataSource.Request.provider_meta:type_name -> tfplugin6.DynamicValue + 4, // 54: tfplugin6.ReadDataSource.Response.state:type_name -> tfplugin6.DynamicValue + 5, // 55: tfplugin6.ReadDataSource.Response.diagnostics:type_name -> tfplugin6.Diagnostic + 29, // 56: tfplugin6.Provider.GetProviderSchema:input_type -> tfplugin6.GetProviderSchema.Request + 33, // 57: tfplugin6.Provider.ValidateProviderConfig:input_type -> tfplugin6.ValidateProviderConfig.Request + 37, // 58: tfplugin6.Provider.ValidateResourceConfig:input_type -> tfplugin6.ValidateResourceConfig.Request + 39, // 59: tfplugin6.Provider.ValidateDataResourceConfig:input_type -> tfplugin6.ValidateDataResourceConfig.Request + 35, // 60: tfplugin6.Provider.UpgradeResourceState:input_type -> tfplugin6.UpgradeResourceState.Request + 41, // 61: tfplugin6.Provider.ConfigureProvider:input_type -> tfplugin6.ConfigureProvider.Request + 43, // 62: tfplugin6.Provider.ReadResource:input_type -> tfplugin6.ReadResource.Request + 45, // 63: tfplugin6.Provider.PlanResourceChange:input_type -> tfplugin6.PlanResourceChange.Request + 47, // 64: tfplugin6.Provider.ApplyResourceChange:input_type -> tfplugin6.ApplyResourceChange.Request + 49, // 65: tfplugin6.Provider.ImportResourceState:input_type -> tfplugin6.ImportResourceState.Request + 52, // 66: tfplugin6.Provider.ReadDataSource:input_type -> tfplugin6.ReadDataSource.Request + 22, // 67: tfplugin6.Provider.StopProvider:input_type -> tfplugin6.StopProvider.Request + 30, // 68: tfplugin6.Provider.GetProviderSchema:output_type -> tfplugin6.GetProviderSchema.Response + 34, // 69: tfplugin6.Provider.ValidateProviderConfig:output_type -> tfplugin6.ValidateProviderConfig.Response + 38, // 70: tfplugin6.Provider.ValidateResourceConfig:output_type -> tfplugin6.ValidateResourceConfig.Response + 40, // 71: tfplugin6.Provider.ValidateDataResourceConfig:output_type -> tfplugin6.ValidateDataResourceConfig.Response + 36, // 72: tfplugin6.Provider.UpgradeResourceState:output_type -> tfplugin6.UpgradeResourceState.Response + 42, // 73: tfplugin6.Provider.ConfigureProvider:output_type -> tfplugin6.ConfigureProvider.Response + 44, // 74: tfplugin6.Provider.ReadResource:output_type -> tfplugin6.ReadResource.Response + 46, // 75: tfplugin6.Provider.PlanResourceChange:output_type -> tfplugin6.PlanResourceChange.Response + 48, // 76: tfplugin6.Provider.ApplyResourceChange:output_type -> tfplugin6.ApplyResourceChange.Response + 51, // 77: tfplugin6.Provider.ImportResourceState:output_type -> tfplugin6.ImportResourceState.Response + 53, // 78: tfplugin6.Provider.ReadDataSource:output_type -> tfplugin6.ReadDataSource.Response + 23, // 79: tfplugin6.Provider.StopProvider:output_type -> tfplugin6.StopProvider.Response + 68, // [68:80] is the sub-list for method output_type + 56, // [56:68] is the sub-list for method input_type + 56, // [56:56] is the sub-list for extension type_name + 56, // [56:56] is the sub-list for extension extendee + 0, // [0:56] is the sub-list for field type_name +} + +func init() { file_tfplugin6_proto_init() } +func file_tfplugin6_proto_init() { + if File_tfplugin6_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_tfplugin6_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DynamicValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Diagnostic); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AttributePath); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StopProvider); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RawState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Schema); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetProviderSchema); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateProviderConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpgradeResourceState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateResourceConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateDataResourceConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ConfigureProvider); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadResource); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PlanResourceChange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyResourceChange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ImportResourceState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadDataSource); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AttributePath_Step); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StopProvider_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StopProvider_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Schema_Block); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Schema_Attribute); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Schema_NestedBlock); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Schema_Object); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetProviderSchema_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetProviderSchema_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateProviderConfig_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateProviderConfig_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpgradeResourceState_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpgradeResourceState_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateResourceConfig_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateResourceConfig_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateDataResourceConfig_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateDataResourceConfig_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ConfigureProvider_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ConfigureProvider_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadResource_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadResource_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PlanResourceChange_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PlanResourceChange_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyResourceChange_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyResourceChange_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ImportResourceState_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ImportResourceState_ImportedResource); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ImportResourceState_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadDataSource_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tfplugin6_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadDataSource_Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_tfplugin6_proto_msgTypes[17].OneofWrappers = []interface{}{ + (*AttributePath_Step_AttributeName)(nil), + (*AttributePath_Step_ElementKeyString)(nil), + (*AttributePath_Step_ElementKeyInt)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_tfplugin6_proto_rawDesc, + NumEnums: 4, + NumMessages: 50, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_tfplugin6_proto_goTypes, + DependencyIndexes: file_tfplugin6_proto_depIdxs, + EnumInfos: file_tfplugin6_proto_enumTypes, + MessageInfos: file_tfplugin6_proto_msgTypes, + }.Build() + File_tfplugin6_proto = out.File + file_tfplugin6_proto_rawDesc = nil + file_tfplugin6_proto_goTypes = nil + file_tfplugin6_proto_depIdxs = nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6.proto b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6.proto new file mode 100644 index 000000000000..9986f780ac1c --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6.proto @@ -0,0 +1,321 @@ +// Terraform Plugin RPC protocol version 6.0 +// +// This file defines version 6.0 of the RPC protocol. To implement a plugin +// against this protocol, copy this definition into your own codebase and +// use protoc to generate stubs for your target language. +// +// This file will not be updated. Any minor versions of protocol 6 to follow +// should copy this file and modify the copy while maintaing backwards +// compatibility. Breaking changes, if any are required, will come +// in a subsequent major version with its own separate proto definition. +// +// Note that only the proto files included in a release tag of Terraform are +// official protocol releases. Proto files taken from other commits may include +// incomplete changes or features that did not make it into a final release. +// In all reasonable cases, plugin developers should take the proto file from +// the tag of the most recent release of Terraform, and not from the main +// branch or any other development branch. +// +syntax = "proto3"; +option go_package = "github.com/hashicorp/terraform/internal/tfplugin6"; + +package tfplugin6; + +// DynamicValue is an opaque encoding of terraform data, with the field name +// indicating the encoding scheme used. +message DynamicValue { + bytes msgpack = 1; + bytes json = 2; +} + +message Diagnostic { + enum Severity { + INVALID = 0; + ERROR = 1; + WARNING = 2; + } + Severity severity = 1; + string summary = 2; + string detail = 3; + AttributePath attribute = 4; +} + +message AttributePath { + message Step { + oneof selector { + // Set "attribute_name" to represent looking up an attribute + // in the current object value. + string attribute_name = 1; + // Set "element_key_*" to represent looking up an element in + // an indexable collection type. + string element_key_string = 2; + int64 element_key_int = 3; + } + } + repeated Step steps = 1; +} + +message StopProvider { + message Request { + } + message Response { + string Error = 1; + } +} + +// RawState holds the stored state for a resource to be upgraded by the +// provider. It can be in one of two formats, the current json encoded format +// in bytes, or the legacy flatmap format as a map of strings. +message RawState { + bytes json = 1; + map flatmap = 2; +} + +enum StringKind { + PLAIN = 0; + MARKDOWN = 1; +} + +// Schema is the configuration schema for a Resource or Provider. +message Schema { + message Block { + int64 version = 1; + repeated Attribute attributes = 2; + repeated NestedBlock block_types = 3; + string description = 4; + StringKind description_kind = 5; + bool deprecated = 6; + } + + message Attribute { + string name = 1; + bytes type = 2; + Object nested_type = 10; + string description = 3; + bool required = 4; + bool optional = 5; + bool computed = 6; + bool sensitive = 7; + StringKind description_kind = 8; + bool deprecated = 9; + } + + message NestedBlock { + enum NestingMode { + INVALID = 0; + SINGLE = 1; + LIST = 2; + SET = 3; + MAP = 4; + GROUP = 5; + } + + string type_name = 1; + Block block = 2; + NestingMode nesting = 3; + int64 min_items = 4; + int64 max_items = 5; + } + + message Object { + enum NestingMode { + INVALID = 0; + SINGLE = 1; + LIST = 2; + SET = 3; + MAP = 4; + } + + repeated Attribute attributes = 1; + NestingMode nesting = 3; + int64 min_items = 4; + int64 max_items = 5; + } + + // The version of the schema. + // Schemas are versioned, so that providers can upgrade a saved resource + // state when the schema is changed. + int64 version = 1; + + // Block is the top level configuration block for this schema. + Block block = 2; +} + +service Provider { + //////// Information about what a provider supports/expects + rpc GetProviderSchema(GetProviderSchema.Request) returns (GetProviderSchema.Response); + rpc ValidateProviderConfig(ValidateProviderConfig.Request) returns (ValidateProviderConfig.Response); + rpc ValidateResourceConfig(ValidateResourceConfig.Request) returns (ValidateResourceConfig.Response); + rpc ValidateDataResourceConfig(ValidateDataResourceConfig.Request) returns (ValidateDataResourceConfig.Response); + rpc UpgradeResourceState(UpgradeResourceState.Request) returns (UpgradeResourceState.Response); + + //////// One-time initialization, called before other functions below + rpc ConfigureProvider(ConfigureProvider.Request) returns (ConfigureProvider.Response); + + //////// Managed Resource Lifecycle + rpc ReadResource(ReadResource.Request) returns (ReadResource.Response); + rpc PlanResourceChange(PlanResourceChange.Request) returns (PlanResourceChange.Response); + rpc ApplyResourceChange(ApplyResourceChange.Request) returns (ApplyResourceChange.Response); + rpc ImportResourceState(ImportResourceState.Request) returns (ImportResourceState.Response); + + rpc ReadDataSource(ReadDataSource.Request) returns (ReadDataSource.Response); + + //////// Graceful Shutdown + rpc StopProvider(StopProvider.Request) returns (StopProvider.Response); +} + +message GetProviderSchema { + message Request { + } + message Response { + Schema provider = 1; + map resource_schemas = 2; + map data_source_schemas = 3; + repeated Diagnostic diagnostics = 4; + Schema provider_meta = 5; + } +} + +message ValidateProviderConfig { + message Request { + DynamicValue config = 1; + } + message Response { + repeated Diagnostic diagnostics = 2; + } +} + +message UpgradeResourceState { + message Request { + string type_name = 1; + + // version is the schema_version number recorded in the state file + int64 version = 2; + + // raw_state is the raw states as stored for the resource. Core does + // not have access to the schema of prior_version, so it's the + // provider's responsibility to interpret this value using the + // appropriate older schema. The raw_state will be the json encoded + // state, or a legacy flat-mapped format. + RawState raw_state = 3; + } + message Response { + // new_state is a msgpack-encoded data structure that, when interpreted with + // the _current_ schema for this resource type, is functionally equivalent to + // that which was given in prior_state_raw. + DynamicValue upgraded_state = 1; + + // diagnostics describes any errors encountered during migration that could not + // be safely resolved, and warnings about any possibly-risky assumptions made + // in the upgrade process. + repeated Diagnostic diagnostics = 2; + } +} + +message ValidateResourceConfig { + message Request { + string type_name = 1; + DynamicValue config = 2; + } + message Response { + repeated Diagnostic diagnostics = 1; + } +} + +message ValidateDataResourceConfig { + message Request { + string type_name = 1; + DynamicValue config = 2; + } + message Response { + repeated Diagnostic diagnostics = 1; + } +} + +message ConfigureProvider { + message Request { + string terraform_version = 1; + DynamicValue config = 2; + } + message Response { + repeated Diagnostic diagnostics = 1; + } +} + +message ReadResource { + message Request { + string type_name = 1; + DynamicValue current_state = 2; + bytes private = 3; + DynamicValue provider_meta = 4; + } + message Response { + DynamicValue new_state = 1; + repeated Diagnostic diagnostics = 2; + bytes private = 3; + } +} + +message PlanResourceChange { + message Request { + string type_name = 1; + DynamicValue prior_state = 2; + DynamicValue proposed_new_state = 3; + DynamicValue config = 4; + bytes prior_private = 5; + DynamicValue provider_meta = 6; + } + + message Response { + DynamicValue planned_state = 1; + repeated AttributePath requires_replace = 2; + bytes planned_private = 3; + repeated Diagnostic diagnostics = 4; + } +} + +message ApplyResourceChange { + message Request { + string type_name = 1; + DynamicValue prior_state = 2; + DynamicValue planned_state = 3; + DynamicValue config = 4; + bytes planned_private = 5; + DynamicValue provider_meta = 6; + } + message Response { + DynamicValue new_state = 1; + bytes private = 2; + repeated Diagnostic diagnostics = 3; + } +} + +message ImportResourceState { + message Request { + string type_name = 1; + string id = 2; + } + + message ImportedResource { + string type_name = 1; + DynamicValue state = 2; + bytes private = 3; + } + + message Response { + repeated ImportedResource imported_resources = 1; + repeated Diagnostic diagnostics = 2; + } +} + +message ReadDataSource { + message Request { + string type_name = 1; + DynamicValue config = 2; + DynamicValue provider_meta = 3; + } + message Response { + DynamicValue state = 1; + repeated Diagnostic diagnostics = 2; + } +} \ No newline at end of file diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6_grpc.pb.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6_grpc.pb.go new file mode 100644 index 000000000000..957e9d239330 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6/tfplugin6_grpc.pb.go @@ -0,0 +1,505 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package tfplugin6 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// ProviderClient is the client API for Provider service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ProviderClient interface { + //////// Information about what a provider supports/expects + GetProviderSchema(ctx context.Context, in *GetProviderSchema_Request, opts ...grpc.CallOption) (*GetProviderSchema_Response, error) + ValidateProviderConfig(ctx context.Context, in *ValidateProviderConfig_Request, opts ...grpc.CallOption) (*ValidateProviderConfig_Response, error) + ValidateResourceConfig(ctx context.Context, in *ValidateResourceConfig_Request, opts ...grpc.CallOption) (*ValidateResourceConfig_Response, error) + ValidateDataResourceConfig(ctx context.Context, in *ValidateDataResourceConfig_Request, opts ...grpc.CallOption) (*ValidateDataResourceConfig_Response, error) + UpgradeResourceState(ctx context.Context, in *UpgradeResourceState_Request, opts ...grpc.CallOption) (*UpgradeResourceState_Response, error) + //////// One-time initialization, called before other functions below + ConfigureProvider(ctx context.Context, in *ConfigureProvider_Request, opts ...grpc.CallOption) (*ConfigureProvider_Response, error) + //////// Managed Resource Lifecycle + ReadResource(ctx context.Context, in *ReadResource_Request, opts ...grpc.CallOption) (*ReadResource_Response, error) + PlanResourceChange(ctx context.Context, in *PlanResourceChange_Request, opts ...grpc.CallOption) (*PlanResourceChange_Response, error) + ApplyResourceChange(ctx context.Context, in *ApplyResourceChange_Request, opts ...grpc.CallOption) (*ApplyResourceChange_Response, error) + ImportResourceState(ctx context.Context, in *ImportResourceState_Request, opts ...grpc.CallOption) (*ImportResourceState_Response, error) + ReadDataSource(ctx context.Context, in *ReadDataSource_Request, opts ...grpc.CallOption) (*ReadDataSource_Response, error) + //////// Graceful Shutdown + StopProvider(ctx context.Context, in *StopProvider_Request, opts ...grpc.CallOption) (*StopProvider_Response, error) +} + +type providerClient struct { + cc grpc.ClientConnInterface +} + +func NewProviderClient(cc grpc.ClientConnInterface) ProviderClient { + return &providerClient{cc} +} + +func (c *providerClient) GetProviderSchema(ctx context.Context, in *GetProviderSchema_Request, opts ...grpc.CallOption) (*GetProviderSchema_Response, error) { + out := new(GetProviderSchema_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/GetProviderSchema", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) ValidateProviderConfig(ctx context.Context, in *ValidateProviderConfig_Request, opts ...grpc.CallOption) (*ValidateProviderConfig_Response, error) { + out := new(ValidateProviderConfig_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ValidateProviderConfig", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) ValidateResourceConfig(ctx context.Context, in *ValidateResourceConfig_Request, opts ...grpc.CallOption) (*ValidateResourceConfig_Response, error) { + out := new(ValidateResourceConfig_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ValidateResourceConfig", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) ValidateDataResourceConfig(ctx context.Context, in *ValidateDataResourceConfig_Request, opts ...grpc.CallOption) (*ValidateDataResourceConfig_Response, error) { + out := new(ValidateDataResourceConfig_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ValidateDataResourceConfig", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) UpgradeResourceState(ctx context.Context, in *UpgradeResourceState_Request, opts ...grpc.CallOption) (*UpgradeResourceState_Response, error) { + out := new(UpgradeResourceState_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/UpgradeResourceState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) ConfigureProvider(ctx context.Context, in *ConfigureProvider_Request, opts ...grpc.CallOption) (*ConfigureProvider_Response, error) { + out := new(ConfigureProvider_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ConfigureProvider", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) ReadResource(ctx context.Context, in *ReadResource_Request, opts ...grpc.CallOption) (*ReadResource_Response, error) { + out := new(ReadResource_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ReadResource", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) PlanResourceChange(ctx context.Context, in *PlanResourceChange_Request, opts ...grpc.CallOption) (*PlanResourceChange_Response, error) { + out := new(PlanResourceChange_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/PlanResourceChange", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) ApplyResourceChange(ctx context.Context, in *ApplyResourceChange_Request, opts ...grpc.CallOption) (*ApplyResourceChange_Response, error) { + out := new(ApplyResourceChange_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ApplyResourceChange", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) ImportResourceState(ctx context.Context, in *ImportResourceState_Request, opts ...grpc.CallOption) (*ImportResourceState_Response, error) { + out := new(ImportResourceState_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ImportResourceState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) ReadDataSource(ctx context.Context, in *ReadDataSource_Request, opts ...grpc.CallOption) (*ReadDataSource_Response, error) { + out := new(ReadDataSource_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/ReadDataSource", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *providerClient) StopProvider(ctx context.Context, in *StopProvider_Request, opts ...grpc.CallOption) (*StopProvider_Response, error) { + out := new(StopProvider_Response) + err := c.cc.Invoke(ctx, "/tfplugin6.Provider/StopProvider", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ProviderServer is the server API for Provider service. +// All implementations must embed UnimplementedProviderServer +// for forward compatibility +type ProviderServer interface { + //////// Information about what a provider supports/expects + GetProviderSchema(context.Context, *GetProviderSchema_Request) (*GetProviderSchema_Response, error) + ValidateProviderConfig(context.Context, *ValidateProviderConfig_Request) (*ValidateProviderConfig_Response, error) + ValidateResourceConfig(context.Context, *ValidateResourceConfig_Request) (*ValidateResourceConfig_Response, error) + ValidateDataResourceConfig(context.Context, *ValidateDataResourceConfig_Request) (*ValidateDataResourceConfig_Response, error) + UpgradeResourceState(context.Context, *UpgradeResourceState_Request) (*UpgradeResourceState_Response, error) + //////// One-time initialization, called before other functions below + ConfigureProvider(context.Context, *ConfigureProvider_Request) (*ConfigureProvider_Response, error) + //////// Managed Resource Lifecycle + ReadResource(context.Context, *ReadResource_Request) (*ReadResource_Response, error) + PlanResourceChange(context.Context, *PlanResourceChange_Request) (*PlanResourceChange_Response, error) + ApplyResourceChange(context.Context, *ApplyResourceChange_Request) (*ApplyResourceChange_Response, error) + ImportResourceState(context.Context, *ImportResourceState_Request) (*ImportResourceState_Response, error) + ReadDataSource(context.Context, *ReadDataSource_Request) (*ReadDataSource_Response, error) + //////// Graceful Shutdown + StopProvider(context.Context, *StopProvider_Request) (*StopProvider_Response, error) + mustEmbedUnimplementedProviderServer() +} + +// UnimplementedProviderServer must be embedded to have forward compatible implementations. +type UnimplementedProviderServer struct { +} + +func (UnimplementedProviderServer) GetProviderSchema(context.Context, *GetProviderSchema_Request) (*GetProviderSchema_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetProviderSchema not implemented") +} +func (UnimplementedProviderServer) ValidateProviderConfig(context.Context, *ValidateProviderConfig_Request) (*ValidateProviderConfig_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ValidateProviderConfig not implemented") +} +func (UnimplementedProviderServer) ValidateResourceConfig(context.Context, *ValidateResourceConfig_Request) (*ValidateResourceConfig_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ValidateResourceConfig not implemented") +} +func (UnimplementedProviderServer) ValidateDataResourceConfig(context.Context, *ValidateDataResourceConfig_Request) (*ValidateDataResourceConfig_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ValidateDataResourceConfig not implemented") +} +func (UnimplementedProviderServer) UpgradeResourceState(context.Context, *UpgradeResourceState_Request) (*UpgradeResourceState_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpgradeResourceState not implemented") +} +func (UnimplementedProviderServer) ConfigureProvider(context.Context, *ConfigureProvider_Request) (*ConfigureProvider_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConfigureProvider not implemented") +} +func (UnimplementedProviderServer) ReadResource(context.Context, *ReadResource_Request) (*ReadResource_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReadResource not implemented") +} +func (UnimplementedProviderServer) PlanResourceChange(context.Context, *PlanResourceChange_Request) (*PlanResourceChange_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method PlanResourceChange not implemented") +} +func (UnimplementedProviderServer) ApplyResourceChange(context.Context, *ApplyResourceChange_Request) (*ApplyResourceChange_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ApplyResourceChange not implemented") +} +func (UnimplementedProviderServer) ImportResourceState(context.Context, *ImportResourceState_Request) (*ImportResourceState_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ImportResourceState not implemented") +} +func (UnimplementedProviderServer) ReadDataSource(context.Context, *ReadDataSource_Request) (*ReadDataSource_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReadDataSource not implemented") +} +func (UnimplementedProviderServer) StopProvider(context.Context, *StopProvider_Request) (*StopProvider_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method StopProvider not implemented") +} +func (UnimplementedProviderServer) mustEmbedUnimplementedProviderServer() {} + +// UnsafeProviderServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ProviderServer will +// result in compilation errors. +type UnsafeProviderServer interface { + mustEmbedUnimplementedProviderServer() +} + +func RegisterProviderServer(s grpc.ServiceRegistrar, srv ProviderServer) { + s.RegisterService(&Provider_ServiceDesc, srv) +} + +func _Provider_GetProviderSchema_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetProviderSchema_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).GetProviderSchema(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/GetProviderSchema", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).GetProviderSchema(ctx, req.(*GetProviderSchema_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_ValidateProviderConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ValidateProviderConfig_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).ValidateProviderConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/ValidateProviderConfig", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).ValidateProviderConfig(ctx, req.(*ValidateProviderConfig_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_ValidateResourceConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ValidateResourceConfig_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).ValidateResourceConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/ValidateResourceConfig", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).ValidateResourceConfig(ctx, req.(*ValidateResourceConfig_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_ValidateDataResourceConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ValidateDataResourceConfig_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).ValidateDataResourceConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/ValidateDataResourceConfig", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).ValidateDataResourceConfig(ctx, req.(*ValidateDataResourceConfig_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_UpgradeResourceState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpgradeResourceState_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).UpgradeResourceState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/UpgradeResourceState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).UpgradeResourceState(ctx, req.(*UpgradeResourceState_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_ConfigureProvider_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ConfigureProvider_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).ConfigureProvider(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/ConfigureProvider", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).ConfigureProvider(ctx, req.(*ConfigureProvider_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_ReadResource_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReadResource_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).ReadResource(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/ReadResource", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).ReadResource(ctx, req.(*ReadResource_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_PlanResourceChange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PlanResourceChange_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).PlanResourceChange(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/PlanResourceChange", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).PlanResourceChange(ctx, req.(*PlanResourceChange_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_ApplyResourceChange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ApplyResourceChange_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).ApplyResourceChange(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/ApplyResourceChange", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).ApplyResourceChange(ctx, req.(*ApplyResourceChange_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_ImportResourceState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ImportResourceState_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).ImportResourceState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/ImportResourceState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).ImportResourceState(ctx, req.(*ImportResourceState_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_ReadDataSource_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReadDataSource_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).ReadDataSource(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/ReadDataSource", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).ReadDataSource(ctx, req.(*ReadDataSource_Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Provider_StopProvider_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StopProvider_Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProviderServer).StopProvider(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tfplugin6.Provider/StopProvider", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProviderServer).StopProvider(ctx, req.(*StopProvider_Request)) + } + return interceptor(ctx, in, info, handler) +} + +// Provider_ServiceDesc is the grpc.ServiceDesc for Provider service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Provider_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "tfplugin6.Provider", + HandlerType: (*ProviderServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetProviderSchema", + Handler: _Provider_GetProviderSchema_Handler, + }, + { + MethodName: "ValidateProviderConfig", + Handler: _Provider_ValidateProviderConfig_Handler, + }, + { + MethodName: "ValidateResourceConfig", + Handler: _Provider_ValidateResourceConfig_Handler, + }, + { + MethodName: "ValidateDataResourceConfig", + Handler: _Provider_ValidateDataResourceConfig_Handler, + }, + { + MethodName: "UpgradeResourceState", + Handler: _Provider_UpgradeResourceState_Handler, + }, + { + MethodName: "ConfigureProvider", + Handler: _Provider_ConfigureProvider_Handler, + }, + { + MethodName: "ReadResource", + Handler: _Provider_ReadResource_Handler, + }, + { + MethodName: "PlanResourceChange", + Handler: _Provider_PlanResourceChange_Handler, + }, + { + MethodName: "ApplyResourceChange", + Handler: _Provider_ApplyResourceChange_Handler, + }, + { + MethodName: "ImportResourceState", + Handler: _Provider_ImportResourceState_Handler, + }, + { + MethodName: "ReadDataSource", + Handler: _Provider_ReadDataSource_Handler, + }, + { + MethodName: "StopProvider", + Handler: _Provider_StopProvider_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "tfplugin6.proto", +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/attribute_path.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/attribute_path.go new file mode 100644 index 000000000000..0cf4daac9bd9 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/attribute_path.go @@ -0,0 +1,98 @@ +package toproto + +import ( + "errors" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +var ErrUnknownAttributePathStepType = errors.New("unknown type of AttributePath_Step") + +func AttributePath(in *tftypes.AttributePath) (*tfplugin6.AttributePath, error) { + if in == nil { + return nil, nil + } + steps, err := AttributePath_Steps(in.Steps()) + if err != nil { + return nil, err + } + return &tfplugin6.AttributePath{ + Steps: steps, + }, nil +} + +func AttributePaths(in []*tftypes.AttributePath) ([]*tfplugin6.AttributePath, error) { + resp := make([]*tfplugin6.AttributePath, 0, len(in)) + for _, a := range in { + if a == nil { + resp = append(resp, nil) + continue + } + attr, err := AttributePath(a) + if err != nil { + return resp, err + } + resp = append(resp, attr) + } + return resp, nil +} + +func AttributePath_Step(step tftypes.AttributePathStep) (*tfplugin6.AttributePath_Step, error) { + var resp tfplugin6.AttributePath_Step + if name, ok := step.(tftypes.AttributeName); ok { + resp.Selector = &tfplugin6.AttributePath_Step_AttributeName{ + AttributeName: string(name), + } + return &resp, nil + } + if key, ok := step.(tftypes.ElementKeyString); ok { + resp.Selector = &tfplugin6.AttributePath_Step_ElementKeyString{ + ElementKeyString: string(key), + } + return &resp, nil + } + if key, ok := step.(tftypes.ElementKeyInt); ok { + resp.Selector = &tfplugin6.AttributePath_Step_ElementKeyInt{ + ElementKeyInt: int64(key), + } + return &resp, nil + } + if _, ok := step.(tftypes.ElementKeyValue); ok { + // the protocol has no equivalent of an ElementKeyValue, so we + // return nil for both the step and the error here, to signal + // that we've hit a step we can't convey back to Terraform + return nil, nil + } + return nil, ErrUnknownAttributePathStepType +} + +func AttributePath_Steps(in []tftypes.AttributePathStep) ([]*tfplugin6.AttributePath_Step, error) { + resp := make([]*tfplugin6.AttributePath_Step, 0, len(in)) + for _, step := range in { + if step == nil { + resp = append(resp, nil) + continue + } + s, err := AttributePath_Step(step) + if err != nil { + return resp, err + } + // in the face of a set, the protocol has no way to represent + // the index, so we just bail and return the prefix we can + // return. + if s == nil { + return resp, nil + } + resp = append(resp, s) + } + return resp, nil +} + +// we have to say this next thing to get golint to stop yelling at us about the +// underscores in the function names. We want the function names to match +// actually-generated code, so it feels like fair play. It's just a shame we +// lose golint for the entire file. +// +// This file is not actually generated. You can edit it. Ignore this next line. +// Code generated by hand ignore this next bit DO NOT EDIT. diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/data_source.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/data_source.go new file mode 100644 index 000000000000..624a3bb108c9 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/data_source.go @@ -0,0 +1,61 @@ +package toproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func ValidateDataResourceConfig_Request(in *tfprotov6.ValidateDataResourceConfigRequest) (*tfplugin6.ValidateDataResourceConfig_Request, error) { + resp := &tfplugin6.ValidateDataResourceConfig_Request{ + TypeName: in.TypeName, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + return resp, nil +} + +func ValidateDataResourceConfig_Response(in *tfprotov6.ValidateDataResourceConfigResponse) (*tfplugin6.ValidateDataResourceConfig_Response, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + return &tfplugin6.ValidateDataResourceConfig_Response{ + Diagnostics: diags, + }, nil +} + +func ReadDataSource_Request(in *tfprotov6.ReadDataSourceRequest) (*tfplugin6.ReadDataSource_Request, error) { + resp := &tfplugin6.ReadDataSource_Request{ + TypeName: in.TypeName, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + if in.ProviderMeta != nil { + resp.ProviderMeta = DynamicValue(in.ProviderMeta) + } + return resp, nil +} + +func ReadDataSource_Response(in *tfprotov6.ReadDataSourceResponse) (*tfplugin6.ReadDataSource_Response, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + resp := &tfplugin6.ReadDataSource_Response{ + Diagnostics: diags, + } + if in.State != nil { + resp.State = DynamicValue(in.State) + } + return resp, nil +} + +// we have to say this next thing to get golint to stop yelling at us about the +// underscores in the function names. We want the function names to match +// actually-generated code, so it feels like fair play. It's just a shame we +// lose golint for the entire file. +// +// This file is not actually generated. You can edit it. Ignore this next line. +// Code generated by hand ignore this next bit DO NOT EDIT. diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/diagnostic.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/diagnostic.go new file mode 100644 index 000000000000..26ce3e9df703 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/diagnostic.go @@ -0,0 +1,50 @@ +package toproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func Diagnostic(in *tfprotov6.Diagnostic) (*tfplugin6.Diagnostic, error) { + diag := &tfplugin6.Diagnostic{ + Severity: Diagnostic_Severity(in.Severity), + Summary: in.Summary, + Detail: in.Detail, + } + if in.Attribute != nil { + attr, err := AttributePath(in.Attribute) + if err != nil { + return diag, err + } + diag.Attribute = attr + } + return diag, nil +} + +func Diagnostic_Severity(in tfprotov6.DiagnosticSeverity) tfplugin6.Diagnostic_Severity { + return tfplugin6.Diagnostic_Severity(in) +} + +func Diagnostics(in []*tfprotov6.Diagnostic) ([]*tfplugin6.Diagnostic, error) { + diagnostics := make([]*tfplugin6.Diagnostic, 0, len(in)) + for _, diag := range in { + if diag == nil { + diagnostics = append(diagnostics, nil) + continue + } + d, err := Diagnostic(diag) + if err != nil { + return diagnostics, err + } + diagnostics = append(diagnostics, d) + } + return diagnostics, nil +} + +// we have to say this next thing to get golint to stop yelling at us about the +// underscores in the function names. We want the function names to match +// actually-generated code, so it feels like fair play. It's just a shame we +// lose golint for the entire file. +// +// This file is not actually generated. You can edit it. Ignore this next line. +// Code generated by hand ignore this next bit DO NOT EDIT. diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/dynamic_value.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/dynamic_value.go new file mode 100644 index 000000000000..ef1693dae4c7 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/dynamic_value.go @@ -0,0 +1,35 @@ +package toproto + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +func DynamicValue(in *tfprotov6.DynamicValue) *tfplugin6.DynamicValue { + return &tfplugin6.DynamicValue{ + Msgpack: in.MsgPack, + Json: in.JSON, + } +} + +func CtyType(in tftypes.Type) ([]byte, error) { + switch { + case in.Is(tftypes.String), in.Is(tftypes.Bool), in.Is(tftypes.Number), + in.Is(tftypes.List{}), in.Is(tftypes.Map{}), + in.Is(tftypes.Set{}), in.Is(tftypes.Object{}), + in.Is(tftypes.Tuple{}), in.Is(tftypes.DynamicPseudoType): + return in.MarshalJSON() //nolint:staticcheck + } + return nil, fmt.Errorf("unknown type %s", in) +} + +// we have to say this next thing to get golint to stop yelling at us about the +// underscores in the function names. We want the function names to match +// actually-generated code, so it feels like fair play. It's just a shame we +// lose golint for the entire file. +// +// This file is not actually generated. You can edit it. Ignore this next line. +// Code generated by hand ignore this next bit DO NOT EDIT. diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/provider.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/provider.go new file mode 100644 index 000000000000..503ba4e2b54a --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/provider.go @@ -0,0 +1,117 @@ +package toproto + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func GetProviderSchema_Request(in *tfprotov6.GetProviderSchemaRequest) (*tfplugin6.GetProviderSchema_Request, error) { + return &tfplugin6.GetProviderSchema_Request{}, nil +} + +func GetProviderSchema_Response(in *tfprotov6.GetProviderSchemaResponse) (*tfplugin6.GetProviderSchema_Response, error) { + var resp tfplugin6.GetProviderSchema_Response + if in.Provider != nil { + schema, err := Schema(in.Provider) + if err != nil { + return &resp, fmt.Errorf("error marshaling provider schema: %w", err) + } + resp.Provider = schema + } + if in.ProviderMeta != nil { + schema, err := Schema(in.ProviderMeta) + if err != nil { + return &resp, fmt.Errorf("error marshaling provider_meta schema: %w", err) + } + resp.ProviderMeta = schema + } + resp.ResourceSchemas = make(map[string]*tfplugin6.Schema, len(in.ResourceSchemas)) + for k, v := range in.ResourceSchemas { + if v == nil { + resp.ResourceSchemas[k] = nil + continue + } + schema, err := Schema(v) + if err != nil { + return &resp, fmt.Errorf("error marshaling resource schema for %q: %w", k, err) + } + resp.ResourceSchemas[k] = schema + } + resp.DataSourceSchemas = make(map[string]*tfplugin6.Schema, len(in.DataSourceSchemas)) + for k, v := range in.DataSourceSchemas { + if v == nil { + resp.DataSourceSchemas[k] = nil + continue + } + schema, err := Schema(v) + if err != nil { + return &resp, fmt.Errorf("error marshaling data source schema for %q: %w", k, err) + } + resp.DataSourceSchemas[k] = schema + } + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return &resp, err + } + resp.Diagnostics = diags + return &resp, nil +} + +func ValidateProviderConfig_Request(in *tfprotov6.ValidateProviderConfigRequest) (*tfplugin6.ValidateProviderConfig_Request, error) { + resp := &tfplugin6.ValidateProviderConfig_Request{} + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + return resp, nil +} + +func ValidateProviderConfig_Response(in *tfprotov6.ValidateProviderConfigResponse) (*tfplugin6.ValidateProviderConfig_Response, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + resp := &tfplugin6.ValidateProviderConfig_Response{ + Diagnostics: diags, + } + return resp, nil +} + +func Configure_Request(in *tfprotov6.ConfigureProviderRequest) (*tfplugin6.ConfigureProvider_Request, error) { + resp := &tfplugin6.ConfigureProvider_Request{ + TerraformVersion: in.TerraformVersion, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + return resp, nil +} + +func Configure_Response(in *tfprotov6.ConfigureProviderResponse) (*tfplugin6.ConfigureProvider_Response, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + return &tfplugin6.ConfigureProvider_Response{ + Diagnostics: diags, + }, nil +} + +func Stop_Request(in *tfprotov6.StopProviderRequest) (*tfplugin6.StopProvider_Request, error) { + return &tfplugin6.StopProvider_Request{}, nil +} + +func Stop_Response(in *tfprotov6.StopProviderResponse) (*tfplugin6.StopProvider_Response, error) { + return &tfplugin6.StopProvider_Response{ + Error: in.Error, + }, nil +} + +// we have to say this next thing to get golint to stop yelling at us about the +// underscores in the function names. We want the function names to match +// actually-generated code, so it feels like fair play. It's just a shame we +// lose golint for the entire file. +// +// This file is not actually generated. You can edit it. Ignore this next line. +// Code generated by hand ignore this next bit DO NOT EDIT. diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/resource.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/resource.go new file mode 100644 index 000000000000..e86988849a58 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/resource.go @@ -0,0 +1,212 @@ +package toproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func ValidateResourceConfig_Request(in *tfprotov6.ValidateResourceConfigRequest) (*tfplugin6.ValidateResourceConfig_Request, error) { + resp := &tfplugin6.ValidateResourceConfig_Request{ + TypeName: in.TypeName, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + return resp, nil +} + +func ValidateResourceConfig_Response(in *tfprotov6.ValidateResourceConfigResponse) (*tfplugin6.ValidateResourceConfig_Response, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + return &tfplugin6.ValidateResourceConfig_Response{ + Diagnostics: diags, + }, nil +} + +func UpgradeResourceState_Request(in *tfprotov6.UpgradeResourceStateRequest) (*tfplugin6.UpgradeResourceState_Request, error) { + resp := &tfplugin6.UpgradeResourceState_Request{ + TypeName: in.TypeName, + Version: in.Version, + } + if in.RawState != nil { + resp.RawState = RawState(in.RawState) + } + return resp, nil +} + +func UpgradeResourceState_Response(in *tfprotov6.UpgradeResourceStateResponse) (*tfplugin6.UpgradeResourceState_Response, error) { + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + resp := &tfplugin6.UpgradeResourceState_Response{ + Diagnostics: diags, + } + if in.UpgradedState != nil { + resp.UpgradedState = DynamicValue(in.UpgradedState) + } + return resp, nil +} + +func ReadResource_Request(in *tfprotov6.ReadResourceRequest) (*tfplugin6.ReadResource_Request, error) { + resp := &tfplugin6.ReadResource_Request{ + TypeName: in.TypeName, + Private: in.Private, + } + if in.CurrentState != nil { + resp.CurrentState = DynamicValue(in.CurrentState) + } + if in.ProviderMeta != nil { + resp.ProviderMeta = DynamicValue(in.ProviderMeta) + } + return resp, nil +} + +func ReadResource_Response(in *tfprotov6.ReadResourceResponse) (*tfplugin6.ReadResource_Response, error) { + resp := &tfplugin6.ReadResource_Response{ + Private: in.Private, + } + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return resp, err + } + resp.Diagnostics = diags + if in.NewState != nil { + resp.NewState = DynamicValue(in.NewState) + } + return resp, nil +} + +func PlanResourceChange_Request(in *tfprotov6.PlanResourceChangeRequest) (*tfplugin6.PlanResourceChange_Request, error) { + resp := &tfplugin6.PlanResourceChange_Request{ + TypeName: in.TypeName, + PriorPrivate: in.PriorPrivate, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + if in.PriorState != nil { + resp.PriorState = DynamicValue(in.PriorState) + } + if in.ProposedNewState != nil { + resp.ProposedNewState = DynamicValue(in.ProposedNewState) + } + if in.ProviderMeta != nil { + resp.ProviderMeta = DynamicValue(in.ProviderMeta) + } + return resp, nil +} + +func PlanResourceChange_Response(in *tfprotov6.PlanResourceChangeResponse) (*tfplugin6.PlanResourceChange_Response, error) { + resp := &tfplugin6.PlanResourceChange_Response{ + PlannedPrivate: in.PlannedPrivate, + } + requiresReplace, err := AttributePaths(in.RequiresReplace) + if err != nil { + return resp, err + } + resp.RequiresReplace = requiresReplace + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return resp, err + } + resp.Diagnostics = diags + if in.PlannedState != nil { + resp.PlannedState = DynamicValue(in.PlannedState) + } + return resp, nil +} + +func ApplyResourceChange_Request(in *tfprotov6.ApplyResourceChangeRequest) (*tfplugin6.ApplyResourceChange_Request, error) { + resp := &tfplugin6.ApplyResourceChange_Request{ + TypeName: in.TypeName, + PlannedPrivate: in.PlannedPrivate, + } + if in.Config != nil { + resp.Config = DynamicValue(in.Config) + } + if in.PriorState != nil { + resp.PriorState = DynamicValue(in.PriorState) + } + if in.PlannedState != nil { + resp.PlannedState = DynamicValue(in.PlannedState) + } + if in.ProviderMeta != nil { + resp.ProviderMeta = DynamicValue(in.ProviderMeta) + } + return resp, nil +} + +func ApplyResourceChange_Response(in *tfprotov6.ApplyResourceChangeResponse) (*tfplugin6.ApplyResourceChange_Response, error) { + resp := &tfplugin6.ApplyResourceChange_Response{ + Private: in.Private, + } + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return resp, err + } + resp.Diagnostics = diags + if in.NewState != nil { + resp.NewState = DynamicValue(in.NewState) + } + return resp, nil +} + +func ImportResourceState_Request(in *tfprotov6.ImportResourceStateRequest) (*tfplugin6.ImportResourceState_Request, error) { + return &tfplugin6.ImportResourceState_Request{ + TypeName: in.TypeName, + Id: in.ID, + }, nil +} + +func ImportResourceState_Response(in *tfprotov6.ImportResourceStateResponse) (*tfplugin6.ImportResourceState_Response, error) { + importedResources, err := ImportResourceState_ImportedResources(in.ImportedResources) + if err != nil { + return nil, err + } + diags, err := Diagnostics(in.Diagnostics) + if err != nil { + return nil, err + } + return &tfplugin6.ImportResourceState_Response{ + ImportedResources: importedResources, + Diagnostics: diags, + }, nil +} + +func ImportResourceState_ImportedResource(in *tfprotov6.ImportedResource) (*tfplugin6.ImportResourceState_ImportedResource, error) { + resp := &tfplugin6.ImportResourceState_ImportedResource{ + TypeName: in.TypeName, + Private: in.Private, + } + if in.State != nil { + resp.State = DynamicValue(in.State) + } + return resp, nil +} + +func ImportResourceState_ImportedResources(in []*tfprotov6.ImportedResource) ([]*tfplugin6.ImportResourceState_ImportedResource, error) { + resp := make([]*tfplugin6.ImportResourceState_ImportedResource, 0, len(in)) + for _, i := range in { + if i == nil { + resp = append(resp, nil) + continue + } + r, err := ImportResourceState_ImportedResource(i) + if err != nil { + return resp, err + } + resp = append(resp, r) + } + return resp, nil +} + +// we have to say this next thing to get golint to stop yelling at us about the +// underscores in the function names. We want the function names to match +// actually-generated code, so it feels like fair play. It's just a shame we +// lose golint for the entire file. +// +// This file is not actually generated. You can edit it. Ignore this next line. +// Code generated by hand ignore this next bit DO NOT EDIT. diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/schema.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/schema.go new file mode 100644 index 000000000000..f9f721a15e35 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/schema.go @@ -0,0 +1,149 @@ +package toproto + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func Schema(in *tfprotov6.Schema) (*tfplugin6.Schema, error) { + var resp tfplugin6.Schema + resp.Version = in.Version + if in.Block != nil { + block, err := Schema_Block(in.Block) + if err != nil { + return &resp, fmt.Errorf("error marshalling block: %w", err) + } + resp.Block = block + } + return &resp, nil +} + +func Schema_Block(in *tfprotov6.SchemaBlock) (*tfplugin6.Schema_Block, error) { + resp := &tfplugin6.Schema_Block{ + Version: in.Version, + Description: in.Description, + DescriptionKind: StringKind(in.DescriptionKind), + Deprecated: in.Deprecated, + } + attrs, err := Schema_Attributes(in.Attributes) + if err != nil { + return resp, err + } + resp.Attributes = attrs + blocks, err := Schema_NestedBlocks(in.BlockTypes) + if err != nil { + return resp, err + } + resp.BlockTypes = blocks + return resp, nil +} + +func Schema_Attribute(in *tfprotov6.SchemaAttribute) (*tfplugin6.Schema_Attribute, error) { + resp := &tfplugin6.Schema_Attribute{ + Name: in.Name, + Description: in.Description, + Required: in.Required, + Optional: in.Optional, + Computed: in.Computed, + Sensitive: in.Sensitive, + DescriptionKind: StringKind(in.DescriptionKind), + Deprecated: in.Deprecated, + } + if in.Type != nil { + t, err := CtyType(in.Type) + if err != nil { + return resp, fmt.Errorf("error marshaling type to JSON: %w", err) + } + resp.Type = t + } + if in.NestedType != nil { + nb, err := Schema_Object(in.NestedType) + if err != nil { + return resp, err + } + resp.NestedType = nb + } + return resp, nil +} + +func Schema_Attributes(in []*tfprotov6.SchemaAttribute) ([]*tfplugin6.Schema_Attribute, error) { + resp := make([]*tfplugin6.Schema_Attribute, 0, len(in)) + for _, a := range in { + if a == nil { + resp = append(resp, nil) + continue + } + attr, err := Schema_Attribute(a) + if err != nil { + return nil, err + } + resp = append(resp, attr) + } + return resp, nil +} + +func Schema_NestedBlock(in *tfprotov6.SchemaNestedBlock) (*tfplugin6.Schema_NestedBlock, error) { + resp := &tfplugin6.Schema_NestedBlock{ + TypeName: in.TypeName, + Nesting: Schema_NestedBlock_NestingMode(in.Nesting), + MinItems: in.MinItems, + MaxItems: in.MaxItems, + } + if in.Block != nil { + block, err := Schema_Block(in.Block) + if err != nil { + return resp, fmt.Errorf("error marshaling nested block: %w", err) + } + resp.Block = block + } + return resp, nil +} + +func Schema_NestedBlocks(in []*tfprotov6.SchemaNestedBlock) ([]*tfplugin6.Schema_NestedBlock, error) { + resp := make([]*tfplugin6.Schema_NestedBlock, 0, len(in)) + for _, b := range in { + if b == nil { + resp = append(resp, nil) + continue + } + block, err := Schema_NestedBlock(b) + if err != nil { + return nil, err + } + resp = append(resp, block) + } + return resp, nil +} + +func Schema_NestedBlock_NestingMode(in tfprotov6.SchemaNestedBlockNestingMode) tfplugin6.Schema_NestedBlock_NestingMode { + return tfplugin6.Schema_NestedBlock_NestingMode(in) +} + +func Schema_Object_NestingMode(in tfprotov6.SchemaObjectNestingMode) tfplugin6.Schema_Object_NestingMode { + return tfplugin6.Schema_Object_NestingMode(in) +} + +func Schema_Object(in *tfprotov6.SchemaObject) (*tfplugin6.Schema_Object, error) { + resp := &tfplugin6.Schema_Object{ + Nesting: Schema_Object_NestingMode(in.Nesting), + MinItems: in.MinItems, + MaxItems: in.MaxItems, + } + attrs, err := Schema_Attributes(in.Attributes) + if err != nil { + return nil, err + } + resp.Attributes = attrs + + return resp, nil +} + +// we have to say this next thing to get golint to stop yelling at us about the +// underscores in the function names. We want the function names to match +// actually-generated code, so it feels like fair play. It's just a shame we +// lose golint for the entire file. +// +// This file is not actually generated. You can edit it. Ignore this next line. +// Code generated by hand ignore this next bit DO NOT EDIT. diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/state.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/state.go new file mode 100644 index 000000000000..b6a69fcc4f2c --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/state.go @@ -0,0 +1,21 @@ +package toproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func RawState(in *tfprotov6.RawState) *tfplugin6.RawState { + return &tfplugin6.RawState{ + Json: in.JSON, + Flatmap: in.Flatmap, + } +} + +// we have to say this next thing to get golint to stop yelling at us about the +// underscores in the function names. We want the function names to match +// actually-generated code, so it feels like fair play. It's just a shame we +// lose golint for the entire file. +// +// This file is not actually generated. You can edit it. Ignore this next line. +// Code generated by hand ignore this next bit DO NOT EDIT. diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/string_kind.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/string_kind.go new file mode 100644 index 000000000000..10f1727e0aa6 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto/string_kind.go @@ -0,0 +1,18 @@ +package toproto + +import ( + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" +) + +func StringKind(in tfprotov6.StringKind) tfplugin6.StringKind { + return tfplugin6.StringKind(in) +} + +// we have to say this next thing to get golint to stop yelling at us about the +// underscores in the function names. We want the function names to match +// actually-generated code, so it feels like fair play. It's just a shame we +// lose golint for the entire file. +// +// This file is not actually generated. You can edit it. Ignore this next line. +// Code generated by hand ignore this next bit DO NOT EDIT. diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/provider.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/provider.go new file mode 100644 index 000000000000..f2b8b3add974 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/provider.go @@ -0,0 +1,181 @@ +package tfprotov6 + +import ( + "context" +) + +// ProviderServer is an interface that reflects that Terraform protocol. +// Providers must implement this interface. +type ProviderServer interface { + // GetProviderSchema is called when Terraform needs to know what the + // provider's schema is, along with the schemas of all its resources + // and data sources. + GetProviderSchema(context.Context, *GetProviderSchemaRequest) (*GetProviderSchemaResponse, error) + + // ValidateProviderConfig is called to give a provider a chance to + // validate the configuration the user specified. + ValidateProviderConfig(context.Context, *ValidateProviderConfigRequest) (*ValidateProviderConfigResponse, error) + + // ConfigureProvider is called to pass the user-specified provider + // configuration to the provider. + ConfigureProvider(context.Context, *ConfigureProviderRequest) (*ConfigureProviderResponse, error) + + // StopProvider is called when Terraform would like providers to shut + // down as quickly as possible, and usually represents an interrupt. + StopProvider(context.Context, *StopProviderRequest) (*StopProviderResponse, error) + + // ResourceServer is an interface encapsulating all the + // resource-related RPC requests. ProviderServer implementations must + // implement them, but they are a handy interface for defining what a + // resource is to terraform-plugin-go, so they're their own interface + // that is composed into ProviderServer. + ResourceServer + + // DataSourceServer is an interface encapsulating all the data + // source-related RPC requests. ProviderServer implementations must + // implement them, but they are a handy interface for defining what a + // data source is to terraform-plugin-go, so they're their own + // interface that is composed into ProviderServer. + DataSourceServer +} + +// GetProviderSchemaRequest represents a Terraform RPC request for the +// provider's schemas. +type GetProviderSchemaRequest struct{} + +// GetProviderSchemaResponse represents a Terraform RPC response containing the +// provider's schemas. +type GetProviderSchemaResponse struct { + // Provider defines the schema for the provider configuration, which + // will be specified in the provider block of the user's configuration. + Provider *Schema + + // ProviderMeta defines the schema for the provider's metadta, which + // will be specified in the provider_meta blocks of the terraform block + // for a module. This is an advanced feature and its usage should be + // coordinated with the Terraform Core team by opening an issue at + // https://github.com/hashicorp/terraform/issues/new/choose. + ProviderMeta *Schema + + // ResourceSchemas is a map of resource names to the schema for the + // configuration specified in the resource. The name should be a + // resource name, and should be prefixed with your provider's shortname + // and an underscore. It should match the first label after `resource` + // in a user's configuration. + ResourceSchemas map[string]*Schema + + // DataSourceSchemas is a map of data source names to the schema for + // the configuration specified in the data source. The name should be a + // data source name, and should be prefixed with your provider's + // shortname and an underscore. It should match the first label after + // `data` in a user's configuration. + DataSourceSchemas map[string]*Schema + + // Diagnostics report errors or warnings related to returning the + // provider's schemas. Returning an empty slice indicates success, with + // no errors or warnings generated. + Diagnostics []*Diagnostic +} + +// ValidateProviderConfigRequest represents a Terraform RPC request for the +// provider to modify the provider configuration in preparation for Terraform +// validating it. +type ValidateProviderConfigRequest struct { + // Config is the configuration the user supplied for the provider. See + // the documentation on `DynamicValue` for more information about + // safely accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // The ValidateProviderConfig RPC call will be called twice; once when + // generating a plan, once when applying the plan. When called during + // plan, Config can contain unknown values if fields with unknown + // values are interpolated into it. At apply time, all fields will have + // known values. Values that are not set in the configuration will be + // null. + Config *DynamicValue +} + +// ValidateProviderConfigResponse represents a Terraform RPC response containing +// a modified provider configuration that Terraform can now validate and use. +type ValidateProviderConfigResponse struct { + // PreparedConfig should be set to the modified configuration. See the + // documentation on `DynamicValue` for information about safely + // creating the `DynamicValue`. + // + // This RPC call exists because early versions of the Terraform Plugin + // SDK allowed providers to set defaults for provider configurations in + // such a way that Terraform couldn't validate the provider config + // without retrieving the default values first. As providers using + // terraform-plugin-go directly and new frameworks built on top of it + // have no such requirement, it is safe and recommended to simply set + // PreparedConfig to the value of the PrepareProviderConfigRequest's + // Config property, indicating that no changes are needed to the + // configuration. + // + // The configuration should be represented as a tftypes.Object, with + // each attribute and nested block getting its own key and value. + // + // TODO: should we provide an implementation that does that that + // provider developers can just embed and not need to implement the + // method themselves, then? + PreparedConfig *DynamicValue + + // Diagnostics report errors or warnings related to preparing the + // provider's configuration. Returning an empty slice indicates + // success, with no errors or warnings generated. + Diagnostics []*Diagnostic +} + +// ConfigureProviderRequest represents a Terraform RPC request to supply the +// provider with information about what the user entered in the provider's +// configuration block. +type ConfigureProviderRequest struct { + // TerraformVersion is the version of Terraform executing the request. + // This is supplied for logging, analytics, and User-Agent purposes + // *only*. Providers should not try to gate provider behavior on + // Terraform versions. It will make you sad. We can't stop you from + // doing it, but we really highly recommend you do not do it. + TerraformVersion string + + // Config is the configuration the user supplied for the provider. This + // information should usually be persisted to the underlying type + // that's implementing the ProviderServer interface, for use in later + // RPC requests. See the documentation on `DynamicValue` for more + // information about safely accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // The ConfigureProvider RPC call will be called twice; once when + // generating a plan, once when applying the plan. When called during + // plan, Config can contain unknown values if fields with unknown + // values are interpolated into it. At apply time, all fields will have + // known values. Values that are not set in the configuration will be + // null. + Config *DynamicValue +} + +// ConfigureProviderResponse represents a Terraform RPC response to the +// configuration block that Terraform supplied for the provider. +type ConfigureProviderResponse struct { + // Diagnostics report errors or warnings related to the provider's + // configuration. Returning an empty slice indicates success, with no + // errors or warnings generated. + Diagnostics []*Diagnostic +} + +// StopProviderRequest represents a Terraform RPC request to interrupt a +// provider's work and terminate a provider's processes as soon as possible. +type StopProviderRequest struct{} + +// StopProviderResponse represents a Terraform RPC response surfacing an issues +// the provider encountered in terminating. +type StopProviderResponse struct { + // Error should be set to a string describing the error if the provider + // cannot currently shut down for some reason. Because this always + // represents a system error and not a user error, it is returned as a + // string, not a Diagnostic. + Error string +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/resource.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/resource.go new file mode 100644 index 000000000000..3250f195486b --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/resource.go @@ -0,0 +1,451 @@ +package tfprotov6 + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +// ResourceServer is an interface containing the methods a resource +// implementation needs to fill. +type ResourceServer interface { + // ValidateResourceConfig is called when Terraform is checking that + // a resource's configuration is valid. It is guaranteed to have types + // conforming to your schema. This is your opportunity to do custom or + // advanced validation prior to a plan being generated. + ValidateResourceConfig(context.Context, *ValidateResourceConfigRequest) (*ValidateResourceConfigResponse, error) + + // UpgradeResourceState is called when Terraform has encountered a + // resource with a state in a schema that doesn't match the schema's + // current version. It is the provider's responsibility to modify the + // state to upgrade it to the latest state schema. + UpgradeResourceState(context.Context, *UpgradeResourceStateRequest) (*UpgradeResourceStateResponse, error) + + // ReadResource is called when Terraform is refreshing a resource's + // state. + ReadResource(context.Context, *ReadResourceRequest) (*ReadResourceResponse, error) + + // PlanResourceChange is called when Terraform is attempting to + // calculate a plan for a resource. Terraform will suggest a proposed + // new state, which the provider can modify or return unmodified to + // influence Terraform's plan. + PlanResourceChange(context.Context, *PlanResourceChangeRequest) (*PlanResourceChangeResponse, error) + + // ApplyResourceChange is called when Terraform has detected a diff + // between the resource's state and the user's config, and the user has + // approved a planned change. The provider is to apply the changes + // contained in the plan, and return the resulting state. + ApplyResourceChange(context.Context, *ApplyResourceChangeRequest) (*ApplyResourceChangeResponse, error) + + // ImportResourceState is called when a user has requested Terraform + // import a resource. The provider should fetch the information + // specified by the passed ID and return it as one or more resource + // states for Terraform to assume control of. + ImportResourceState(context.Context, *ImportResourceStateRequest) (*ImportResourceStateResponse, error) +} + +// ValidateResourceConfigRequest is the request Terraform sends when it +// wants to validate a resource's configuration. +type ValidateResourceConfigRequest struct { + // TypeName is the type of resource Terraform is validating. + TypeName string + + // Config is the configuration the user supplied for that resource. See + // the documentation on `DynamicValue` for more information about + // safely accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // This configuration may contain unknown values if a user uses + // interpolation or other functionality that would prevent Terraform + // from knowing the value at request time. Any attributes not directly + // set in the configuration will be null. + Config *DynamicValue +} + +// ValidateResourceConfigResponse is the response from the provider about +// the validity of a resource's configuration. +type ValidateResourceConfigResponse struct { + // Diagnostics report errors or warnings related to the given + // configuration. Returning an empty slice indicates a successful + // validation with no warnings or errors generated. + Diagnostics []*Diagnostic +} + +// UpgradeResourceStateRequest is the request Terraform sends when it needs a +// provider to upgrade the state of a given resource. +type UpgradeResourceStateRequest struct { + // TypeName is the type of resource that Terraform needs to upgrade the + // state for. + TypeName string + + // Version is the version of the state the resource currently has. + Version int64 + + // RawState is the state as Terraform sees it right now. See the + // documentation for `RawState` for information on how to work with the + // data it contains. + RawState *RawState +} + +// UpgradeResourceStateResponse is the response from the provider containing +// the upgraded state for the given resource. +type UpgradeResourceStateResponse struct { + // UpgradedState is the upgraded state for the resource, represented as + // a `DynamicValue`. See the documentation on `DynamicValue` for + // information about safely creating the `DynamicValue`. + // + // The state should be represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + UpgradedState *DynamicValue + + // Diagnostics report errors or warnings related to upgrading the + // state of the requested resource. Returning an empty slice indicates + // a successful validation with no warnings or errors generated. + Diagnostics []*Diagnostic +} + +// ReadResourceRequest is the request Terraform sends when it wants to get the +// latest state for a resource. +type ReadResourceRequest struct { + // TypeName is the type of resource Terraform is requesting an upated + // state for. + TypeName string + + // CurrentState is the current state of the resource as far as + // Terraform knows, represented as a `DynamicValue`. See the + // documentation for `DynamicValue` for information about safely + // accessing the state. + // + // The state is represented as a tftypes.Object, with each attribute + // and nested block getting its own key and value. + CurrentState *DynamicValue + + // Private is any provider-defined private state stored with the + // resource. It is used for keeping state with the resource that is not + // meant to be included when calculating diffs. + Private []byte + + // ProviderMeta supplies the provider metadata configuration for the + // module this resource is in. Module-specific provider metadata is an + // advanced feature and usage of it should be coordinated with the + // Terraform Core team by raising an issue at + // https://github.com/hashicorp/terraform/issues/new/choose. See the + // documentation on `DynamicValue` for information about safely + // accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // This configuration will have known values for all fields. + ProviderMeta *DynamicValue +} + +// ReadResourceResponse is the response from the provider about the current +// state of the requested resource. +type ReadResourceResponse struct { + // NewState is the current state of the resource according to the + // provider, represented as a `DynamicValue`. See the documentation for + // `DynamicValue` for information about safely creating the + // `DynamicValue`. + // + // The state should be represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + NewState *DynamicValue + + // Diagnostics report errors or warnings related to retrieving the + // current state of the requested resource. Returning an empty slice + // indicates a successful validation with no warnings or errors + // generated. + Diagnostics []*Diagnostic + + // Private should be set to any state that the provider would like sent + // with requests for this resource. This state will be associated with + // the resource, but will not be considered when calculating diffs. + Private []byte +} + +// PlanResourceChangeRequest is the request Terraform sends when it is +// generating a plan for a resource and wants the provider's input on what the +// planned state should be. +type PlanResourceChangeRequest struct { + // TypeName is the type of resource Terraform is generating a plan for. + TypeName string + + // PriorState is the state of the resource before the plan is applied, + // represented as a `DynamicValue`. See the documentation for + // `DynamicValue` for information about safely accessing the state. + // + // The state is represented as a tftypes.Object, with each attribute + // and nested block getting its own key and value. + PriorState *DynamicValue + + // ProposedNewState is the state that Terraform is proposing for the + // resource, with the changes in the configuration applied, represented + // as a `DynamicValue`. See the documentation for `DynamicValue` for + // information about safely accessing the state. + // + // The ProposedNewState merges any non-null values in the configuration + // with any computed attributes in PriorState as a utility to help + // providers avoid needing to implement such merging functionality + // themselves. + // + // The state is represented as a tftypes.Object, with each attribute + // and nested block getting its own key and value. + // + // The ProposedNewState will be null when planning a delete operation. + ProposedNewState *DynamicValue + + // Config is the configuration the user supplied for the resource. See + // the documentation on `DynamicValue` for more information about + // safely accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // This configuration may contain unknown values if a user uses + // interpolation or other functionality that would prevent Terraform + // from knowing the value at request time. + Config *DynamicValue + + // PriorPrivate is any provider-defined private state stored with the + // resource. It is used for keeping state with the resource that is not + // meant to be included when calculating diffs. + PriorPrivate []byte + + // ProviderMeta supplies the provider metadata configuration for the + // module this resource is in. Module-specific provider metadata is an + // advanced feature and usage of it should be coordinated with the + // Terraform Core team by raising an issue at + // https://github.com/hashicorp/terraform/issues/new/choose. See the + // documentation on `DynamicValue` for information about safely + // accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // This configuration will have known values for all fields. + ProviderMeta *DynamicValue +} + +// PlanResourceChangeResponse is the response from the provider about what the +// planned state for a given resource should be. +type PlanResourceChangeResponse struct { + // PlannedState is the provider's indication of what the state for the + // resource should be after apply, represented as a `DynamicValue`. See + // the documentation for `DynamicValue` for information about safely + // creating the `DynamicValue`. + // + // This is usually derived from the ProposedNewState passed in the + // PlanResourceChangeRequest, with default values substituted for any + // null values and overriding any computed values that are expected to + // change as a result of the apply operation. This may contain unknown + // values if the value could change but its new value won't be known + // until apply time. + // + // Any value that was non-null in the configuration must either + // preserve the exact configuration value or return the corresponding + // value from the prior state. The value from the prior state should be + // returned when the configuration value is semantically equivalent to + // the state value. + // + // Any value that is marked as computed in the schema and is null in + // the configuration may be set by the provider to any value of the + // expected type. + // + // PlanResourceChange will actually be called twice; once when + // generating the plan for the user to approve, once during the apply. + // During the apply, additional values from the configuration--upstream + // values interpolated in that were computed at apply time--will be + // populated. During this second call, any attribute that had a known + // value in the first PlannedState must have an identical value in the + // second PlannedState. Any unknown values may remain unknown or may + // take on any value of the appropriate type. This means the values + // returned in PlannedState should be deterministic and unknown values + // should be used if a field's value may change depending on what value + // ends up filling an unknown value in the config. + // + // The state should be represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + PlannedState *DynamicValue + + // RequiresReplace is a list of tftypes.AttributePaths that require the + // resource to be replaced. They should point to the specific field + // that changed that requires the resource to be destroyed and + // recreated. + RequiresReplace []*tftypes.AttributePath + + // PlannedPrivate should be set to any state that the provider would + // like sent with requests for this resource. This state will be + // associated with the resource, but will not be considered when + // calculating diffs. + PlannedPrivate []byte + + // Diagnostics report errors or warnings related to determining the + // planned state of the requested resource. Returning an empty slice + // indicates a successful validation with no warnings or errors + // generated. + Diagnostics []*Diagnostic + + // UnsafeToUseLegacyTypeSystem should only be set by + // hashicorp/terraform-plugin-sdk. It modifies Terraform's behavior to + // work with the legacy expectations of that SDK. + // + // Nobody else should use this. Ever. For any reason. Just don't do it. + // + // We have to expose it here for terraform-plugin-sdk to be muxable, or + // we wouldn't even be including it in this type. Don't use it. It may + // go away or change behavior on you with no warning. It is + // explicitly unsupported and not part of our SemVer guarantees. + // + // Deprecated: Really, just don't use this, you don't need it. + UnsafeToUseLegacyTypeSystem bool +} + +// ApplyResourceChangeRequest is the request Terraform sends when it needs to +// apply a planned set of changes to a resource. +type ApplyResourceChangeRequest struct { + // TypeName is the type of resource Terraform wants to change. + TypeName string + + // PriorState is the state of the resource before the changes are + // applied, represented as a `DynamicValue`. See the documentation for + // `DynamicValue` for information about safely accessing the state. + // + // The state is represented as a tftypes.Object, with each attribute + // and nested block getting its own key and value. + PriorState *DynamicValue + + // PlannedState is Terraform's plan for what the state should look like + // after the changes are applied, represented as a `DynamicValue`. See + // the documentation for `DynamicValue` for information about safely + // accessing the state. + // + // This is the PlannedState returned during PlanResourceChange. + // + // The state is represented as a tftypes.Object, with each attribute + // and nested block getting its own key and value. + PlannedState *DynamicValue + + // Config is the configuration the user supplied for the resource. See + // the documentation on `DynamicValue` for more information about + // safely accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // This configuration may contain unknown values. + Config *DynamicValue + + // PlannedPrivate is any provider-defined private state stored with the + // resource. It is used for keeping state with the resource that is not + // meant to be included when calculating diffs. + PlannedPrivate []byte + + // ProviderMeta supplies the provider metadata configuration for the + // module this resource is in. Module-specific provider metadata is an + // advanced feature and usage of it should be coordinated with the + // Terraform Core team by raising an issue at + // https://github.com/hashicorp/terraform/issues/new/choose. See the + // documentation on `DynamicValue` for information about safely + // accessing the configuration. + // + // The configuration is represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + // + // This configuration will have known values for all fields. + ProviderMeta *DynamicValue +} + +// ApplyResourceChangeResponse is the response from the provider about what the +// state of a resource is after planned changes have been applied. +type ApplyResourceChangeResponse struct { + // NewState is the provider's understanding of what the resource's + // state is after changes are applied, represented as a `DynamicValue`. + // See the documentation for `DynamicValue` for information about + // safely creating the `DynamicValue`. + // + // Any attribute, whether computed or not, that has a known value in + // the PlannedState in the ApplyResourceChangeRequest must be preserved + // exactly as it was in NewState. + // + // Any attribute in the PlannedState in the ApplyResourceChangeRequest + // that is unknown must take on a known value at this time. No unknown + // values are allowed in the NewState. + // + // The state should be represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + NewState *DynamicValue + + // Private should be set to any state that the provider would like sent + // with requests for this resource. This state will be associated with + // the resource, but will not be considered when calculating diffs. + Private []byte + + // Diagnostics report errors or warnings related to applying changes to + // the requested resource. Returning an empty slice indicates a + // successful validation with no warnings or errors generated. + Diagnostics []*Diagnostic + + // UnsafeToUseLegacyTypeSystem should only be set by + // hashicorp/terraform-plugin-sdk. It modifies Terraform's behavior to + // work with the legacy expectations of that SDK. + // + // Nobody else should use this. Ever. For any reason. Just don't do it. + // + // We have to expose it here for terraform-plugin-sdk to be muxable, or + // we wouldn't even be including it in this type. Don't use it. It may + // go away or change behavior on you with no warning. It is + // explicitly unsupported and not part of our SemVer guarantees. + // + // Deprecated: Really, just don't use this, you don't need it. + UnsafeToUseLegacyTypeSystem bool +} + +// ImportResourceStateRequest is the request Terraform sends when it wants a +// provider to import one or more resources specified by an ID. +type ImportResourceStateRequest struct { + // TypeName is the type of resource Terraform wants to import. + TypeName string + + // ID is the user-supplied identifying information about the resource + // or resources. Providers decide and communicate to users the format + // for the ID, and use it to determine what resource or resources to + // import. + ID string +} + +// ImportResourceStateResponse is the response from the provider about the +// imported resources. +type ImportResourceStateResponse struct { + // ImportedResources are the resources the provider found and was able + // to import. + ImportedResources []*ImportedResource + + // Diagnostics report errors or warnings related to importing the + // requested resource or resources. Returning an empty slice indicates + // a successful validation with no warnings or errors generated. + Diagnostics []*Diagnostic +} + +// ImportedResource represents a single resource that a provider has +// successfully imported into state. +type ImportedResource struct { + // TypeName is the type of resource that was imported. + TypeName string + + // State is the provider's understanding of the imported resource's + // state, represented as a `DynamicValue`. See the documentation for + // `DynamicValue` for information about safely creating the + // `DynamicValue`. + // + // The state should be represented as a tftypes.Object, with each + // attribute and nested block getting its own key and value. + State *DynamicValue + + // Private should be set to any state that the provider would like sent + // with requests for this resource. This state will be associated with + // the resource, but will not be considered when calculating diffs. + Private []byte +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/schema.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/schema.go new file mode 100644 index 000000000000..17ead5b71e12 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/schema.go @@ -0,0 +1,293 @@ +package tfprotov6 + +import "github.com/hashicorp/terraform-plugin-go/tftypes" + +const ( + // SchemaNestedBlockNestingModeInvalid indicates that the nesting mode + // for a nested block in the schema is invalid. This generally + // indicates a nested block that was created incorrectly. + SchemaNestedBlockNestingModeInvalid SchemaNestedBlockNestingMode = 0 + + // SchemaNestedBlockNestingModeSingle indicates that the nested block + // should be treated as a single block with no labels, and there should + // not be more than one of these blocks in the containing block. The + // block will appear in config and state values as a tftypes.Object. + SchemaNestedBlockNestingModeSingle SchemaNestedBlockNestingMode = 1 + + // SchemaNestedBlockNestingModeList indicates that multiple instances + // of the nested block should be permitted, with no labels, and that + // the instances of the block should appear in config and state values + // as a tftypes.List, with an ElementType of tftypes.Object. + SchemaNestedBlockNestingModeList SchemaNestedBlockNestingMode = 2 + + // SchemaNestedBlockNestingModeSet indicates that multiple instances + // of the nested block should be permitted, with no labels, and that + // the instances of the block should appear in config and state values + // as a tftypes.Set, with an ElementType of tftypes.Object. + SchemaNestedBlockNestingModeSet SchemaNestedBlockNestingMode = 3 + + // SchemaNestedBlockNestingModeMap indicates that multiple instances of + // the nested block should be permitted, each with a single label, and + // that they should be represented in state and config values as a + // tftypes.Map, with an AttributeType of tftypes.Object. The labels on + // the blocks will be used as the map keys. It is an error, therefore, + // to use the same label value on multiple block instances. + SchemaNestedBlockNestingModeMap SchemaNestedBlockNestingMode = 4 + + // SchemaNestedBlockNestingModeGroup indicates that the nested block + // should be treated as a single block with no labels, and there should + // not be more than one of these blocks in the containing block. The + // block will appear in config and state values as a tftypes.Object. + // + // SchemaNestedBlockNestingModeGroup is distinct from + // SchemaNestedBlockNestingModeSingle in that it guarantees that the + // block will never be null. If it is omitted from a config, the block + // will still be set, but its attributes and nested blocks will all be + // null. This is an exception to the rule that any block not set in the + // configuration cannot be set in config by the provider; this ensures + // the block is always considered "set" in the configuration, and is + // therefore settable in state by the provider. + SchemaNestedBlockNestingModeGroup SchemaNestedBlockNestingMode = 5 + + // SchemaObjectNestingModeInvalid indicates that the nesting mode + // for a nested type in the schema is invalid. This generally + // indicates a nested type that was created incorrectly. + SchemaObjectNestingModeInvalid SchemaObjectNestingMode = 0 + + // SchemaObjectNestingModeSingle indicates that the nested type should + // be treated as a single object. The block will appear in config and state + // values as a tftypes.Object. + SchemaObjectNestingModeSingle SchemaObjectNestingMode = 1 + + // SchemaObjectNestingModeList indicates that multiple instances of the + // nested type should be permitted, and that the nested type should appear + // in config and state values as a tftypes.List, with an ElementType of + // tftypes.Object. + SchemaObjectNestingModeList SchemaObjectNestingMode = 2 + + // SchemaObjectNestingModeSet indicates that multiple instances of the + // nested type should be permitted, and that the nested type should appear in + // config and state values as a tftypes.Set, with an ElementType of + // tftypes.Object. + SchemaObjectNestingModeSet SchemaObjectNestingMode = 3 + + // SchemaObjectNestingModeMap indicates that multiple instances of the + // nested type should be permitted, and that they should be appear in state + // and config values as a tftypes.Map, with an AttributeType of + // tftypes.Object. + SchemaObjectNestingModeMap SchemaObjectNestingMode = 4 +) + +// Schema is how Terraform defines the shape of data. It can be thought of as +// the type information for resources, data sources, provider configuration, +// and all the other data that Terraform sends to providers. It is how +// providers express their requirements for that data. +type Schema struct { + // Version indicates which version of the schema this is. Versions + // should be monotonically incrementing numbers. When Terraform + // encounters a resource stored in state with a schema version lower + // that the schema version the provider advertises for that resource, + // Terraform requests the provider upgrade the resource's state. + Version int64 + + // Block is the root level of the schema, the collection of attributes + // and blocks that make up a resource, data source, provider, or other + // configuration block. + Block *SchemaBlock +} + +// SchemaBlock represents a block in a schema. Blocks are how Terraform creates +// groupings of attributes. In configurations, they don't use the equals sign +// and use dynamic instead of list comprehensions. +// +// Blocks will show up in state and config Values as a tftypes.Object, with the +// attributes and nested blocks defining the tftypes.Object's AttributeTypes. +type SchemaBlock struct { + // TODO: why do we have version in the block, too? + Version int64 + + // Attributes are the attributes defined within the block. These are + // the fields that users can set using the equals sign or reference in + // interpolations. + Attributes []*SchemaAttribute + + // BlockTypes are the nested blocks within the block. These are used to + // have blocks within blocks. + BlockTypes []*SchemaNestedBlock + + // Description offers an end-user friendly description of what the + // block is for. This will be surfaced to users through editor + // integrations, documentation generation, and other settings. + Description string + + // DescriptionKind indicates the formatting and encoding that the + // Description field is using. + DescriptionKind StringKind + + // Deprecated, when set to true, indicates that a block should no + // longer be used and users should migrate away from it. At the moment + // it is unused and will have no impact, but it will be used in future + // tooling that is powered by provider schemas to enable richer user + // experiences. Providers should set it when deprecating blocks in + // preparation for these tools. + Deprecated bool +} + +// SchemaAttribute represents a single attribute within a schema block. +// Attributes are the fields users can set in configuration using the equals +// sign, can assign to variables, can interpolate, and can use list +// comprehensions on. +type SchemaAttribute struct { + // Name is the name of the attribute. This is what the user will put + // before the equals sign to assign a value to this attribute. + Name string + + // Type indicates the type of data the attribute expects. See the + // documentation for the tftypes package for information on what types + // are supported and their behaviors. + Type tftypes.Type + + // NestedType indicates that this is a NestedBlock-style object masquerading + // as an attribute. This field conflicts with Type. + NestedType *SchemaObject + + // Description offers an end-user friendly description of what the + // attribute is for. This will be surfaced to users through editor + // integrations, documentation generation, and other settings. + Description string + + // Required, when set to true, indicates that this attribute must have + // a value assigned to it by the user or Terraform will throw an error. + Required bool + + // Optional, when set to true, indicates that the user does not need to + // supply a value for this attribute, but may. + Optional bool + + // Computed, when set to true, indicates the the provider will supply a + // value for this field. If Optional and Required are false and + // Computed is true, the user will not be able to specify a value for + // this field without Terraform throwing an error. If Optional is true + // and Computed is true, the user can specify a value for this field, + // but the provider may supply a value if the user does not. It is + // always a violation of Terraform's protocol to substitute a value for + // what the user entered, even if Computed is true. + Computed bool + + // Sensitive, when set to true, indicates that the contents of this + // attribute should be considered sensitive and not included in output. + // This does not encrypt or otherwise protect these values in state, it + // only offers protection from them showing up in plans or other + // output. + Sensitive bool + + // DescriptionKind indicates the formatting and encoding that the + // Description field is using. + DescriptionKind StringKind + + // Deprecated, when set to true, indicates that a attribute should no + // longer be used and users should migrate away from it. At the moment + // it is unused and will have no impact, but it will be used in future + // tooling that is powered by provider schemas to enable richer user + // experiences. Providers should set it when deprecating attributes in + // preparation for these tools. + Deprecated bool +} + +// SchemaNestedBlock is a nested block within another block. See SchemaBlock +// for more information on blocks. +type SchemaNestedBlock struct { + // TypeName is the name of the block. It is what the user will specify + // when using the block in configuration. + TypeName string + + // Block is the block being nested inside another block. See the + // SchemaBlock documentation for more information on blocks. + Block *SchemaBlock + + // Nesting is the kind of nesting the block is using. Different nesting + // modes have different behaviors and imply different kinds of data. + Nesting SchemaNestedBlockNestingMode + + // MinItems is the minimum number of instances of this block that a + // user must specify or Terraform will return an error. + // + // MinItems can only be set for SchemaNestedBlockNestingModeList and + // SchemaNestedBlockNestingModeSet. SchemaNestedBlockNestingModeSingle + // can also set MinItems and MaxItems both to 1 to indicate that the + // block is required to be set. All other SchemaNestedBlockNestingModes + // must leave MinItems set to 0. + MinItems int64 + + // MaxItems is the maximum number of instances of this block that a + // user may specify before Terraform returns an error. + // + // MaxItems can only be set for SchemaNestedBlockNestingModeList and + // SchemaNestedBlockNestingModeSet. SchemaNestedBlockNestingModeSingle + // can also set MinItems and MaxItems both to 1 to indicate that the + // block is required to be set. All other SchemaNestedBlockNestingModes + // must leave MaxItems set to 0. + MaxItems int64 +} + +// SchemaNestedBlockNestingMode indicates the nesting mode for +// SchemaNestedBlocks. The nesting mode determines the number of instances of +// the block allowed, how many labels the block expects, and the data structure +// used for the block in config and state values. +type SchemaNestedBlockNestingMode int32 + +func (s SchemaNestedBlockNestingMode) String() string { + switch s { + case 0: + return "INVALID" + case 1: + return "SINGLE" + case 2: + return "LIST" + case 3: + return "SET" + case 4: + return "MAP" + case 5: + return "GROUP" + } + return "UNKNOWN" +} + +// SchemaObject represents a nested-block-stype object in an Attribute. +type SchemaObject struct { + // Attributes are the attributes defined within the Object. + Attributes []*SchemaAttribute + + Nesting SchemaObjectNestingMode + + // MinItems is the minimum number of instances of this type that a + // user must specify or Terraform will return an error. + MinItems int64 + + // MaxItems is the maximum number of instances of this type that a + // user may specify before Terraform returns an error. + MaxItems int64 +} + +// SchemaObjectNestingMode indicates the nesting mode for +// SchemaNestedBlocks. The nesting mode determines the number of instances of +// the nested type allowed and the data structure used for the block in config +// and state values. +type SchemaObjectNestingMode int32 + +func (s SchemaObjectNestingMode) String() string { + switch s { + case 0: + return "INVALID" + case 1: + return "SINGLE" + case 2: + return "LIST" + case 3: + return "SET" + case 4: + return "MAP" + } + return "UNKNOWN" +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/doc.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/doc.go new file mode 100644 index 000000000000..8b5313d953b9 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/doc.go @@ -0,0 +1,6 @@ +// Package tf6server implements a server implementation to run +// tfprotov6.ProviderServers as gRPC servers. +// +// Providers will likely be calling tf6server.Serve from their main function to +// start the server so Terraform can connect to it. +package tf6server diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/plugin.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/plugin.go new file mode 100644 index 000000000000..afdb3f08da48 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/plugin.go @@ -0,0 +1,45 @@ +package tf6server + +import ( + "context" + "errors" + "net/rpc" + + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" + "google.golang.org/grpc" +) + +// GRPCProviderPlugin is an implementation of the +// github.com/hashicorp/go-plugin#Plugin and +// github.com/hashicorp/go-plugin#GRPCPlugin interfaces, indicating how to +// serve tfprotov6.ProviderServers as gRPC plugins for go-plugin. +type GRPCProviderPlugin struct { + GRPCProvider func() tfprotov6.ProviderServer +} + +// Server always returns an error; we're only implementing the GRPCPlugin +// interface, not the Plugin interface. +func (p *GRPCProviderPlugin) Server(*plugin.MuxBroker) (interface{}, error) { + return nil, errors.New("terraform-plugin-go only implements gRPC servers") +} + +// Client always returns an error; we're only implementing the GRPCPlugin +// interface, not the Plugin interface. +func (p *GRPCProviderPlugin) Client(*plugin.MuxBroker, *rpc.Client) (interface{}, error) { + return nil, errors.New("terraform-plugin-go only implements gRPC servers") +} + +// GRPCClient always returns an error; we're only implementing the server half +// of the interface. +func (p *GRPCProviderPlugin) GRPCClient(context.Context, *plugin.GRPCBroker, *grpc.ClientConn) (interface{}, error) { + return nil, errors.New("terraform-plugin-go only implements gRPC servers") +} + +// GRPCServer registers the gRPC provider server with the gRPC server that +// go-plugin is standing up. +func (p *GRPCProviderPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error { + tfplugin6.RegisterProviderServer(s, New(p.GRPCProvider())) + return nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/server.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/server.go new file mode 100644 index 000000000000..2e907f5d660d --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/server/server.go @@ -0,0 +1,357 @@ +package tf6server + +import ( + "context" + "sync" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-plugin" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6" + "github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto" +) + +// ServeOpt is an interface for defining options that can be passed to the +// Serve function. Each implementation modifies the ServeConfig being +// generated. A slice of ServeOpts then, cumulatively applied, render a full +// ServeConfig. +type ServeOpt interface { + ApplyServeOpt(*ServeConfig) error +} + +// ServeConfig contains the configured options for how a provider should be +// served. +type ServeConfig struct { + logger hclog.Logger + debugCtx context.Context + debugCh chan *plugin.ReattachConfig + debugCloseCh chan struct{} +} + +type serveConfigFunc func(*ServeConfig) error + +func (s serveConfigFunc) ApplyServeOpt(in *ServeConfig) error { + return s(in) +} + +// WithDebug returns a ServeOpt that will set the server into debug mode, using +// the passed options to populate the go-plugin ServeTestConfig. +func WithDebug(ctx context.Context, config chan *plugin.ReattachConfig, closeCh chan struct{}) ServeOpt { + return serveConfigFunc(func(in *ServeConfig) error { + in.debugCtx = ctx + in.debugCh = config + in.debugCloseCh = closeCh + return nil + }) +} + +// WithGoPluginLogger returns a ServeOpt that will set the logger that +// go-plugin should use to log messages. +func WithGoPluginLogger(logger hclog.Logger) ServeOpt { + return serveConfigFunc(func(in *ServeConfig) error { + in.logger = logger + return nil + }) +} + +// Serve starts a tfprotov6.ProviderServer serving, ready for Terraform to +// connect to it. The name passed in should be the fully qualified name that +// users will enter in the source field of the required_providers block, like +// "registry.terraform.io/hashicorp/time". +// +// Zero or more options to configure the server may also be passed. The default +// invocation is sufficient, but if the provider wants to run in debug mode or +// modify the logger that go-plugin is using, ServeOpts can be specified to +// support that. +func Serve(name string, serverFactory func() tfprotov6.ProviderServer, opts ...ServeOpt) error { + var conf ServeConfig + for _, opt := range opts { + err := opt.ApplyServeOpt(&conf) + if err != nil { + return err + } + } + serveConfig := &plugin.ServeConfig{ + HandshakeConfig: plugin.HandshakeConfig{ + ProtocolVersion: 6, + MagicCookieKey: "TF_PLUGIN_MAGIC_COOKIE", + MagicCookieValue: "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2", + }, + Plugins: plugin.PluginSet{ + "provider": &GRPCProviderPlugin{ + GRPCProvider: serverFactory, + }, + }, + GRPCServer: plugin.DefaultGRPCServer, + } + if conf.logger != nil { + serveConfig.Logger = conf.logger + } + if conf.debugCh != nil { + serveConfig.Test = &plugin.ServeTestConfig{ + Context: conf.debugCtx, + ReattachConfigCh: conf.debugCh, + CloseCh: conf.debugCloseCh, + } + } + plugin.Serve(serveConfig) + return nil +} + +type server struct { + downstream tfprotov6.ProviderServer + tfplugin6.UnimplementedProviderServer + + stopMu sync.Mutex + stopCh chan struct{} +} + +func mergeStop(ctx context.Context, cancel context.CancelFunc, stopCh chan struct{}) { + select { + case <-ctx.Done(): + return + case <-stopCh: + cancel() + } +} + +// stoppableContext returns a context that wraps `ctx` but will be canceled +// when the server's stopCh is closed. +// +// This is used to cancel all in-flight contexts when the Stop method of the +// server is called. +func (s *server) stoppableContext(ctx context.Context) context.Context { + s.stopMu.Lock() + defer s.stopMu.Unlock() + + stoppable, cancel := context.WithCancel(ctx) + go mergeStop(stoppable, cancel, s.stopCh) + return stoppable +} + +// New converts a tfprotov6.ProviderServer into a server capable of handling +// Terraform protocol requests and issuing responses using the gRPC types. +func New(serve tfprotov6.ProviderServer) tfplugin6.ProviderServer { + return &server{ + downstream: serve, + stopCh: make(chan struct{}), + } +} + +func (s *server) GetProviderSchema(ctx context.Context, req *tfplugin6.GetProviderSchema_Request) (*tfplugin6.GetProviderSchema_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.GetProviderSchemaRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.GetProviderSchema(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.GetProviderSchema_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +func (s *server) ConfigureProvider(ctx context.Context, req *tfplugin6.ConfigureProvider_Request) (*tfplugin6.ConfigureProvider_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.ConfigureProviderRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.ConfigureProvider(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.Configure_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +func (s *server) ValidateProviderConfig(ctx context.Context, req *tfplugin6.ValidateProviderConfig_Request) (*tfplugin6.ValidateProviderConfig_Response, error) { + r, err := fromproto.ValidateProviderConfigRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.ValidateProviderConfig(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.ValidateProviderConfig_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +// stop closes the stopCh associated with the server and replaces it with a new +// one. +// +// This causes all in-flight requests for the server to have their contexts +// canceled. +func (s *server) stop() { + s.stopMu.Lock() + defer s.stopMu.Unlock() + + close(s.stopCh) + s.stopCh = make(chan struct{}) +} + +func (s *server) Stop(ctx context.Context, req *tfplugin6.StopProvider_Request) (*tfplugin6.StopProvider_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.StopProviderRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.StopProvider(ctx, r) + if err != nil { + return nil, err + } + s.stop() + ret, err := toproto.Stop_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +func (s *server) ValidateDataResourceConfig(ctx context.Context, req *tfplugin6.ValidateDataResourceConfig_Request) (*tfplugin6.ValidateDataResourceConfig_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.ValidateDataResourceConfigRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.ValidateDataResourceConfig(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.ValidateDataResourceConfig_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +func (s *server) ReadDataSource(ctx context.Context, req *tfplugin6.ReadDataSource_Request) (*tfplugin6.ReadDataSource_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.ReadDataSourceRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.ReadDataSource(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.ReadDataSource_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +func (s *server) ValidateResourceConfig(ctx context.Context, req *tfplugin6.ValidateResourceConfig_Request) (*tfplugin6.ValidateResourceConfig_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.ValidateResourceConfigRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.ValidateResourceConfig(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.ValidateResourceConfig_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +func (s *server) UpgradeResourceState(ctx context.Context, req *tfplugin6.UpgradeResourceState_Request) (*tfplugin6.UpgradeResourceState_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.UpgradeResourceStateRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.UpgradeResourceState(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.UpgradeResourceState_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +func (s *server) ReadResource(ctx context.Context, req *tfplugin6.ReadResource_Request) (*tfplugin6.ReadResource_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.ReadResourceRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.ReadResource(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.ReadResource_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +func (s *server) PlanResourceChange(ctx context.Context, req *tfplugin6.PlanResourceChange_Request) (*tfplugin6.PlanResourceChange_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.PlanResourceChangeRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.PlanResourceChange(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.PlanResourceChange_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +func (s *server) ApplyResourceChange(ctx context.Context, req *tfplugin6.ApplyResourceChange_Request) (*tfplugin6.ApplyResourceChange_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.ApplyResourceChangeRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.ApplyResourceChange(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.ApplyResourceChange_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} + +func (s *server) ImportResourceState(ctx context.Context, req *tfplugin6.ImportResourceState_Request) (*tfplugin6.ImportResourceState_Response, error) { + ctx = s.stoppableContext(ctx) + r, err := fromproto.ImportResourceStateRequest(req) + if err != nil { + return nil, err + } + resp, err := s.downstream.ImportResourceState(ctx, r) + if err != nil { + return nil, err + } + ret, err := toproto.ImportResourceState_Response(resp) + if err != nil { + return nil, err + } + return ret, nil +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/state.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/state.go new file mode 100644 index 000000000000..3b5d9b11c4bc --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/state.go @@ -0,0 +1,79 @@ +package tfprotov6 + +import ( + "errors" + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +// ErrUnknownRawStateType is returned when a RawState has no Flatmap or JSON +// bytes set. This should never be returned during the normal operation of a +// provider, and indicates one of the following: +// +// 1. terraform-plugin-go is out of sync with the protocol and should be +// updated. +// +// 2. terrafrom-plugin-go has a bug. +// +// 3. The `RawState` was generated or modified by something other than +// terraform-plugin-go and is no longer a valid value. +var ErrUnknownRawStateType = errors.New("RawState had no JSON or flatmap data set") + +// RawState is the raw, undecoded state for providers to upgrade. It is +// undecoded as Terraform, for whatever reason, doesn't have the previous +// schema available to it, and so cannot decode the state itself and pushes +// that responsibility off onto providers. +// +// It is safe to assume that Flatmap can be ignored for any state written by +// Terraform 0.12.0 or higher, but it is not safe to assume that all states +// written by 0.12.0 or higher will be in JSON format; future versions may +// switch to an alternate encoding for states. +type RawState struct { + JSON []byte + Flatmap map[string]string +} + +// Unmarshal returns a `tftypes.Value` that represents the information +// contained in the RawState in an easy-to-interact-with way. It is the +// main purpose of the RawState type, and is how provider developers should +// obtain state values from the UpgradeResourceState RPC call. +// +// Pass in the type you want the `Value` to be interpreted as. Terraform's type +// system encodes in a lossy manner, meaning the type information is not +// preserved losslessly when going over the wire. Sets, lists, and tuples all +// look the same. Objects and maps all look the same, as well, as do +// user-specified values when DynamicPseudoType is used in the schema. +// Fortunately, the provider should already know the type; it should be the +// type of the schema, or DynamicPseudoType if that's what's in the schema. +// `Unmarshal` will then parse the value as though it belongs to that type, if +// possible, and return a `tftypes.Value` with the appropriate information. If +// the data can't be interpreted as that type, an error will be returned saying +// so. In these cases, double check to make sure the schema is declaring the +// same type being passed into `Unmarshal`. +// +// In the event an ErrUnknownRawStateType is returned, one of three things +// has happened: +// +// 1. terraform-plugin-go is out of date and out of sync with the protocol, and +// an issue should be opened on its repo to get it updated. +// +// 2. terraform-plugin-go has a bug somewhere, and an issue should be opened on +// its repo to get it fixed. +// +// 3. The provider or a dependency has modified the `RawState` in an +// unsupported way, or has created one from scratch, and should treat it as +// opaque and not modify it, only calling `Unmarshal` on `RawState`s received +// from RPC requests. +// +// State files written before Terraform 0.12 that haven't been upgraded yet +// cannot be unmarshaled, and must have their Flatmap property read directly. +func (s RawState) Unmarshal(typ tftypes.Type) (tftypes.Value, error) { + if s.JSON != nil { + return tftypes.ValueFromJSON(s.JSON, typ) //nolint:staticcheck + } + if s.Flatmap != nil { + return tftypes.Value{}, fmt.Errorf("flatmap states cannot be unmarshaled, only states written by Terraform 0.12 and higher can be unmarshaled") + } + return tftypes.Value{}, ErrUnknownRawStateType +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/string_kind.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/string_kind.go new file mode 100644 index 000000000000..359e036e7a31 --- /dev/null +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-go/tfprotov6/string_kind.go @@ -0,0 +1,25 @@ +package tfprotov6 + +const ( + // StringKindPlain indicates a string is plaintext, and should be + // interpreted as having no formatting information. + StringKindPlain StringKind = 0 + + // StringKindMarkdown indicates a string is markdown-formatted, and + // should be rendered using a Markdown renderer to correctly display + // its formatting. + StringKindMarkdown StringKind = 1 +) + +// StringKind indicates a formatting or encoding scheme for a string. +type StringKind int32 + +func (s StringKind) String() string { + switch s { + case 0: + return "PLAIN" + case 1: + return "MARKDOWN" + } + return "UNKNOWN" +} diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/plugin.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/plugin.go index bef3a442f196..2eb08b4e4cea 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/plugin.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/plugin.go @@ -12,13 +12,20 @@ import ( "github.com/hashicorp/go-hclog" "github.com/hashicorp/terraform-exec/tfexec" "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest" "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" testing "github.com/mitchellh/go-testing-interface" ) -func runProviderCommand(t testing.T, f func() error, wd *plugintest.WorkingDir, factories map[string]func() (*schema.Provider, error), v5factories map[string]func() (tfprotov5.ProviderServer, error)) error { +type providerFactories struct { + legacy map[string]func() (*schema.Provider, error) + protov5 map[string]func() (tfprotov5.ProviderServer, error) + protov6 map[string]func() (tfprotov6.ProviderServer, error) +} + +func runProviderCommand(t testing.T, f func() error, wd *plugintest.WorkingDir, factories providerFactories) error { // don't point to this as a test failure location // point to whatever called it t.Helper() @@ -58,7 +65,7 @@ func runProviderCommand(t testing.T, f func() error, wd *plugintest.WorkingDir, // WaitGroup to listen for all of the close channels. var wg sync.WaitGroup reattachInfo := map[string]tfexec.ReattachConfig{} - for providerName, factory := range factories { + for providerName, factory := range factories.legacy { // providerName may be returned as terraform-provider-foo, and // we need just foo. So let's fix that. providerName = strings.TrimPrefix(providerName, "terraform-provider-") @@ -94,9 +101,10 @@ func runProviderCommand(t testing.T, f func() error, wd *plugintest.WorkingDir, return fmt.Errorf("unable to serve provider %q: %w", providerName, err) } tfexecConfig := tfexec.ReattachConfig{ - Protocol: config.Protocol, - Pid: config.Pid, - Test: config.Test, + Protocol: config.Protocol, + ProtocolVersion: config.ProtocolVersion, + Pid: config.Pid, + Test: config.Test, Addr: tfexec.ReattachConfigAddr{ Network: config.Addr.Network, String: config.Addr.String, @@ -120,9 +128,9 @@ func runProviderCommand(t testing.T, f func() error, wd *plugintest.WorkingDir, } } - // Now spin up gRPC servers for every plugin-go provider factory + // Now spin up gRPC servers for every protov5 provider factory // in the same way. - for providerName, factory := range v5factories { + for providerName, factory := range factories.protov5 { // providerName may be returned as terraform-provider-foo, and // we need just foo. So let's fix that. providerName = strings.TrimPrefix(providerName, "terraform-provider-") @@ -170,9 +178,85 @@ func runProviderCommand(t testing.T, f func() error, wd *plugintest.WorkingDir, return fmt.Errorf("unable to serve provider %q: %w", providerName, err) } tfexecConfig := tfexec.ReattachConfig{ - Protocol: config.Protocol, - Pid: config.Pid, - Test: config.Test, + Protocol: config.Protocol, + ProtocolVersion: config.ProtocolVersion, + Pid: config.Pid, + Test: config.Test, + Addr: tfexec.ReattachConfigAddr{ + Network: config.Addr.Network, + String: config.Addr.String, + }, + } + + // when the provider exits, remove one from the waitgroup + // so we can track when everything is done + go func(c <-chan struct{}) { + <-c + wg.Done() + }(closeCh) + + // set our provider's reattachinfo in our map, once + // for every namespace that different Terraform versions + // may expect. + for _, ns := range namespaces { + reattachString := strings.TrimSuffix(host, "/") + "/" + + strings.TrimSuffix(ns, "/") + "/" + + providerName + reattachInfo[reattachString] = tfexecConfig + } + } + + // Now spin up gRPC servers for every protov6 provider factory + // in the same way. + for providerName, factory := range factories.protov6 { + // providerName may be returned as terraform-provider-foo, and + // we need just foo. So let's fix that. + providerName = strings.TrimPrefix(providerName, "terraform-provider-") + + // If the user has already registered this provider in + // ProviderFactories or ProtoV5ProviderFactories, they made a + // mistake and we should exit early. + for _, ns := range namespaces { + reattachString := strings.TrimSuffix(host, "/") + "/" + + strings.TrimSuffix(ns, "/") + "/" + + providerName + if _, ok := reattachInfo[reattachString]; ok { + return fmt.Errorf("Provider %s registered in both TestCase.ProtoV6ProviderFactories and either TestCase.ProviderFactories or TestCase.ProtoV5ProviderFactories: please use one of the three, or supply a muxed provider to TestCase.ProtoV5ProviderFactories.", providerName) + } + } + + provider, err := factory() + if err != nil { + return fmt.Errorf("unable to create provider %q from factory: %w", providerName, err) + } + + // keep track of the running factory, so we can make sure it's + // shut down. + wg.Add(1) + + opts := &plugin.ServeOpts{ + GRPCProviderV6Func: func() tfprotov6.ProviderServer { + return provider + }, + Logger: hclog.New(&hclog.LoggerOptions{ + Name: "plugintest", + Level: hclog.Trace, + Output: ioutil.Discard, + }), + NoLogOutputOverride: true, + } + + // let's actually start the provider server + config, closeCh, err := plugin.DebugServe(ctx, opts) + if err != nil { + return fmt.Errorf("unable to serve provider %q: %w", providerName, err) + } + + tfexecConfig := tfexec.ReattachConfig{ + Protocol: config.Protocol, + ProtocolVersion: config.ProtocolVersion, + Pid: config.Pid, + Test: config.Test, Addr: tfexec.ReattachConfigAddr{ Network: config.Addr.Network, String: config.Addr.String, diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing.go index fc9644b371bc..2a03d548e8f6 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing.go @@ -14,6 +14,7 @@ import ( testing "github.com/mitchellh/go-testing-interface" "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/internal/addrs" @@ -305,6 +306,13 @@ type TestCase struct { // ProviderServer interface. ProtoV5ProviderFactories map[string]func() (tfprotov5.ProviderServer, error) + // ProtoV6ProviderFactories serves the same purpose as ProviderFactories, + // but for protocol v6 providers defined using the terraform-plugin-go + // ProviderServer interface. + // The version of Terraform used in acceptance testing must be greater + // than or equal to v0.15.4 to use ProtoV6ProviderFactories. + ProtoV6ProviderFactories map[string]func() (tfprotov6.ProviderServer, error) + // Providers is the ResourceProvider that will be under test. // // Deprecated: Providers is deprecated, please use ProviderFactories diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new.go index c9d90dd21597..1dc73906b331 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new.go @@ -11,17 +11,21 @@ import ( testing "github.com/mitchellh/go-testing-interface" "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func runPostTestDestroy(t testing.T, c TestCase, wd *plugintest.WorkingDir, factories map[string]func() (*schema.Provider, error), v5factories map[string]func() (tfprotov5.ProviderServer, error), statePreDestroy *terraform.State) error { +func runPostTestDestroy(t testing.T, c TestCase, wd *plugintest.WorkingDir, factories map[string]func() (*schema.Provider, error), v5factories map[string]func() (tfprotov5.ProviderServer, error), v6factories map[string]func() (tfprotov6.ProviderServer, error), statePreDestroy *terraform.State) error { t.Helper() err := runProviderCommand(t, func() error { return wd.Destroy() - }, wd, factories, v5factories) + }, wd, providerFactories{ + legacy: factories, + protov5: v5factories, + protov6: v6factories}) if err != nil { return err } @@ -51,14 +55,17 @@ func runNewTest(t testing.T, c TestCase, helper *plugintest.Helper) { return err } return nil - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { t.Fatalf("Error retrieving state, there may be dangling resources: %s", err.Error()) return } if !stateIsEmpty(statePreDestroy) { - err := runPostTestDestroy(t, c, wd, c.ProviderFactories, c.ProtoV5ProviderFactories, statePreDestroy) + err := runPostTestDestroy(t, c, wd, c.ProviderFactories, c.ProtoV5ProviderFactories, c.ProtoV6ProviderFactories, statePreDestroy) if err != nil { t.Fatalf("Error running post-test destroy, there may be dangling resources: %s", err.Error()) } @@ -78,7 +85,10 @@ func runNewTest(t testing.T, c TestCase, helper *plugintest.Helper) { } err = runProviderCommand(t, func() error { return wd.Init() - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { t.Fatalf("Error running init: %s", err.Error()) return @@ -218,7 +228,10 @@ func testIDRefresh(c TestCase, t testing.T, wd *plugintest.WorkingDir, step Test return err } return nil - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return err } diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_config.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_config.go index 0e218f60217e..9900cc3965df 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_config.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_config.go @@ -26,7 +26,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step return err } return nil - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return err } @@ -44,7 +47,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step // failing to do this will result in data sources not being updated err = runProviderCommand(t, func() error { return wd.Refresh() - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error running pre-apply refresh: %w", err) } @@ -59,7 +65,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step return wd.CreateDestroyPlan() } return wd.CreatePlan() - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error running pre-apply plan: %w", err) } @@ -74,7 +83,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step return err } return nil - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error retrieving pre-apply state: %w", err) } @@ -82,7 +94,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step // Apply the diff, creating real resources err = runProviderCommand(t, func() error { return wd.Apply() - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { if step.Destroy { return fmt.Errorf("Error running destroy: %w", err) @@ -98,7 +113,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step return err } return nil - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error retrieving state after apply: %w", err) } @@ -126,7 +144,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step return wd.CreateDestroyPlan() } return wd.CreatePlan() - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error running post-apply plan: %w", err) } @@ -136,7 +157,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step var err error plan, err = wd.SavedPlan() return err - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error retrieving post-apply plan: %w", err) } @@ -147,7 +171,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step var err error stdout, err = wd.SavedPlanRawStdout() return err - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error retrieving formatted plan output: %w", err) } @@ -158,7 +185,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step if !step.Destroy || (step.Destroy && !step.PreventPostDestroyRefresh) { err := runProviderCommand(t, func() error { return wd.Refresh() - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error running post-apply refresh: %w", err) } @@ -170,7 +200,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step return wd.CreateDestroyPlan() } return wd.CreatePlan() - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error running second post-apply plan: %w", err) } @@ -179,7 +212,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step var err error plan, err = wd.SavedPlan() return err - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error retrieving second post-apply plan: %w", err) } @@ -191,7 +227,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step var err error stdout, err = wd.SavedPlanRawStdout() return err - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return fmt.Errorf("Error retrieving formatted second plan output: %w", err) } @@ -210,7 +249,10 @@ func testStepNewConfig(t testing.T, c TestCase, wd *plugintest.WorkingDir, step return err } return nil - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return err } diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_import_state.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_import_state.go index 52487ad85cbe..a38c3c7dc421 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_import_state.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_import_state.go @@ -30,7 +30,10 @@ func testStepNewImportState(t testing.T, c TestCase, helper *plugintest.Helper, return err } return nil - }, wd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, wd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { t.Fatalf("Error getting state: %s", err) } @@ -71,14 +74,20 @@ func testStepNewImportState(t testing.T, c TestCase, helper *plugintest.Helper, err = runProviderCommand(t, func() error { return importWd.Init() - }, importWd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, importWd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { t.Fatalf("Error running init: %s", err) } err = runProviderCommand(t, func() error { return importWd.Import(step.ResourceName, importId) - }, importWd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, importWd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { return err } @@ -90,7 +99,10 @@ func testStepNewImportState(t testing.T, c TestCase, helper *plugintest.Helper, return err } return nil - }, importWd, c.ProviderFactories, c.ProtoV5ProviderFactories) + }, importWd, providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories}) if err != nil { t.Fatalf("Error getting state: %s", err) } diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema/schema.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema/schema.go index 7146bef766b2..10a9743c717d 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema/schema.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema/schema.go @@ -1439,7 +1439,7 @@ func (m schemaMap) validate( if err != nil { return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "Loading Default", + Summary: "Failed to determine default value", Detail: err.Error(), AttributePath: path, }) @@ -1453,7 +1453,7 @@ func (m schemaMap) validate( if err != nil { return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "ExactlyOne", + Summary: "Invalid combination of arguments", Detail: err.Error(), AttributePath: path, }) @@ -1463,7 +1463,7 @@ func (m schemaMap) validate( if err != nil { return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "AtLeastOne", + Summary: "Missing required argument", Detail: err.Error(), AttributePath: path, }) @@ -1485,8 +1485,8 @@ func (m schemaMap) validate( // This is a computed-only field return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "Computed attributes cannot be set", - Detail: fmt.Sprintf("Computed attributes cannot be set, but a value was set for %q.", k), + Summary: "Value for unconfigurable attribute", + Detail: fmt.Sprintf("Can't configure a value for %q: its value will be decided automatically based on the result of applying this configuration.", k), AttributePath: path, }) } @@ -1495,7 +1495,7 @@ func (m schemaMap) validate( if err != nil { return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "RequiredWith", + Summary: "Missing required argument", Detail: err.Error(), AttributePath: path, }) @@ -1510,7 +1510,7 @@ func (m schemaMap) validate( if schema.Deprecated != "" { return append(diags, diag.Diagnostic{ Severity: diag.Warning, - Summary: "Attribute is deprecated", + Summary: "Argument is deprecated", Detail: schema.Deprecated, AttributePath: path, }) @@ -1522,7 +1522,7 @@ func (m schemaMap) validate( if err != nil { return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "ConflictsWith", + Summary: "Conflicting configuration arguments", Detail: err.Error(), AttributePath: path, }) @@ -1699,7 +1699,7 @@ func (m schemaMap) validateList( if rawV.Kind() != reflect.Slice { return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "Attribute should be a list", + Summary: "Attribute must be a list", AttributePath: path, }) } @@ -1717,8 +1717,8 @@ func (m schemaMap) validateList( if schema.MaxItems > 0 && rawV.Len() > schema.MaxItems { return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "List longer than MaxItems", - Detail: fmt.Sprintf("Attribute supports %d item maximum, config has %d declared", schema.MaxItems, rawV.Len()), + Summary: "Too many list items", + Detail: fmt.Sprintf("Attribute supports %d item maximum, but config has %d declared.", schema.MaxItems, rawV.Len()), AttributePath: path, }) } @@ -1726,8 +1726,8 @@ func (m schemaMap) validateList( if schema.MinItems > 0 && rawV.Len() < schema.MinItems { return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "List shorter than MinItems", - Detail: fmt.Sprintf("Attribute supports %d item minimum, config has %d declared", schema.MinItems, rawV.Len()), + Summary: "Not enough list items", + Detail: fmt.Sprintf("Attribute requires %d item minimum, but config has only %d declared.", schema.MinItems, rawV.Len()), AttributePath: path, }) } @@ -1794,7 +1794,7 @@ func (m schemaMap) validateMap( if reifiedOk && raw == reified && !c.IsComputed(k) { return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "Attribute should be a map", + Summary: "Attribute must be a map", AttributePath: path, }) } @@ -1805,7 +1805,7 @@ func (m schemaMap) validateMap( default: return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "Attribute should be a map", + Summary: "Attribute must be a map", AttributePath: path, }) } @@ -1832,7 +1832,7 @@ func (m schemaMap) validateMap( if v.Kind() != reflect.Map { return append(diags, diag.Diagnostic{ Severity: diag.Error, - Summary: "Attribute should be a map", + Summary: "Attribute must be a map", AttributePath: path, }) } @@ -2111,7 +2111,7 @@ func (m schemaMap) validateType( if schema.Deprecated != "" { diags = append(diags, diag.Diagnostic{ Severity: diag.Warning, - Summary: "Deprecated Attribute", + Summary: "Argument is deprecated", Detail: schema.Deprecated, AttributePath: path, }) diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/meta/meta.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/meta/meta.go index 05dc625f1249..ab6c9e2aba8a 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/meta/meta.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/meta/meta.go @@ -11,7 +11,7 @@ import ( ) // The main version number that is being run at the moment. -var SDKVersion = "2.6.1" +var SDKVersion = "2.7.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/plugin/debug.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/plugin/debug.go index fb4f81400f89..171451ca7f97 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/plugin/debug.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/plugin/debug.go @@ -17,10 +17,11 @@ import ( // ReattachConfig holds the information Terraform needs to be able to attach // itself to a provider process, so it can drive the process. type ReattachConfig struct { - Protocol string - Pid int - Test bool - Addr ReattachConfigAddr + Protocol string + ProtocolVersion int + Pid int + Test bool + Addr ReattachConfigAddr } // ReattachConfigAddr is a JSON-encoding friendly version of net.Addr. @@ -56,9 +57,10 @@ func DebugServe(ctx context.Context, opts *ServeOpts) (ReattachConfig, <-chan st } return ReattachConfig{ - Protocol: string(config.Protocol), - Pid: config.Pid, - Test: config.Test, + Protocol: string(config.Protocol), + ProtocolVersion: config.ProtocolVersion, + Pid: config.Pid, + Test: config.Test, Addr: ReattachConfigAddr{ Network: config.Addr.Network(), String: config.Addr.String(), diff --git a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/plugin/serve.go b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/plugin/serve.go index baaab2d1d1c2..127889986ea1 100644 --- a/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/plugin/serve.go +++ b/awsproviderlint/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/plugin/serve.go @@ -9,6 +9,8 @@ import ( "github.com/hashicorp/terraform-plugin-go/tfprotov5" tf5server "github.com/hashicorp/terraform-plugin-go/tfprotov5/server" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + tf6server "github.com/hashicorp/terraform-plugin-go/tfprotov6/server" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -27,6 +29,7 @@ var Handshake = plugin.HandshakeConfig{ type ProviderFunc func() *schema.Provider type GRPCProviderFunc func() tfprotov5.ProviderServer +type GRPCProviderV6Func func() tfprotov6.ProviderServer // ServeOpts are the configurations to serve a plugin. type ServeOpts struct { @@ -36,6 +39,8 @@ type ServeOpts struct { // added to the GRPC functions when possible. GRPCProviderFunc GRPCProviderFunc + GRPCProviderV6Func GRPCProviderV6Func + // Logger is the logger that go-plugin will use. Logger hclog.Logger @@ -78,10 +83,19 @@ func Serve(opts *ServeOpts) { } } - provider := opts.GRPCProviderFunc() - plugin.Serve(&plugin.ServeConfig{ + serveConfig := plugin.ServeConfig{ HandshakeConfig: Handshake, - VersionedPlugins: map[int]plugin.PluginSet{ + GRPCServer: func(opts []grpc.ServerOption) *grpc.Server { + return grpc.NewServer(opts...) + }, + Logger: opts.Logger, + Test: opts.TestConfig, + } + + // assume we have either a v5 or a v6 provider + if opts.GRPCProviderFunc != nil { + provider := opts.GRPCProviderFunc() + serveConfig.VersionedPlugins = map[int]plugin.PluginSet{ 5: { ProviderPluginName: &tf5server.GRPCProviderPlugin{ GRPCProvider: func() tfprotov5.ProviderServer { @@ -89,11 +103,21 @@ func Serve(opts *ServeOpts) { }, }, }, - }, - GRPCServer: func(opts []grpc.ServerOption) *grpc.Server { - return grpc.NewServer(opts...) - }, - Logger: opts.Logger, - Test: opts.TestConfig, - }) + } + + } else if opts.GRPCProviderV6Func != nil { + provider := opts.GRPCProviderV6Func() + serveConfig.VersionedPlugins = map[int]plugin.PluginSet{ + 6: { + ProviderPluginName: &tf6server.GRPCProviderPlugin{ + GRPCProvider: func() tfprotov6.ProviderServer { + return provider + }, + }, + }, + } + + } + + plugin.Serve(&serveConfig) } diff --git a/awsproviderlint/vendor/github.com/mitchellh/copystructure/.travis.yml b/awsproviderlint/vendor/github.com/mitchellh/copystructure/.travis.yml deleted file mode 100644 index d7b9589ab11a..000000000000 --- a/awsproviderlint/vendor/github.com/mitchellh/copystructure/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: go - -go: - - 1.7 - - tip - -script: - - go test - -matrix: - allow_failures: - - go: tip diff --git a/awsproviderlint/vendor/github.com/mitchellh/copystructure/README.md b/awsproviderlint/vendor/github.com/mitchellh/copystructure/README.md index bcb8c8d2cb97..f0fbd2e5c98c 100644 --- a/awsproviderlint/vendor/github.com/mitchellh/copystructure/README.md +++ b/awsproviderlint/vendor/github.com/mitchellh/copystructure/README.md @@ -1,21 +1,21 @@ -# copystructure - -copystructure is a Go library for deep copying values in Go. - -This allows you to copy Go values that may contain reference values -such as maps, slices, or pointers, and copy their data as well instead -of just their references. - -## Installation - -Standard `go get`: - -``` -$ go get github.com/mitchellh/copystructure -``` - -## Usage & Example - -For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/copystructure). - -The `Copy` function has examples associated with it there. +# copystructure + +copystructure is a Go library for deep copying values in Go. + +This allows you to copy Go values that may contain reference values +such as maps, slices, or pointers, and copy their data as well instead +of just their references. + +## Installation + +Standard `go get`: + +``` +$ go get github.com/mitchellh/copystructure +``` + +## Usage & Example + +For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/copystructure). + +The `Copy` function has examples associated with it there. diff --git a/awsproviderlint/vendor/github.com/mitchellh/copystructure/copystructure.go b/awsproviderlint/vendor/github.com/mitchellh/copystructure/copystructure.go index 140435255e10..8089e6670a34 100644 --- a/awsproviderlint/vendor/github.com/mitchellh/copystructure/copystructure.go +++ b/awsproviderlint/vendor/github.com/mitchellh/copystructure/copystructure.go @@ -8,7 +8,30 @@ import ( "github.com/mitchellh/reflectwalk" ) +const tagKey = "copy" + // Copy returns a deep copy of v. +// +// Copy is unable to copy unexported fields in a struct (lowercase field names). +// Unexported fields can't be reflected by the Go runtime and therefore +// copystructure can't perform any data copies. +// +// For structs, copy behavior can be controlled with struct tags. For example: +// +// struct { +// Name string +// Data *bytes.Buffer `copy:"shallow"` +// } +// +// The available tag values are: +// +// * "ignore" - The field will be ignored, effectively resulting in it being +// assigned the zero value in the copy. +// +// * "shallow" - The field will be be shallow copied. This means that references +// values such as pointers, maps, slices, etc. will be directly assigned +// versus deep copied. +// func Copy(v interface{}) (interface{}, error) { return Config{}.Copy(v) } @@ -28,6 +51,19 @@ type CopierFunc func(interface{}) (interface{}, error) // this map as well as to Copy in a mutex. var Copiers map[reflect.Type]CopierFunc = make(map[reflect.Type]CopierFunc) +// ShallowCopiers is a map of pointer types that behave specially +// when they are copied. If a type is found in this map while deep +// copying, the pointer value will be shallow copied and not walked +// into. +// +// The key should be the type, obtained using: reflect.TypeOf(value +// with type). +// +// It is unsafe to write to this map after Copies have started. If you +// are writing to this map while also copying, wrap all modifications to +// this map as well as to Copy in a mutex. +var ShallowCopiers map[reflect.Type]struct{} = make(map[reflect.Type]struct{}) + // Must is a helper that wraps a call to a function returning // (interface{}, error) and panics if the error is non-nil. It is intended // for use in variable initializations and should only be used when a copy @@ -50,6 +86,11 @@ type Config struct { // Copiers is a map of types associated with a CopierFunc. Use the global // Copiers map if this is nil. Copiers map[reflect.Type]CopierFunc + + // ShallowCopiers is a map of pointer types that when they are + // shallow copied no matter where they are encountered. Use the + // global ShallowCopiers if this is nil. + ShallowCopiers map[reflect.Type]struct{} } func (c Config) Copy(v interface{}) (interface{}, error) { @@ -65,6 +106,12 @@ func (c Config) Copy(v interface{}) (interface{}, error) { if c.Copiers == nil { c.Copiers = Copiers } + w.copiers = c.Copiers + + if c.ShallowCopiers == nil { + c.ShallowCopiers = ShallowCopiers + } + w.shallowCopiers = c.ShallowCopiers err := reflectwalk.Walk(v, w) if err != nil { @@ -93,10 +140,12 @@ func ifaceKey(pointers, depth int) uint64 { type walker struct { Result interface{} - depth int - ignoreDepth int - vals []reflect.Value - cs []reflect.Value + copiers map[reflect.Type]CopierFunc + shallowCopiers map[reflect.Type]struct{} + depth int + ignoreDepth int + vals []reflect.Value + cs []reflect.Value // This stores the number of pointers we've walked over, indexed by depth. ps []int @@ -263,6 +312,20 @@ func (w *walker) PointerExit(v bool) error { return nil } +func (w *walker) Pointer(v reflect.Value) error { + if _, ok := w.shallowCopiers[v.Type()]; ok { + // Shallow copy this value. Use the same logic as primitive, then + // return skip. + if err := w.Primitive(v); err != nil { + return err + } + + return reflectwalk.SkipEntry + } + + return nil +} + func (w *walker) Interface(v reflect.Value) error { if !v.IsValid() { return nil @@ -356,7 +419,7 @@ func (w *walker) Struct(s reflect.Value) error { w.lock(s) var v reflect.Value - if c, ok := Copiers[s.Type()]; ok { + if c, ok := w.copiers[s.Type()]; ok { // We have a Copier for this struct, so we use that copier to // get the copy, and we ignore anything deeper than this. w.ignoreDepth = w.depth @@ -396,9 +459,29 @@ func (w *walker) StructField(f reflect.StructField, v reflect.Value) error { return reflectwalk.SkipEntry } + switch f.Tag.Get(tagKey) { + case "shallow": + // If we're shallow copying then assign the value directly to the + // struct and skip the entry. + if v.IsValid() { + s := w.cs[len(w.cs)-1] + sf := reflect.Indirect(s).FieldByName(f.Name) + if sf.CanSet() { + sf.Set(v) + } + } + + return reflectwalk.SkipEntry + + case "ignore": + // Do nothing + return reflectwalk.SkipEntry + } + // Push the field onto the stack, we'll handle it when we exit // the struct field in Exit... w.valPush(reflect.ValueOf(f)) + return nil } diff --git a/awsproviderlint/vendor/github.com/mitchellh/copystructure/go.mod b/awsproviderlint/vendor/github.com/mitchellh/copystructure/go.mod index d01864309b40..cd9c050c1bc5 100644 --- a/awsproviderlint/vendor/github.com/mitchellh/copystructure/go.mod +++ b/awsproviderlint/vendor/github.com/mitchellh/copystructure/go.mod @@ -1,3 +1,5 @@ module github.com/mitchellh/copystructure -require github.com/mitchellh/reflectwalk v1.0.0 +go 1.15 + +require github.com/mitchellh/reflectwalk v1.0.2 diff --git a/awsproviderlint/vendor/github.com/mitchellh/copystructure/go.sum b/awsproviderlint/vendor/github.com/mitchellh/copystructure/go.sum index be572456190a..3e38da1e18fd 100644 --- a/awsproviderlint/vendor/github.com/mitchellh/copystructure/go.sum +++ b/awsproviderlint/vendor/github.com/mitchellh/copystructure/go.sum @@ -1,2 +1,2 @@ -github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= diff --git a/awsproviderlint/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go b/awsproviderlint/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go index 3a93a0b114d4..7fee7b050ba4 100644 --- a/awsproviderlint/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go +++ b/awsproviderlint/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go @@ -69,6 +69,13 @@ type PointerWalker interface { PointerExit(bool) error } +// PointerValueWalker implementations are notified with the value of +// a particular pointer when a pointer is walked. Pointer is called +// right before PointerEnter. +type PointerValueWalker interface { + Pointer(reflect.Value) error +} + // SkipEntry can be returned from walk functions to skip walking // the value of this field. This is only valid in the following functions: // @@ -130,6 +137,17 @@ func walk(v reflect.Value, w interface{}) (err error) { } if pointerV.Kind() == reflect.Ptr { + if pw, ok := w.(PointerValueWalker); ok { + if err = pw.Pointer(pointerV); err != nil { + if err == SkipEntry { + // Skip the rest of this entry but clear the error + return nil + } + + return + } + } + pointer = true v = reflect.Indirect(pointerV) } diff --git a/awsproviderlint/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go b/awsproviderlint/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go index f05132e1c591..f50f196e2ca8 100644 --- a/awsproviderlint/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go +++ b/awsproviderlint/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go @@ -129,8 +129,9 @@ var LengthFunc = function.New(&function.Spec{ var ElementFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "list", - Type: cty.DynamicPseudoType, + Name: "list", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, { Name: "index", @@ -185,11 +186,12 @@ var ElementFunc = function.New(&function.Spec{ return cty.DynamicVal, fmt.Errorf("cannot use element function with a negative index") } - if !args[0].IsKnown() { + input, marks := args[0].Unmark() + if !input.IsKnown() { return cty.UnknownVal(retType), nil } - l := args[0].LengthInt() + l := input.LengthInt() if l == 0 { return cty.DynamicVal, errors.New("cannot use element function with an empty list") } @@ -197,7 +199,7 @@ var ElementFunc = function.New(&function.Spec{ // We did all the necessary type checks in the type function above, // so this is guaranteed not to fail. - return args[0].Index(cty.NumberIntVal(int64(index))), nil + return input.Index(cty.NumberIntVal(int64(index))).WithMarks(marks), nil }, }) @@ -528,10 +530,18 @@ func flattener(flattenList cty.Value) ([]cty.Value, []cty.ValueMarks, bool) { // predict the length of our result yet either. return nil, markses, false } + out := make([]cty.Value, 0) isKnown := true for it := flattenList.ElementIterator(); it.Next(); { _, val := it.Element() + + // Any dynamic types could result in more collections that need to be + // flattened, so the type cannot be known. + if val.Type().Equals(cty.DynamicPseudoType) { + isKnown = false + } + if val.Type().IsListType() || val.Type().IsSetType() || val.Type().IsTupleType() { if !val.IsKnown() { isKnown = false @@ -841,8 +851,9 @@ var MergeFunc = function.New(&function.Spec{ var ReverseListFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "list", - Type: cty.DynamicPseudoType, + Name: "list", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, }, Type: func(args []cty.Value) (cty.Type, error) { @@ -862,19 +873,21 @@ var ReverseListFunc = function.New(&function.Spec{ } }, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - in := args[0].AsValueSlice() - outVals := make([]cty.Value, len(in)) - for i, v := range in { + in, marks := args[0].Unmark() + inVals := in.AsValueSlice() + outVals := make([]cty.Value, len(inVals)) + + for i, v := range inVals { outVals[len(outVals)-i-1] = v } switch { case retType.IsTupleType(): - return cty.TupleVal(outVals), nil + return cty.TupleVal(outVals).WithMarks(marks), nil default: if len(outVals) == 0 { - return cty.ListValEmpty(retType.ElementType()), nil + return cty.ListValEmpty(retType.ElementType()).WithMarks(marks), nil } - return cty.ListVal(outVals), nil + return cty.ListVal(outVals).WithMarks(marks), nil } }, }) @@ -935,12 +948,16 @@ var SetProductFunc = function.New(&function.Spec{ var retMarks cty.ValueMarks total := 1 + var hasUnknownLength bool for _, arg := range args { arg, marks := arg.Unmark() retMarks = cty.NewValueMarks(retMarks, marks) + // Continue processing after we find an argument with unknown + // length to ensure that we cover all the marks if !arg.Length().IsKnown() { - return cty.UnknownVal(retType).Mark(marks), nil + hasUnknownLength = true + continue } // Because of our type checking function, we are guaranteed that @@ -949,13 +966,17 @@ var SetProductFunc = function.New(&function.Spec{ total *= arg.LengthInt() } + if hasUnknownLength { + return cty.UnknownVal(retType).WithMarks(retMarks), nil + } + if total == 0 { // If any of the arguments was an empty collection then our result // is also an empty collection, which we'll short-circuit here. if retType.IsListType() { - return cty.ListValEmpty(ety).Mark(retMarks), nil + return cty.ListValEmpty(ety).WithMarks(retMarks), nil } - return cty.SetValEmpty(ety).Mark(retMarks), nil + return cty.SetValEmpty(ety).WithMarks(retMarks), nil } subEtys := ety.TupleElementTypes() @@ -1018,8 +1039,9 @@ var SetProductFunc = function.New(&function.Spec{ var SliceFunc = function.New(&function.Spec{ Params: []function.Parameter{ { - Name: "list", - Type: cty.DynamicPseudoType, + Name: "list", + Type: cty.DynamicPseudoType, + AllowMarked: true, }, { Name: "start_index", @@ -1058,10 +1080,10 @@ var SliceFunc = function.New(&function.Spec{ return cty.Tuple(argTy.TupleElementTypes()[startIndex:endIndex]), nil }, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - inputList := args[0] + inputList, marks := args[0].Unmark() if retType == cty.DynamicPseudoType { - return cty.DynamicVal, nil + return cty.DynamicVal.WithMarks(marks), nil } // we ignore idxsKnown return value here because the indices are always @@ -1073,18 +1095,18 @@ var SliceFunc = function.New(&function.Spec{ if endIndex-startIndex == 0 { if retType.IsTupleType() { - return cty.EmptyTupleVal, nil + return cty.EmptyTupleVal.WithMarks(marks), nil } - return cty.ListValEmpty(retType.ElementType()), nil + return cty.ListValEmpty(retType.ElementType()).WithMarks(marks), nil } outputList := inputList.AsValueSlice()[startIndex:endIndex] if retType.IsTupleType() { - return cty.TupleVal(outputList), nil + return cty.TupleVal(outputList).WithMarks(marks), nil } - return cty.ListVal(outputList), nil + return cty.ListVal(outputList).WithMarks(marks), nil }, }) @@ -1092,9 +1114,12 @@ func sliceIndexes(args []cty.Value) (int, int, bool, error) { var startIndex, endIndex, length int var startKnown, endKnown, lengthKnown bool + // remove marks from args[0] + list, _ := args[0].Unmark() + // If it's a tuple then we always know the length by the type, but collections might be unknown or have unknown length - if args[0].Type().IsTupleType() || args[0].Length().IsKnown() { - length = args[0].LengthInt() + if list.Type().IsTupleType() || list.Length().IsKnown() { + length = list.LengthInt() lengthKnown = true } diff --git a/awsproviderlint/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go b/awsproviderlint/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go index 8cfed57f5358..6a6f66b3f6a3 100644 --- a/awsproviderlint/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go +++ b/awsproviderlint/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go @@ -43,6 +43,10 @@ var ConcatFunc = function.New(&function.Spec{ etys := make([]cty.Type, 0, len(args)) for i, val := range args { + // Discard marks for nested values, as we only need to handle types + // and lengths. + val, _ := val.UnmarkDeep() + ety := val.Type() switch { case ety.IsTupleType(): diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s index 6b4027b33fd2..db9171c2e491 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gc // +build gc #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_386.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_386.s index 0655ecbfbbec..8fd101d0716d 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_386.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_386.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gc // +build gc #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_amd64.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_amd64.s index bc3fb6ac3ed2..7ed38e43c673 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_amd64.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_amd64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gc // +build gc #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_arm.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_arm.s index 55b13c7ba45c..8ef1d51402ae 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_arm.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_arm.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gc // +build gc #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_arm64.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_arm64.s index 22a83d8e3fad..98ae02760da1 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_arm64.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_arm64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && arm64 && gc // +build linux // +build arm64 // +build gc diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s index dc222b90ce74..21231d2ce13f 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips64 || mips64le) && gc // +build linux // +build mips64 mips64le // +build gc diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s index d333f13cff3b..6783b26c606a 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (mips || mipsle) && gc // +build linux // +build mips mipsle // +build gc diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s index 459a629c2732..19d4989344df 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && (ppc64 || ppc64le) && gc // +build linux // +build ppc64 ppc64le // +build gc diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s index 04d38497c6dd..e42eb81d583d 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build riscv64,gc +//go:build riscv64 && gc +// +build riscv64 +// +build gc #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_s390x.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_s390x.s index cc303989e174..c46aab339594 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_s390x.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_linux_s390x.s @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build s390x +//go:build linux && s390x && gc // +build linux +// +build s390x // +build gc #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s index 47c93fcb6c76..5e7a1169c05d 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gc // +build gc #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s index 1f2c755a7203..f8c5394c1a72 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gc // +build gc #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go b/awsproviderlint/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go index cb0dfbd09a04..29d44808b1d0 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle) -// +build linux,386 linux,arm linux,mips linux,mipsle +//go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle) || (linux && ppc) +// +build linux,386 linux,arm linux,mips linux,mipsle linux,ppc package unix diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/fdset.go b/awsproviderlint/vendor/golang.org/x/sys/unix/fdset.go index b1e07b22023d..a8068f94f290 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/fdset.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/fdset.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris -// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos package unix diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/ioctl_linux.go b/awsproviderlint/vendor/golang.org/x/sys/unix/ioctl_linux.go new file mode 100644 index 000000000000..48773f730ac6 --- /dev/null +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/ioctl_linux.go @@ -0,0 +1,196 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "runtime" + "unsafe" +) + +// IoctlRetInt performs an ioctl operation specified by req on a device +// associated with opened file descriptor fd, and returns a non-negative +// integer that is returned by the ioctl syscall. +func IoctlRetInt(fd int, req uint) (int, error) { + ret, _, err := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), 0) + if err != 0 { + return 0, err + } + return int(ret), nil +} + +func IoctlGetUint32(fd int, req uint) (uint32, error) { + var value uint32 + err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) + return value, err +} + +func IoctlGetRTCTime(fd int) (*RTCTime, error) { + var value RTCTime + err := ioctl(fd, RTC_RD_TIME, uintptr(unsafe.Pointer(&value))) + return &value, err +} + +func IoctlSetRTCTime(fd int, value *RTCTime) error { + err := ioctl(fd, RTC_SET_TIME, uintptr(unsafe.Pointer(value))) + runtime.KeepAlive(value) + return err +} + +func IoctlGetRTCWkAlrm(fd int) (*RTCWkAlrm, error) { + var value RTCWkAlrm + err := ioctl(fd, RTC_WKALM_RD, uintptr(unsafe.Pointer(&value))) + return &value, err +} + +func IoctlSetRTCWkAlrm(fd int, value *RTCWkAlrm) error { + err := ioctl(fd, RTC_WKALM_SET, uintptr(unsafe.Pointer(value))) + runtime.KeepAlive(value) + return err +} + +type ifreqEthtool struct { + name [IFNAMSIZ]byte + data unsafe.Pointer +} + +// IoctlGetEthtoolDrvinfo fetches ethtool driver information for the network +// device specified by ifname. +func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) { + // Leave room for terminating NULL byte. + if len(ifname) >= IFNAMSIZ { + return nil, EINVAL + } + + value := EthtoolDrvinfo{ + Cmd: ETHTOOL_GDRVINFO, + } + ifreq := ifreqEthtool{ + data: unsafe.Pointer(&value), + } + copy(ifreq.name[:], ifname) + err := ioctl(fd, SIOCETHTOOL, uintptr(unsafe.Pointer(&ifreq))) + runtime.KeepAlive(ifreq) + return &value, err +} + +// IoctlGetWatchdogInfo fetches information about a watchdog device from the +// Linux watchdog API. For more information, see: +// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html. +func IoctlGetWatchdogInfo(fd int) (*WatchdogInfo, error) { + var value WatchdogInfo + err := ioctl(fd, WDIOC_GETSUPPORT, uintptr(unsafe.Pointer(&value))) + return &value, err +} + +// IoctlWatchdogKeepalive issues a keepalive ioctl to a watchdog device. For +// more information, see: +// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html. +func IoctlWatchdogKeepalive(fd int) error { + return ioctl(fd, WDIOC_KEEPALIVE, 0) +} + +// IoctlFileCloneRange performs an FICLONERANGE ioctl operation to clone the +// range of data conveyed in value to the file associated with the file +// descriptor destFd. See the ioctl_ficlonerange(2) man page for details. +func IoctlFileCloneRange(destFd int, value *FileCloneRange) error { + err := ioctl(destFd, FICLONERANGE, uintptr(unsafe.Pointer(value))) + runtime.KeepAlive(value) + return err +} + +// IoctlFileClone performs an FICLONE ioctl operation to clone the entire file +// associated with the file description srcFd to the file associated with the +// file descriptor destFd. See the ioctl_ficlone(2) man page for details. +func IoctlFileClone(destFd, srcFd int) error { + return ioctl(destFd, FICLONE, uintptr(srcFd)) +} + +type FileDedupeRange struct { + Src_offset uint64 + Src_length uint64 + Reserved1 uint16 + Reserved2 uint32 + Info []FileDedupeRangeInfo +} + +type FileDedupeRangeInfo struct { + Dest_fd int64 + Dest_offset uint64 + Bytes_deduped uint64 + Status int32 + Reserved uint32 +} + +// IoctlFileDedupeRange performs an FIDEDUPERANGE ioctl operation to share the +// range of data conveyed in value from the file associated with the file +// descriptor srcFd to the value.Info destinations. See the +// ioctl_fideduperange(2) man page for details. +func IoctlFileDedupeRange(srcFd int, value *FileDedupeRange) error { + buf := make([]byte, SizeofRawFileDedupeRange+ + len(value.Info)*SizeofRawFileDedupeRangeInfo) + rawrange := (*RawFileDedupeRange)(unsafe.Pointer(&buf[0])) + rawrange.Src_offset = value.Src_offset + rawrange.Src_length = value.Src_length + rawrange.Dest_count = uint16(len(value.Info)) + rawrange.Reserved1 = value.Reserved1 + rawrange.Reserved2 = value.Reserved2 + + for i := range value.Info { + rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer( + uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) + + uintptr(i*SizeofRawFileDedupeRangeInfo))) + rawinfo.Dest_fd = value.Info[i].Dest_fd + rawinfo.Dest_offset = value.Info[i].Dest_offset + rawinfo.Bytes_deduped = value.Info[i].Bytes_deduped + rawinfo.Status = value.Info[i].Status + rawinfo.Reserved = value.Info[i].Reserved + } + + err := ioctl(srcFd, FIDEDUPERANGE, uintptr(unsafe.Pointer(&buf[0]))) + + // Output + for i := range value.Info { + rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer( + uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) + + uintptr(i*SizeofRawFileDedupeRangeInfo))) + value.Info[i].Dest_fd = rawinfo.Dest_fd + value.Info[i].Dest_offset = rawinfo.Dest_offset + value.Info[i].Bytes_deduped = rawinfo.Bytes_deduped + value.Info[i].Status = rawinfo.Status + value.Info[i].Reserved = rawinfo.Reserved + } + + return err +} + +func IoctlHIDGetDesc(fd int, value *HIDRawReportDescriptor) error { + err := ioctl(fd, HIDIOCGRDESC, uintptr(unsafe.Pointer(value))) + runtime.KeepAlive(value) + return err +} + +func IoctlHIDGetRawInfo(fd int) (*HIDRawDevInfo, error) { + var value HIDRawDevInfo + err := ioctl(fd, HIDIOCGRAWINFO, uintptr(unsafe.Pointer(&value))) + return &value, err +} + +func IoctlHIDGetRawName(fd int) (string, error) { + var value [_HIDIOCGRAWNAME_LEN]byte + err := ioctl(fd, _HIDIOCGRAWNAME, uintptr(unsafe.Pointer(&value[0]))) + return ByteSliceToString(value[:]), err +} + +func IoctlHIDGetRawPhys(fd int) (string, error) { + var value [_HIDIOCGRAWPHYS_LEN]byte + err := ioctl(fd, _HIDIOCGRAWPHYS, uintptr(unsafe.Pointer(&value[0]))) + return ByteSliceToString(value[:]), err +} + +func IoctlHIDGetRawUniq(fd int) (string, error) { + var value [_HIDIOCGRAWUNIQ_LEN]byte + err := ioctl(fd, _HIDIOCGRAWUNIQ, uintptr(unsafe.Pointer(&value[0]))) + return ByteSliceToString(value[:]), err +} diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/mkerrors.sh b/awsproviderlint/vendor/golang.org/x/sys/unix/mkerrors.sh index 086d69411ba3..007358af8fc1 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -405,10 +405,11 @@ includes_SunOS=' #include #include #include +#include #include -#include #include #include +#include ' @@ -499,10 +500,10 @@ ccflags="$@" $2 ~ /^LOCK_(SH|EX|NB|UN)$/ || $2 ~ /^LO_(KEY|NAME)_SIZE$/ || $2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ || - $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL)_/ || + $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL)_/ || $2 ~ /^TP_STATUS_/ || $2 ~ /^FALLOC_/ || - $2 ~ /^ICMP(V6)?_FILTER$/ || + $2 ~ /^ICMPV?6?_(FILTER|SEC)/ || $2 == "SOMAXCONN" || $2 == "NAME_MAX" || $2 == "IFNAMSIZ" || diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_darwin.go b/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_darwin.go index 1223d7aed1c7..9945e5f9655a 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -378,6 +378,17 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e return } +func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) { + var value IPMreqn + vallen := _Socklen(SizeofIPMreqn) + errno := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) + return &value, errno +} + +func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) { + return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) +} + // GetsockoptXucred is a getsockopt wrapper that returns an Xucred struct. // The usual level and opt are SOL_LOCAL and LOCAL_PEERCRED, respectively. func GetsockoptXucred(fd, level, opt int) (*Xucred, error) { diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_illumos.go b/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_illumos.go index c5c58806ca86..8c5357683527 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_illumos.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_illumos.go @@ -1,4 +1,4 @@ -// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -10,6 +10,8 @@ package unix import ( + "fmt" + "runtime" "unsafe" ) @@ -127,3 +129,50 @@ func Getmsg(fd int, cl []byte, data []byte) (retCl []byte, retData []byte, flags } return retCl, retData, flags, nil } + +func IoctlSetIntRetInt(fd int, req uint, arg int) (int, error) { + return ioctlRet(fd, req, uintptr(arg)) +} + +func IoctlSetString(fd int, req uint, val string) error { + bs := make([]byte, len(val)+1) + copy(bs[:len(bs)-1], val) + err := ioctl(fd, req, uintptr(unsafe.Pointer(&bs[0]))) + runtime.KeepAlive(&bs[0]) + return err +} + +// Lifreq Helpers + +func (l *Lifreq) SetName(name string) error { + if len(name) >= len(l.Name) { + return fmt.Errorf("name cannot be more than %d characters", len(l.Name)-1) + } + for i := range name { + l.Name[i] = int8(name[i]) + } + return nil +} + +func (l *Lifreq) SetLifruInt(d int) { + *(*int)(unsafe.Pointer(&l.Lifru[0])) = d +} + +func (l *Lifreq) GetLifruInt() int { + return *(*int)(unsafe.Pointer(&l.Lifru[0])) +} + +func IoctlLifreq(fd int, req uint, l *Lifreq) error { + return ioctl(fd, req, uintptr(unsafe.Pointer(l))) +} + +// Strioctl Helpers + +func (s *Strioctl) SetInt(i int) { + s.Len = int32(unsafe.Sizeof(i)) + s.Dp = (*int8)(unsafe.Pointer(&i)) +} + +func IoctlSetStrioctlRetInt(fd int, req uint, s *Strioctl) (int, error) { + return ioctlRet(fd, req, uintptr(unsafe.Pointer(s))) +} diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_linux.go b/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_linux.go index 44ea96e39c6b..2dd7c8e34a94 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -70,167 +70,7 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { // ioctl itself should not be exposed directly, but additional get/set // functions for specific types are permissible. - -// IoctlRetInt performs an ioctl operation specified by req on a device -// associated with opened file descriptor fd, and returns a non-negative -// integer that is returned by the ioctl syscall. -func IoctlRetInt(fd int, req uint) (int, error) { - ret, _, err := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), 0) - if err != 0 { - return 0, err - } - return int(ret), nil -} - -func IoctlSetRTCTime(fd int, value *RTCTime) error { - err := ioctl(fd, RTC_SET_TIME, uintptr(unsafe.Pointer(value))) - runtime.KeepAlive(value) - return err -} - -func IoctlSetRTCWkAlrm(fd int, value *RTCWkAlrm) error { - err := ioctl(fd, RTC_WKALM_SET, uintptr(unsafe.Pointer(value))) - runtime.KeepAlive(value) - return err -} - -func IoctlGetUint32(fd int, req uint) (uint32, error) { - var value uint32 - err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) - return value, err -} - -func IoctlGetRTCTime(fd int) (*RTCTime, error) { - var value RTCTime - err := ioctl(fd, RTC_RD_TIME, uintptr(unsafe.Pointer(&value))) - return &value, err -} - -// IoctlGetWatchdogInfo fetches information about a watchdog device from the -// Linux watchdog API. For more information, see: -// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html. -func IoctlGetWatchdogInfo(fd int) (*WatchdogInfo, error) { - var value WatchdogInfo - err := ioctl(fd, WDIOC_GETSUPPORT, uintptr(unsafe.Pointer(&value))) - return &value, err -} - -func IoctlGetRTCWkAlrm(fd int) (*RTCWkAlrm, error) { - var value RTCWkAlrm - err := ioctl(fd, RTC_WKALM_RD, uintptr(unsafe.Pointer(&value))) - return &value, err -} - -// IoctlFileCloneRange performs an FICLONERANGE ioctl operation to clone the -// range of data conveyed in value to the file associated with the file -// descriptor destFd. See the ioctl_ficlonerange(2) man page for details. -func IoctlFileCloneRange(destFd int, value *FileCloneRange) error { - err := ioctl(destFd, FICLONERANGE, uintptr(unsafe.Pointer(value))) - runtime.KeepAlive(value) - return err -} - -// IoctlFileClone performs an FICLONE ioctl operation to clone the entire file -// associated with the file description srcFd to the file associated with the -// file descriptor destFd. See the ioctl_ficlone(2) man page for details. -func IoctlFileClone(destFd, srcFd int) error { - return ioctl(destFd, FICLONE, uintptr(srcFd)) -} - -type FileDedupeRange struct { - Src_offset uint64 - Src_length uint64 - Reserved1 uint16 - Reserved2 uint32 - Info []FileDedupeRangeInfo -} - -type FileDedupeRangeInfo struct { - Dest_fd int64 - Dest_offset uint64 - Bytes_deduped uint64 - Status int32 - Reserved uint32 -} - -// IoctlFileDedupeRange performs an FIDEDUPERANGE ioctl operation to share the -// range of data conveyed in value from the file associated with the file -// descriptor srcFd to the value.Info destinations. See the -// ioctl_fideduperange(2) man page for details. -func IoctlFileDedupeRange(srcFd int, value *FileDedupeRange) error { - buf := make([]byte, SizeofRawFileDedupeRange+ - len(value.Info)*SizeofRawFileDedupeRangeInfo) - rawrange := (*RawFileDedupeRange)(unsafe.Pointer(&buf[0])) - rawrange.Src_offset = value.Src_offset - rawrange.Src_length = value.Src_length - rawrange.Dest_count = uint16(len(value.Info)) - rawrange.Reserved1 = value.Reserved1 - rawrange.Reserved2 = value.Reserved2 - - for i := range value.Info { - rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer( - uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) + - uintptr(i*SizeofRawFileDedupeRangeInfo))) - rawinfo.Dest_fd = value.Info[i].Dest_fd - rawinfo.Dest_offset = value.Info[i].Dest_offset - rawinfo.Bytes_deduped = value.Info[i].Bytes_deduped - rawinfo.Status = value.Info[i].Status - rawinfo.Reserved = value.Info[i].Reserved - } - - err := ioctl(srcFd, FIDEDUPERANGE, uintptr(unsafe.Pointer(&buf[0]))) - - // Output - for i := range value.Info { - rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer( - uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) + - uintptr(i*SizeofRawFileDedupeRangeInfo))) - value.Info[i].Dest_fd = rawinfo.Dest_fd - value.Info[i].Dest_offset = rawinfo.Dest_offset - value.Info[i].Bytes_deduped = rawinfo.Bytes_deduped - value.Info[i].Status = rawinfo.Status - value.Info[i].Reserved = rawinfo.Reserved - } - - return err -} - -// IoctlWatchdogKeepalive issues a keepalive ioctl to a watchdog device. For -// more information, see: -// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html. -func IoctlWatchdogKeepalive(fd int) error { - return ioctl(fd, WDIOC_KEEPALIVE, 0) -} - -func IoctlHIDGetDesc(fd int, value *HIDRawReportDescriptor) error { - err := ioctl(fd, HIDIOCGRDESC, uintptr(unsafe.Pointer(value))) - runtime.KeepAlive(value) - return err -} - -func IoctlHIDGetRawInfo(fd int) (*HIDRawDevInfo, error) { - var value HIDRawDevInfo - err := ioctl(fd, HIDIOCGRAWINFO, uintptr(unsafe.Pointer(&value))) - return &value, err -} - -func IoctlHIDGetRawName(fd int) (string, error) { - var value [_HIDIOCGRAWNAME_LEN]byte - err := ioctl(fd, _HIDIOCGRAWNAME, uintptr(unsafe.Pointer(&value[0]))) - return ByteSliceToString(value[:]), err -} - -func IoctlHIDGetRawPhys(fd int) (string, error) { - var value [_HIDIOCGRAWPHYS_LEN]byte - err := ioctl(fd, _HIDIOCGRAWPHYS, uintptr(unsafe.Pointer(&value[0]))) - return ByteSliceToString(value[:]), err -} - -func IoctlHIDGetRawUniq(fd int) (string, error) { - var value [_HIDIOCGRAWUNIQ_LEN]byte - err := ioctl(fd, _HIDIOCGRAWUNIQ, uintptr(unsafe.Pointer(&value[0]))) - return ByteSliceToString(value[:]), err -} +// These are defined in ioctl.go and ioctl_linux.go. //sys Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) @@ -857,16 +697,19 @@ type SockaddrVM struct { // CID and Port specify a context ID and port address for a VM socket. // Guests have a unique CID, and hosts may have a well-known CID of: // - VMADDR_CID_HYPERVISOR: refers to the hypervisor process. + // - VMADDR_CID_LOCAL: refers to local communication (loopback). // - VMADDR_CID_HOST: refers to other processes on the host. - CID uint32 - Port uint32 - raw RawSockaddrVM + CID uint32 + Port uint32 + Flags uint8 + raw RawSockaddrVM } func (sa *SockaddrVM) sockaddr() (unsafe.Pointer, _Socklen, error) { sa.raw.Family = AF_VSOCK sa.raw.Port = sa.Port sa.raw.Cid = sa.CID + sa.raw.Flags = sa.Flags return unsafe.Pointer(&sa.raw), SizeofSockaddrVM, nil } @@ -1171,8 +1014,9 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { case AF_VSOCK: pp := (*RawSockaddrVM)(unsafe.Pointer(rsa)) sa := &SockaddrVM{ - CID: pp.Cid, - Port: pp.Port, + CID: pp.Cid, + Port: pp.Port, + Flags: pp.Flags, } return sa, nil case AF_BLUETOOTH: @@ -1307,7 +1151,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { func Accept(fd int) (nfd int, sa Sockaddr, err error) { var rsa RawSockaddrAny var len _Socklen = SizeofSockaddrAny - nfd, err = accept(fd, &rsa, &len) + // Try accept4 first for Android, then try accept for kernel older than 2.6.28 + nfd, err = accept4(fd, &rsa, &len, 0) + if err == ENOSYS { + nfd, err = accept(fd, &rsa, &len) + } if err != nil { return } diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go b/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go new file mode 100644 index 000000000000..7e65e088d29b --- /dev/null +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go @@ -0,0 +1,272 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && ppc +// +build linux +// +build ppc + +package unix + +import ( + "syscall" + "unsafe" +) + +//sys dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) +//sys Fchown(fd int, uid int, gid int) (err error) +//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 +//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 +//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64 +//sysnb Getegid() (egid int) +//sysnb Geteuid() (euid int) +//sysnb Getgid() (gid int) +//sysnb Getuid() (uid int) +//sysnb InotifyInit() (fd int, err error) +//sys Ioperm(from int, num int, on int) (err error) +//sys Iopl(level int) (err error) +//sys Lchown(path string, uid int, gid int) (err error) +//sys Listen(s int, n int) (err error) +//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 +//sys Pause() (err error) +//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 +//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) +//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT +//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64 +//sys setfsgid(gid int) (prev int, err error) +//sys setfsuid(uid int) (prev int, err error) +//sysnb Setregid(rgid int, egid int) (err error) +//sysnb Setresgid(rgid int, egid int, sgid int) (err error) +//sysnb Setresuid(ruid int, euid int, suid int) (err error) +//sysnb Setreuid(ruid int, euid int) (err error) +//sys Shutdown(fd int, how int) (err error) +//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) +//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 +//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64 +//sys Ustat(dev int, ubuf *Ustat_t) (err error) +//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) +//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) +//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) +//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) +//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) +//sysnb setgroups(n int, list *_Gid_t) (err error) +//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) +//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) +//sysnb socket(domain int, typ int, proto int) (fd int, err error) +//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) +//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) +//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) +//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) +//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) +//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) +//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) + +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) +//sysnb Gettimeofday(tv *Timeval) (err error) +//sysnb Time(t *Time_t) (tt Time_t, err error) +//sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) + +func Fadvise(fd int, offset int64, length int64, advice int) (err error) { + _, _, e1 := Syscall6(SYS_FADVISE64_64, uintptr(fd), uintptr(advice), uintptr(offset>>32), uintptr(offset), uintptr(length>>32), uintptr(length)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func seek(fd int, offset int64, whence int) (int64, syscall.Errno) { + var newoffset int64 + offsetLow := uint32(offset & 0xffffffff) + offsetHigh := uint32((offset >> 32) & 0xffffffff) + _, _, err := Syscall6(SYS__LLSEEK, uintptr(fd), uintptr(offsetHigh), uintptr(offsetLow), uintptr(unsafe.Pointer(&newoffset)), uintptr(whence), 0) + return newoffset, err +} + +func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { + newoffset, errno := seek(fd, offset, whence) + if errno != 0 { + return 0, errno + } + return newoffset, nil +} + +func Fstatfs(fd int, buf *Statfs_t) (err error) { + _, _, e := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf))) + if e != 0 { + err = e + } + return +} + +func Statfs(path string, buf *Statfs_t) (err error) { + pathp, err := BytePtrFromString(path) + if err != nil { + return err + } + _, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf))) + if e != 0 { + err = e + } + return +} + +//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) + +func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) { + page := uintptr(offset / 4096) + if offset != int64(page)*4096 { + return 0, EINVAL + } + return mmap2(addr, length, prot, flags, fd, page) +} + +func setTimespec(sec, nsec int64) Timespec { + return Timespec{Sec: int32(sec), Nsec: int32(nsec)} +} + +func setTimeval(sec, usec int64) Timeval { + return Timeval{Sec: int32(sec), Usec: int32(usec)} +} + +type rlimit32 struct { + Cur uint32 + Max uint32 +} + +//sysnb getrlimit(resource int, rlim *rlimit32) (err error) = SYS_UGETRLIMIT + +const rlimInf32 = ^uint32(0) +const rlimInf64 = ^uint64(0) + +func Getrlimit(resource int, rlim *Rlimit) (err error) { + err = prlimit(0, resource, nil, rlim) + if err != ENOSYS { + return err + } + + rl := rlimit32{} + err = getrlimit(resource, &rl) + if err != nil { + return + } + + if rl.Cur == rlimInf32 { + rlim.Cur = rlimInf64 + } else { + rlim.Cur = uint64(rl.Cur) + } + + if rl.Max == rlimInf32 { + rlim.Max = rlimInf64 + } else { + rlim.Max = uint64(rl.Max) + } + return +} + +//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT + +func Setrlimit(resource int, rlim *Rlimit) (err error) { + err = prlimit(0, resource, rlim, nil) + if err != ENOSYS { + return err + } + + rl := rlimit32{} + if rlim.Cur == rlimInf64 { + rl.Cur = rlimInf32 + } else if rlim.Cur < uint64(rlimInf32) { + rl.Cur = uint32(rlim.Cur) + } else { + return EINVAL + } + if rlim.Max == rlimInf64 { + rl.Max = rlimInf32 + } else if rlim.Max < uint64(rlimInf32) { + rl.Max = uint32(rlim.Max) + } else { + return EINVAL + } + + return setrlimit(resource, &rl) +} + +func (r *PtraceRegs) PC() uint32 { return r.Nip } + +func (r *PtraceRegs) SetPC(pc uint32) { r.Nip = pc } + +func (iov *Iovec) SetLen(length int) { + iov.Len = uint32(length) +} + +func (msghdr *Msghdr) SetControllen(length int) { + msghdr.Controllen = uint32(length) +} + +func (msghdr *Msghdr) SetIovlen(length int) { + msghdr.Iovlen = uint32(length) +} + +func (cmsg *Cmsghdr) SetLen(length int) { + cmsg.Len = uint32(length) +} + +//sysnb pipe(p *[2]_C_int) (err error) + +func Pipe(p []int) (err error) { + if len(p) != 2 { + return EINVAL + } + var pp [2]_C_int + err = pipe(&pp) + p[0] = int(pp[0]) + p[1] = int(pp[1]) + return +} + +//sysnb pipe2(p *[2]_C_int, flags int) (err error) + +func Pipe2(p []int, flags int) (err error) { + if len(p) != 2 { + return EINVAL + } + var pp [2]_C_int + err = pipe2(&pp, flags) + p[0] = int(pp[0]) + p[1] = int(pp[1]) + return +} + +//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) + +func Poll(fds []PollFd, timeout int) (n int, err error) { + if len(fds) == 0 { + return poll(nil, 0, timeout) + } + return poll(&fds[0], len(fds), timeout) +} + +//sys syncFileRange2(fd int, flags int, off int64, n int64) (err error) = SYS_SYNC_FILE_RANGE2 + +func SyncFileRange(fd int, off int64, n int64, flags int) error { + // The sync_file_range and sync_file_range2 syscalls differ only in the + // order of their arguments. + return syncFileRange2(fd, flags, off, n) +} + +//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) + +func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { + cmdlineLen := len(cmdline) + if cmdlineLen > 0 { + // Account for the additional NULL byte added by + // BytePtrFromString in kexecFileLoad. The kexec_file_load + // syscall expects a NULL-terminated string. + cmdlineLen++ + } + return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) +} diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go b/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go index 13f58d2b2fbc..1ffd8bfcfb90 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go @@ -222,6 +222,8 @@ func (cmsg *Cmsghdr) SetLen(length int) { //sys Creat(path string, mode uint32) (fd int, err error) = SYS___CREAT_A //sys Dup(oldfd int) (fd int, err error) //sys Dup2(oldfd int, newfd int) (err error) +//sys Errno2() (er2 int) = SYS___ERRNO2 +//sys Err2ad() (eadd *int) = SYS___ERR2AD //sys Exit(code int) //sys Fchdir(fd int) (err error) //sys Fchmod(fd int, mode uint32) (err error) @@ -245,10 +247,12 @@ func Fstat(fd int, stat *Stat_t) (err error) { //sys Poll(fds []PollFd, timeout int) (n int, err error) = SYS_POLL //sys Times(tms *Tms) (ticks uintptr, err error) = SYS_TIMES //sys W_Getmntent(buff *byte, size int) (lastsys int, err error) = SYS_W_GETMNTENT +//sys W_Getmntent_A(buff *byte, size int) (lastsys int, err error) = SYS___W_GETMNTENT_A -//sys Mount(path string, filesystem string, fstype string, mtm uint32, parmlen int32, parm string) (err error) = SYS___MOUNT_A -//sys Unmount(filesystem string, mtm int) (err error) = SYS___UMOUNT_A +//sys mount_LE(path string, filesystem string, fstype string, mtm uint32, parmlen int32, parm string) (err error) = SYS___MOUNT_A +//sys unmount(filesystem string, mtm int) (err error) = SYS___UMOUNT_A //sys Chroot(path string) (err error) = SYS___CHROOT_A +//sys Select(nmsgsfds int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (ret int, err error) = SYS_SELECT //sysnb Uname(buf *Utsname) (err error) = SYS___UNAME_A func Ptsname(fd int) (name string, err error) { @@ -1779,3 +1783,47 @@ func SetNonblock(fd int, nonblocking bool) (err error) { func Exec(argv0 string, argv []string, envv []string) error { return syscall.Exec(argv0, argv, envv) } + +func Mount(source string, target string, fstype string, flags uintptr, data string) (err error) { + if needspace := 8 - len(fstype); needspace <= 0 { + fstype = fstype[:8] + } else { + fstype += " "[:needspace] + } + return mount_LE(target, source, fstype, uint32(flags), int32(len(data)), data) +} + +func Unmount(name string, mtm int) (err error) { + // mountpoint is always a full path and starts with a '/' + // check if input string is not a mountpoint but a filesystem name + if name[0] != '/' { + return unmount(name, mtm) + } + // treat name as mountpoint + b2s := func(arr []byte) string { + nulli := bytes.IndexByte(arr, 0) + if nulli == -1 { + return string(arr) + } else { + return string(arr[:nulli]) + } + } + var buffer struct { + header W_Mnth + fsinfo [64]W_Mntent + } + fsCount, err := W_Getmntent_A((*byte)(unsafe.Pointer(&buffer)), int(unsafe.Sizeof(buffer))) + if err != nil { + return err + } + if fsCount == 0 { + return EINVAL + } + for i := 0; i < fsCount; i++ { + if b2s(buffer.fsinfo[i].Mountpoint[:]) == name { + err = unmount(b2s(buffer.fsinfo[i].Fsname[:]), mtm) + break + } + } + return err +} diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go index 0326a6b3af97..3df99f285f14 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go @@ -1022,6 +1022,15 @@ const ( MAP_RESERVED0100 = 0x100 MAP_SHARED = 0x1 MAP_STACK = 0x400 + MCAST_BLOCK_SOURCE = 0x54 + MCAST_EXCLUDE = 0x2 + MCAST_INCLUDE = 0x1 + MCAST_JOIN_GROUP = 0x50 + MCAST_JOIN_SOURCE_GROUP = 0x52 + MCAST_LEAVE_GROUP = 0x51 + MCAST_LEAVE_SOURCE_GROUP = 0x53 + MCAST_UNBLOCK_SOURCE = 0x55 + MCAST_UNDEFINED = 0x0 MCL_CURRENT = 0x1 MCL_FUTURE = 0x2 MNT_ACLS = 0x8000000 diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux.go index 3b1b9287bb98..47572aaa690f 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -166,13 +166,16 @@ const ( BPF_ALU64 = 0x7 BPF_AND = 0x50 BPF_ARSH = 0xc0 + BPF_ATOMIC = 0xc0 BPF_B = 0x10 BPF_BUILD_ID_SIZE = 0x14 BPF_CALL = 0x80 + BPF_CMPXCHG = 0xf1 BPF_DIV = 0x30 BPF_DW = 0x18 BPF_END = 0xd0 BPF_EXIT = 0x90 + BPF_FETCH = 0x1 BPF_FROM_BE = 0x8 BPF_FROM_LE = 0x0 BPF_FS_MAGIC = 0xcafe4a11 @@ -240,6 +243,7 @@ const ( BPF_W = 0x0 BPF_X = 0x8 BPF_XADD = 0xc0 + BPF_XCHG = 0xe1 BPF_XOR = 0xa0 BRKINT = 0x2 BS0 = 0x0 @@ -490,9 +494,9 @@ const ( DM_UUID_FLAG = 0x4000 DM_UUID_LEN = 0x81 DM_VERSION = 0xc138fd00 - DM_VERSION_EXTRA = "-ioctl (2020-10-01)" + DM_VERSION_EXTRA = "-ioctl (2021-02-01)" DM_VERSION_MAJOR = 0x4 - DM_VERSION_MINOR = 0x2b + DM_VERSION_MINOR = 0x2c DM_VERSION_PATCHLEVEL = 0x0 DT_BLK = 0x6 DT_CHR = 0x2 @@ -860,6 +864,7 @@ const ( FS_IOC_GET_ENCRYPTION_KEY_STATUS = 0xc080661a FS_IOC_GET_ENCRYPTION_POLICY_EX = 0xc0096616 FS_IOC_MEASURE_VERITY = 0xc0046686 + FS_IOC_READ_VERITY_METADATA = 0xc0286687 FS_IOC_REMOVE_ENCRYPTION_KEY = 0xc0406618 FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS = 0xc0406619 FS_KEY_DESCRIPTOR_SIZE = 0x8 @@ -875,6 +880,9 @@ const ( FS_VERITY_FL = 0x100000 FS_VERITY_HASH_ALG_SHA256 = 0x1 FS_VERITY_HASH_ALG_SHA512 = 0x2 + FS_VERITY_METADATA_TYPE_DESCRIPTOR = 0x2 + FS_VERITY_METADATA_TYPE_MERKLE_TREE = 0x1 + FS_VERITY_METADATA_TYPE_SIGNATURE = 0x3 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 F_DUPFD = 0x0 @@ -974,6 +982,10 @@ const ( HUGETLBFS_MAGIC = 0x958458f6 IBSHIFT = 0x10 ICMPV6_FILTER = 0x1 + ICMPV6_FILTER_BLOCK = 0x1 + ICMPV6_FILTER_BLOCKOTHERS = 0x3 + ICMPV6_FILTER_PASS = 0x2 + ICMPV6_FILTER_PASSONLY = 0x4 ICMP_FILTER = 0x1 ICRNL = 0x100 IFA_F_DADFAILED = 0x8 @@ -1669,6 +1681,10 @@ const ( PERF_FLAG_PID_CGROUP = 0x4 PERF_MAX_CONTEXTS_PER_STACK = 0x8 PERF_MAX_STACK_DEPTH = 0x7f + PERF_MEM_BLK_ADDR = 0x4 + PERF_MEM_BLK_DATA = 0x2 + PERF_MEM_BLK_NA = 0x1 + PERF_MEM_BLK_SHIFT = 0x28 PERF_MEM_LOCK_LOCKED = 0x2 PERF_MEM_LOCK_NA = 0x1 PERF_MEM_LOCK_SHIFT = 0x18 @@ -1732,12 +1748,14 @@ const ( PERF_RECORD_MISC_GUEST_USER = 0x5 PERF_RECORD_MISC_HYPERVISOR = 0x3 PERF_RECORD_MISC_KERNEL = 0x1 + PERF_RECORD_MISC_MMAP_BUILD_ID = 0x4000 PERF_RECORD_MISC_MMAP_DATA = 0x2000 PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT = 0x1000 PERF_RECORD_MISC_SWITCH_OUT = 0x2000 PERF_RECORD_MISC_SWITCH_OUT_PREEMPT = 0x4000 PERF_RECORD_MISC_USER = 0x2 PERF_SAMPLE_BRANCH_PLM_ALL = 0x7 + PERF_SAMPLE_WEIGHT_TYPE = 0x1004000 PIPEFS_MAGIC = 0x50495045 PPC_CMM_MAGIC = 0xc7571590 PPPIOCGNPMODE = 0xc008744c @@ -1991,6 +2009,10 @@ const ( RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 RTC_AF = 0x20 + RTC_FEATURE_ALARM = 0x0 + RTC_FEATURE_ALARM_RES_MINUTE = 0x1 + RTC_FEATURE_CNT = 0x3 + RTC_FEATURE_NEED_WEEK_DAY = 0x2 RTC_IRQF = 0x80 RTC_MAX_FREQ = 0x2000 RTC_PF = 0x40 @@ -2064,6 +2086,7 @@ const ( RTM_F_LOOKUP_TABLE = 0x1000 RTM_F_NOTIFY = 0x100 RTM_F_OFFLOAD = 0x4000 + RTM_F_OFFLOAD_FAILED = 0x20000000 RTM_F_PREFIX = 0x800 RTM_F_TRAP = 0x8000 RTM_GETACTION = 0x32 diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go new file mode 100644 index 000000000000..d9530e5fbfbc --- /dev/null +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -0,0 +1,860 @@ +// mkerrors.sh -Wall -Werror -static -I/tmp/include +// Code generated by the command above; see README.md. DO NOT EDIT. + +//go:build ppc && linux +// +build ppc,linux + +// Code generated by cmd/cgo -godefs; DO NOT EDIT. +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go + +package unix + +import "syscall" + +const ( + B1000000 = 0x17 + B115200 = 0x11 + B1152000 = 0x18 + B1500000 = 0x19 + B2000000 = 0x1a + B230400 = 0x12 + B2500000 = 0x1b + B3000000 = 0x1c + B3500000 = 0x1d + B4000000 = 0x1e + B460800 = 0x13 + B500000 = 0x14 + B57600 = 0x10 + B576000 = 0x15 + B921600 = 0x16 + BLKBSZGET = 0x40041270 + BLKBSZSET = 0x80041271 + BLKFLSBUF = 0x20001261 + BLKFRAGET = 0x20001265 + BLKFRASET = 0x20001264 + BLKGETSIZE = 0x20001260 + BLKGETSIZE64 = 0x40041272 + BLKPBSZGET = 0x2000127b + BLKRAGET = 0x20001263 + BLKRASET = 0x20001262 + BLKROGET = 0x2000125e + BLKROSET = 0x2000125d + BLKRRPART = 0x2000125f + BLKSECTGET = 0x20001267 + BLKSECTSET = 0x20001266 + BLKSSZGET = 0x20001268 + BOTHER = 0x1f + BS1 = 0x8000 + BSDLY = 0x8000 + CBAUD = 0xff + CBAUDEX = 0x0 + CIBAUD = 0xff0000 + CLOCAL = 0x8000 + CR1 = 0x1000 + CR2 = 0x2000 + CR3 = 0x3000 + CRDLY = 0x3000 + CREAD = 0x800 + CS6 = 0x100 + CS7 = 0x200 + CS8 = 0x300 + CSIZE = 0x300 + CSTOPB = 0x400 + ECHOCTL = 0x40 + ECHOE = 0x2 + ECHOK = 0x4 + ECHOKE = 0x1 + ECHONL = 0x10 + ECHOPRT = 0x20 + EFD_CLOEXEC = 0x80000 + EFD_NONBLOCK = 0x800 + EPOLL_CLOEXEC = 0x80000 + EXTPROC = 0x10000000 + FF1 = 0x4000 + FFDLY = 0x4000 + FICLONE = 0x80049409 + FICLONERANGE = 0x8020940d + FLUSHO = 0x800000 + FS_IOC_ENABLE_VERITY = 0x80806685 + FS_IOC_GETFLAGS = 0x40046601 + FS_IOC_GET_ENCRYPTION_NONCE = 0x4010661b + FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615 + FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614 + FS_IOC_SETFLAGS = 0x80046602 + FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613 + F_GETLK = 0xc + F_GETLK64 = 0xc + F_GETOWN = 0x9 + F_RDLCK = 0x0 + F_SETLK = 0xd + F_SETLK64 = 0xd + F_SETLKW = 0xe + F_SETLKW64 = 0xe + F_SETOWN = 0x8 + F_UNLCK = 0x2 + F_WRLCK = 0x1 + HIDIOCGRAWINFO = 0x40084803 + HIDIOCGRDESC = 0x50044802 + HIDIOCGRDESCSIZE = 0x40044801 + HUPCL = 0x4000 + ICANON = 0x100 + IEXTEN = 0x400 + IN_CLOEXEC = 0x80000 + IN_NONBLOCK = 0x800 + IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + ISIG = 0x80 + IUCLC = 0x1000 + IXOFF = 0x400 + IXON = 0x200 + MAP_ANON = 0x20 + MAP_ANONYMOUS = 0x20 + MAP_DENYWRITE = 0x800 + MAP_EXECUTABLE = 0x1000 + MAP_GROWSDOWN = 0x100 + MAP_HUGETLB = 0x40000 + MAP_LOCKED = 0x80 + MAP_NONBLOCK = 0x10000 + MAP_NORESERVE = 0x40 + MAP_POPULATE = 0x8000 + MAP_STACK = 0x20000 + MAP_SYNC = 0x80000 + MCL_CURRENT = 0x2000 + MCL_FUTURE = 0x4000 + MCL_ONFAULT = 0x8000 + NFDBITS = 0x20 + NL2 = 0x200 + NL3 = 0x300 + NLDLY = 0x300 + NOFLSH = 0x80000000 + NS_GET_NSTYPE = 0x2000b703 + NS_GET_OWNER_UID = 0x2000b704 + NS_GET_PARENT = 0x2000b702 + NS_GET_USERNS = 0x2000b701 + OLCUC = 0x4 + ONLCR = 0x2 + O_APPEND = 0x400 + O_ASYNC = 0x2000 + O_CLOEXEC = 0x80000 + O_CREAT = 0x40 + O_DIRECT = 0x20000 + O_DIRECTORY = 0x4000 + O_DSYNC = 0x1000 + O_EXCL = 0x80 + O_FSYNC = 0x101000 + O_LARGEFILE = 0x10000 + O_NDELAY = 0x800 + O_NOATIME = 0x40000 + O_NOCTTY = 0x100 + O_NOFOLLOW = 0x8000 + O_NONBLOCK = 0x800 + O_PATH = 0x200000 + O_RSYNC = 0x101000 + O_SYNC = 0x101000 + O_TMPFILE = 0x404000 + O_TRUNC = 0x200 + PARENB = 0x1000 + PARODD = 0x2000 + PENDIN = 0x20000000 + PERF_EVENT_IOC_DISABLE = 0x20002401 + PERF_EVENT_IOC_ENABLE = 0x20002400 + PERF_EVENT_IOC_ID = 0x40042407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8004240b + PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 + PERF_EVENT_IOC_PERIOD = 0x80082404 + PERF_EVENT_IOC_QUERY_BPF = 0xc004240a + PERF_EVENT_IOC_REFRESH = 0x20002402 + PERF_EVENT_IOC_RESET = 0x20002403 + PERF_EVENT_IOC_SET_BPF = 0x80042408 + PERF_EVENT_IOC_SET_FILTER = 0x80042406 + PERF_EVENT_IOC_SET_OUTPUT = 0x20002405 + PPPIOCATTACH = 0x8004743d + PPPIOCATTCHAN = 0x80047438 + PPPIOCBRIDGECHAN = 0x80047435 + PPPIOCCONNECT = 0x8004743a + PPPIOCDETACH = 0x8004743c + PPPIOCDISCONN = 0x20007439 + PPPIOCGASYNCMAP = 0x40047458 + PPPIOCGCHAN = 0x40047437 + PPPIOCGDEBUG = 0x40047441 + PPPIOCGFLAGS = 0x4004745a + PPPIOCGIDLE = 0x4008743f + PPPIOCGIDLE32 = 0x4008743f + PPPIOCGIDLE64 = 0x4010743f + PPPIOCGL2TPSTATS = 0x40487436 + PPPIOCGMRU = 0x40047453 + PPPIOCGRASYNCMAP = 0x40047455 + PPPIOCGUNIT = 0x40047456 + PPPIOCGXASYNCMAP = 0x40207450 + PPPIOCSACTIVE = 0x80087446 + PPPIOCSASYNCMAP = 0x80047457 + PPPIOCSCOMPRESS = 0x800c744d + PPPIOCSDEBUG = 0x80047440 + PPPIOCSFLAGS = 0x80047459 + PPPIOCSMAXCID = 0x80047451 + PPPIOCSMRRU = 0x8004743b + PPPIOCSMRU = 0x80047452 + PPPIOCSNPMODE = 0x8008744b + PPPIOCSPASS = 0x80087447 + PPPIOCSRASYNCMAP = 0x80047454 + PPPIOCSXASYNCMAP = 0x8020744f + PPPIOCUNBRIDGECHAN = 0x20007434 + PPPIOCXFERUNIT = 0x2000744e + PROT_SAO = 0x10 + PR_SET_PTRACER_ANY = 0xffffffff + PTRACE_GETEVRREGS = 0x14 + PTRACE_GETFPREGS = 0xe + PTRACE_GETREGS64 = 0x16 + PTRACE_GETVRREGS = 0x12 + PTRACE_GETVSRREGS = 0x1b + PTRACE_GET_DEBUGREG = 0x19 + PTRACE_SETEVRREGS = 0x15 + PTRACE_SETFPREGS = 0xf + PTRACE_SETREGS64 = 0x17 + PTRACE_SETVRREGS = 0x13 + PTRACE_SETVSRREGS = 0x1c + PTRACE_SET_DEBUGREG = 0x1a + PTRACE_SINGLEBLOCK = 0x100 + PTRACE_SYSEMU = 0x1d + PTRACE_SYSEMU_SINGLESTEP = 0x1e + PT_CCR = 0x26 + PT_CTR = 0x23 + PT_DAR = 0x29 + PT_DSCR = 0x2c + PT_DSISR = 0x2a + PT_FPR0 = 0x30 + PT_FPR31 = 0x6e + PT_FPSCR = 0x71 + PT_LNK = 0x24 + PT_MQ = 0x27 + PT_MSR = 0x21 + PT_NIP = 0x20 + PT_ORIG_R3 = 0x22 + PT_R0 = 0x0 + PT_R1 = 0x1 + PT_R10 = 0xa + PT_R11 = 0xb + PT_R12 = 0xc + PT_R13 = 0xd + PT_R14 = 0xe + PT_R15 = 0xf + PT_R16 = 0x10 + PT_R17 = 0x11 + PT_R18 = 0x12 + PT_R19 = 0x13 + PT_R2 = 0x2 + PT_R20 = 0x14 + PT_R21 = 0x15 + PT_R22 = 0x16 + PT_R23 = 0x17 + PT_R24 = 0x18 + PT_R25 = 0x19 + PT_R26 = 0x1a + PT_R27 = 0x1b + PT_R28 = 0x1c + PT_R29 = 0x1d + PT_R3 = 0x3 + PT_R30 = 0x1e + PT_R31 = 0x1f + PT_R4 = 0x4 + PT_R5 = 0x5 + PT_R6 = 0x6 + PT_R7 = 0x7 + PT_R8 = 0x8 + PT_R9 = 0x9 + PT_REGS_COUNT = 0x2c + PT_RESULT = 0x2b + PT_TRAP = 0x28 + PT_XER = 0x25 + RLIMIT_AS = 0x9 + RLIMIT_MEMLOCK = 0x8 + RLIMIT_NOFILE = 0x7 + RLIMIT_NPROC = 0x6 + RLIMIT_RSS = 0x5 + RNDADDENTROPY = 0x80085203 + RNDADDTOENTCNT = 0x80045201 + RNDCLEARPOOL = 0x20005206 + RNDGETENTCNT = 0x40045200 + RNDGETPOOL = 0x40085202 + RNDRESEEDCRNG = 0x20005207 + RNDZAPENTCNT = 0x20005204 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4004700d + RTC_EPOCH_SET = 0x8004700e + RTC_IRQP_READ = 0x4004700b + RTC_IRQP_SET = 0x8004700c + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x401c7011 + RTC_PLL_SET = 0x801c7012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f + SCM_TIMESTAMPING = 0x25 + SCM_TIMESTAMPING_OPT_STATS = 0x36 + SCM_TIMESTAMPING_PKTINFO = 0x3a + SCM_TIMESTAMPNS = 0x23 + SCM_TXTIME = 0x3d + SCM_WIFI_STATUS = 0x29 + SFD_CLOEXEC = 0x80000 + SFD_NONBLOCK = 0x800 + SIOCATMARK = 0x8905 + SIOCGPGRP = 0x8904 + SIOCGSTAMPNS_NEW = 0x40108907 + SIOCGSTAMP_NEW = 0x40108906 + SIOCINQ = 0x4004667f + SIOCOUTQ = 0x40047473 + SIOCSPGRP = 0x8902 + SOCK_CLOEXEC = 0x80000 + SOCK_DGRAM = 0x2 + SOCK_NONBLOCK = 0x800 + SOCK_STREAM = 0x1 + SOL_SOCKET = 0x1 + SO_ACCEPTCONN = 0x1e + SO_ATTACH_BPF = 0x32 + SO_ATTACH_REUSEPORT_CBPF = 0x33 + SO_ATTACH_REUSEPORT_EBPF = 0x34 + SO_BINDTODEVICE = 0x19 + SO_BINDTOIFINDEX = 0x3e + SO_BPF_EXTENSIONS = 0x30 + SO_BROADCAST = 0x6 + SO_BSDCOMPAT = 0xe + SO_BUSY_POLL = 0x2e + SO_BUSY_POLL_BUDGET = 0x46 + SO_CNX_ADVICE = 0x35 + SO_COOKIE = 0x39 + SO_DETACH_REUSEPORT_BPF = 0x44 + SO_DOMAIN = 0x27 + SO_DONTROUTE = 0x5 + SO_ERROR = 0x4 + SO_INCOMING_CPU = 0x31 + SO_INCOMING_NAPI_ID = 0x38 + SO_KEEPALIVE = 0x9 + SO_LINGER = 0xd + SO_LOCK_FILTER = 0x2c + SO_MARK = 0x24 + SO_MAX_PACING_RATE = 0x2f + SO_MEMINFO = 0x37 + SO_NOFCS = 0x2b + SO_OOBINLINE = 0xa + SO_PASSCRED = 0x14 + SO_PASSSEC = 0x22 + SO_PEEK_OFF = 0x2a + SO_PEERCRED = 0x15 + SO_PEERGROUPS = 0x3b + SO_PEERSEC = 0x1f + SO_PREFER_BUSY_POLL = 0x45 + SO_PROTOCOL = 0x26 + SO_RCVBUF = 0x8 + SO_RCVBUFFORCE = 0x21 + SO_RCVLOWAT = 0x10 + SO_RCVTIMEO = 0x12 + SO_RCVTIMEO_NEW = 0x42 + SO_RCVTIMEO_OLD = 0x12 + SO_REUSEADDR = 0x2 + SO_REUSEPORT = 0xf + SO_RXQ_OVFL = 0x28 + SO_SECURITY_AUTHENTICATION = 0x16 + SO_SECURITY_ENCRYPTION_NETWORK = 0x18 + SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17 + SO_SELECT_ERR_QUEUE = 0x2d + SO_SNDBUF = 0x7 + SO_SNDBUFFORCE = 0x20 + SO_SNDLOWAT = 0x11 + SO_SNDTIMEO = 0x13 + SO_SNDTIMEO_NEW = 0x43 + SO_SNDTIMEO_OLD = 0x13 + SO_TIMESTAMPING = 0x25 + SO_TIMESTAMPING_NEW = 0x41 + SO_TIMESTAMPING_OLD = 0x25 + SO_TIMESTAMPNS = 0x23 + SO_TIMESTAMPNS_NEW = 0x40 + SO_TIMESTAMPNS_OLD = 0x23 + SO_TIMESTAMP_NEW = 0x3f + SO_TXTIME = 0x3d + SO_TYPE = 0x3 + SO_WIFI_STATUS = 0x29 + SO_ZEROCOPY = 0x3c + TAB1 = 0x400 + TAB2 = 0x800 + TAB3 = 0xc00 + TABDLY = 0xc00 + TCFLSH = 0x2000741f + TCGETA = 0x40147417 + TCGETS = 0x402c7413 + TCSAFLUSH = 0x2 + TCSBRK = 0x2000741d + TCSBRKP = 0x5425 + TCSETA = 0x80147418 + TCSETAF = 0x8014741c + TCSETAW = 0x80147419 + TCSETS = 0x802c7414 + TCSETSF = 0x802c7416 + TCSETSW = 0x802c7415 + TCXONC = 0x2000741e + TFD_CLOEXEC = 0x80000 + TFD_NONBLOCK = 0x800 + TIOCCBRK = 0x5428 + TIOCCONS = 0x541d + TIOCEXCL = 0x540c + TIOCGDEV = 0x40045432 + TIOCGETC = 0x40067412 + TIOCGETD = 0x5424 + TIOCGETP = 0x40067408 + TIOCGEXCL = 0x40045440 + TIOCGICOUNT = 0x545d + TIOCGISO7816 = 0x40285442 + TIOCGLCKTRMIOS = 0x5456 + TIOCGLTC = 0x40067474 + TIOCGPGRP = 0x40047477 + TIOCGPKT = 0x40045438 + TIOCGPTLCK = 0x40045439 + TIOCGPTN = 0x40045430 + TIOCGPTPEER = 0x20005441 + TIOCGRS485 = 0x542e + TIOCGSERIAL = 0x541e + TIOCGSID = 0x5429 + TIOCGSOFTCAR = 0x5419 + TIOCGWINSZ = 0x40087468 + TIOCINQ = 0x4004667f + TIOCLINUX = 0x541c + TIOCMBIC = 0x5417 + TIOCMBIS = 0x5416 + TIOCMGET = 0x5415 + TIOCMIWAIT = 0x545c + TIOCMSET = 0x5418 + TIOCM_CAR = 0x40 + TIOCM_CD = 0x40 + TIOCM_CTS = 0x20 + TIOCM_DSR = 0x100 + TIOCM_LOOP = 0x8000 + TIOCM_OUT1 = 0x2000 + TIOCM_OUT2 = 0x4000 + TIOCM_RI = 0x80 + TIOCM_RNG = 0x80 + TIOCM_SR = 0x10 + TIOCM_ST = 0x8 + TIOCNOTTY = 0x5422 + TIOCNXCL = 0x540d + TIOCOUTQ = 0x40047473 + TIOCPKT = 0x5420 + TIOCSBRK = 0x5427 + TIOCSCTTY = 0x540e + TIOCSERCONFIG = 0x5453 + TIOCSERGETLSR = 0x5459 + TIOCSERGETMULTI = 0x545a + TIOCSERGSTRUCT = 0x5458 + TIOCSERGWILD = 0x5454 + TIOCSERSETMULTI = 0x545b + TIOCSERSWILD = 0x5455 + TIOCSER_TEMT = 0x1 + TIOCSETC = 0x80067411 + TIOCSETD = 0x5423 + TIOCSETN = 0x8006740a + TIOCSETP = 0x80067409 + TIOCSIG = 0x80045436 + TIOCSISO7816 = 0xc0285443 + TIOCSLCKTRMIOS = 0x5457 + TIOCSLTC = 0x80067475 + TIOCSPGRP = 0x80047476 + TIOCSPTLCK = 0x80045431 + TIOCSRS485 = 0x542f + TIOCSSERIAL = 0x541f + TIOCSSOFTCAR = 0x541a + TIOCSTART = 0x2000746e + TIOCSTI = 0x5412 + TIOCSTOP = 0x2000746f + TIOCSWINSZ = 0x80087467 + TIOCVHANGUP = 0x5437 + TOSTOP = 0x400000 + TUNATTACHFILTER = 0x800854d5 + TUNDETACHFILTER = 0x800854d6 + TUNGETDEVNETNS = 0x200054e3 + TUNGETFEATURES = 0x400454cf + TUNGETFILTER = 0x400854db + TUNGETIFF = 0x400454d2 + TUNGETSNDBUF = 0x400454d3 + TUNGETVNETBE = 0x400454df + TUNGETVNETHDRSZ = 0x400454d7 + TUNGETVNETLE = 0x400454dd + TUNSETCARRIER = 0x800454e2 + TUNSETDEBUG = 0x800454c9 + TUNSETFILTEREBPF = 0x400454e1 + TUNSETGROUP = 0x800454ce + TUNSETIFF = 0x800454ca + TUNSETIFINDEX = 0x800454da + TUNSETLINK = 0x800454cd + TUNSETNOCSUM = 0x800454c8 + TUNSETOFFLOAD = 0x800454d0 + TUNSETOWNER = 0x800454cc + TUNSETPERSIST = 0x800454cb + TUNSETQUEUE = 0x800454d9 + TUNSETSNDBUF = 0x800454d4 + TUNSETSTEERINGEBPF = 0x400454e0 + TUNSETTXFILTER = 0x800454d1 + TUNSETVNETBE = 0x800454de + TUNSETVNETHDRSZ = 0x800454d8 + TUNSETVNETLE = 0x800454dc + UBI_IOCATT = 0x80186f40 + UBI_IOCDET = 0x80046f41 + UBI_IOCEBCH = 0x80044f02 + UBI_IOCEBER = 0x80044f01 + UBI_IOCEBISMAP = 0x40044f05 + UBI_IOCEBMAP = 0x80084f03 + UBI_IOCEBUNMAP = 0x80044f04 + UBI_IOCMKVOL = 0x80986f00 + UBI_IOCRMVOL = 0x80046f01 + UBI_IOCRNVOL = 0x91106f03 + UBI_IOCRPEB = 0x80046f04 + UBI_IOCRSVOL = 0x800c6f02 + UBI_IOCSETVOLPROP = 0x80104f06 + UBI_IOCSPEB = 0x80046f05 + UBI_IOCVOLCRBLK = 0x80804f07 + UBI_IOCVOLRMBLK = 0x20004f08 + UBI_IOCVOLUP = 0x80084f00 + VDISCARD = 0x10 + VEOF = 0x4 + VEOL = 0x6 + VEOL2 = 0x8 + VMIN = 0x5 + VREPRINT = 0xb + VSTART = 0xd + VSTOP = 0xe + VSUSP = 0xc + VSWTC = 0x9 + VT1 = 0x10000 + VTDLY = 0x10000 + VTIME = 0x7 + VWERASE = 0xa + WDIOC_GETBOOTSTATUS = 0x40045702 + WDIOC_GETPRETIMEOUT = 0x40045709 + WDIOC_GETSTATUS = 0x40045701 + WDIOC_GETSUPPORT = 0x40285700 + WDIOC_GETTEMP = 0x40045703 + WDIOC_GETTIMELEFT = 0x4004570a + WDIOC_GETTIMEOUT = 0x40045707 + WDIOC_KEEPALIVE = 0x40045705 + WDIOC_SETOPTIONS = 0x40045704 + WORDSIZE = 0x20 + XCASE = 0x4000 + XTABS = 0xc00 + _HIDIOCGRAWNAME = 0x40804804 + _HIDIOCGRAWPHYS = 0x40404805 + _HIDIOCGRAWUNIQ = 0x40404808 +) + +// Errors +const ( + EADDRINUSE = syscall.Errno(0x62) + EADDRNOTAVAIL = syscall.Errno(0x63) + EADV = syscall.Errno(0x44) + EAFNOSUPPORT = syscall.Errno(0x61) + EALREADY = syscall.Errno(0x72) + EBADE = syscall.Errno(0x34) + EBADFD = syscall.Errno(0x4d) + EBADMSG = syscall.Errno(0x4a) + EBADR = syscall.Errno(0x35) + EBADRQC = syscall.Errno(0x38) + EBADSLT = syscall.Errno(0x39) + EBFONT = syscall.Errno(0x3b) + ECANCELED = syscall.Errno(0x7d) + ECHRNG = syscall.Errno(0x2c) + ECOMM = syscall.Errno(0x46) + ECONNABORTED = syscall.Errno(0x67) + ECONNREFUSED = syscall.Errno(0x6f) + ECONNRESET = syscall.Errno(0x68) + EDEADLK = syscall.Errno(0x23) + EDEADLOCK = syscall.Errno(0x3a) + EDESTADDRREQ = syscall.Errno(0x59) + EDOTDOT = syscall.Errno(0x49) + EDQUOT = syscall.Errno(0x7a) + EHOSTDOWN = syscall.Errno(0x70) + EHOSTUNREACH = syscall.Errno(0x71) + EHWPOISON = syscall.Errno(0x85) + EIDRM = syscall.Errno(0x2b) + EILSEQ = syscall.Errno(0x54) + EINPROGRESS = syscall.Errno(0x73) + EISCONN = syscall.Errno(0x6a) + EISNAM = syscall.Errno(0x78) + EKEYEXPIRED = syscall.Errno(0x7f) + EKEYREJECTED = syscall.Errno(0x81) + EKEYREVOKED = syscall.Errno(0x80) + EL2HLT = syscall.Errno(0x33) + EL2NSYNC = syscall.Errno(0x2d) + EL3HLT = syscall.Errno(0x2e) + EL3RST = syscall.Errno(0x2f) + ELIBACC = syscall.Errno(0x4f) + ELIBBAD = syscall.Errno(0x50) + ELIBEXEC = syscall.Errno(0x53) + ELIBMAX = syscall.Errno(0x52) + ELIBSCN = syscall.Errno(0x51) + ELNRNG = syscall.Errno(0x30) + ELOOP = syscall.Errno(0x28) + EMEDIUMTYPE = syscall.Errno(0x7c) + EMSGSIZE = syscall.Errno(0x5a) + EMULTIHOP = syscall.Errno(0x48) + ENAMETOOLONG = syscall.Errno(0x24) + ENAVAIL = syscall.Errno(0x77) + ENETDOWN = syscall.Errno(0x64) + ENETRESET = syscall.Errno(0x66) + ENETUNREACH = syscall.Errno(0x65) + ENOANO = syscall.Errno(0x37) + ENOBUFS = syscall.Errno(0x69) + ENOCSI = syscall.Errno(0x32) + ENODATA = syscall.Errno(0x3d) + ENOKEY = syscall.Errno(0x7e) + ENOLCK = syscall.Errno(0x25) + ENOLINK = syscall.Errno(0x43) + ENOMEDIUM = syscall.Errno(0x7b) + ENOMSG = syscall.Errno(0x2a) + ENONET = syscall.Errno(0x40) + ENOPKG = syscall.Errno(0x41) + ENOPROTOOPT = syscall.Errno(0x5c) + ENOSR = syscall.Errno(0x3f) + ENOSTR = syscall.Errno(0x3c) + ENOSYS = syscall.Errno(0x26) + ENOTCONN = syscall.Errno(0x6b) + ENOTEMPTY = syscall.Errno(0x27) + ENOTNAM = syscall.Errno(0x76) + ENOTRECOVERABLE = syscall.Errno(0x83) + ENOTSOCK = syscall.Errno(0x58) + ENOTSUP = syscall.Errno(0x5f) + ENOTUNIQ = syscall.Errno(0x4c) + EOPNOTSUPP = syscall.Errno(0x5f) + EOVERFLOW = syscall.Errno(0x4b) + EOWNERDEAD = syscall.Errno(0x82) + EPFNOSUPPORT = syscall.Errno(0x60) + EPROTO = syscall.Errno(0x47) + EPROTONOSUPPORT = syscall.Errno(0x5d) + EPROTOTYPE = syscall.Errno(0x5b) + EREMCHG = syscall.Errno(0x4e) + EREMOTE = syscall.Errno(0x42) + EREMOTEIO = syscall.Errno(0x79) + ERESTART = syscall.Errno(0x55) + ERFKILL = syscall.Errno(0x84) + ESHUTDOWN = syscall.Errno(0x6c) + ESOCKTNOSUPPORT = syscall.Errno(0x5e) + ESRMNT = syscall.Errno(0x45) + ESTALE = syscall.Errno(0x74) + ESTRPIPE = syscall.Errno(0x56) + ETIME = syscall.Errno(0x3e) + ETIMEDOUT = syscall.Errno(0x6e) + ETOOMANYREFS = syscall.Errno(0x6d) + EUCLEAN = syscall.Errno(0x75) + EUNATCH = syscall.Errno(0x31) + EUSERS = syscall.Errno(0x57) + EXFULL = syscall.Errno(0x36) +) + +// Signals +const ( + SIGBUS = syscall.Signal(0x7) + SIGCHLD = syscall.Signal(0x11) + SIGCLD = syscall.Signal(0x11) + SIGCONT = syscall.Signal(0x12) + SIGIO = syscall.Signal(0x1d) + SIGPOLL = syscall.Signal(0x1d) + SIGPROF = syscall.Signal(0x1b) + SIGPWR = syscall.Signal(0x1e) + SIGSTKFLT = syscall.Signal(0x10) + SIGSTOP = syscall.Signal(0x13) + SIGSYS = syscall.Signal(0x1f) + SIGTSTP = syscall.Signal(0x14) + SIGTTIN = syscall.Signal(0x15) + SIGTTOU = syscall.Signal(0x16) + SIGURG = syscall.Signal(0x17) + SIGUSR1 = syscall.Signal(0xa) + SIGUSR2 = syscall.Signal(0xc) + SIGVTALRM = syscall.Signal(0x1a) + SIGWINCH = syscall.Signal(0x1c) + SIGXCPU = syscall.Signal(0x18) + SIGXFSZ = syscall.Signal(0x19) +) + +// Error table +var errorList = [...]struct { + num syscall.Errno + name string + desc string +}{ + {1, "EPERM", "operation not permitted"}, + {2, "ENOENT", "no such file or directory"}, + {3, "ESRCH", "no such process"}, + {4, "EINTR", "interrupted system call"}, + {5, "EIO", "input/output error"}, + {6, "ENXIO", "no such device or address"}, + {7, "E2BIG", "argument list too long"}, + {8, "ENOEXEC", "exec format error"}, + {9, "EBADF", "bad file descriptor"}, + {10, "ECHILD", "no child processes"}, + {11, "EAGAIN", "resource temporarily unavailable"}, + {12, "ENOMEM", "cannot allocate memory"}, + {13, "EACCES", "permission denied"}, + {14, "EFAULT", "bad address"}, + {15, "ENOTBLK", "block device required"}, + {16, "EBUSY", "device or resource busy"}, + {17, "EEXIST", "file exists"}, + {18, "EXDEV", "invalid cross-device link"}, + {19, "ENODEV", "no such device"}, + {20, "ENOTDIR", "not a directory"}, + {21, "EISDIR", "is a directory"}, + {22, "EINVAL", "invalid argument"}, + {23, "ENFILE", "too many open files in system"}, + {24, "EMFILE", "too many open files"}, + {25, "ENOTTY", "inappropriate ioctl for device"}, + {26, "ETXTBSY", "text file busy"}, + {27, "EFBIG", "file too large"}, + {28, "ENOSPC", "no space left on device"}, + {29, "ESPIPE", "illegal seek"}, + {30, "EROFS", "read-only file system"}, + {31, "EMLINK", "too many links"}, + {32, "EPIPE", "broken pipe"}, + {33, "EDOM", "numerical argument out of domain"}, + {34, "ERANGE", "numerical result out of range"}, + {35, "EDEADLK", "resource deadlock avoided"}, + {36, "ENAMETOOLONG", "file name too long"}, + {37, "ENOLCK", "no locks available"}, + {38, "ENOSYS", "function not implemented"}, + {39, "ENOTEMPTY", "directory not empty"}, + {40, "ELOOP", "too many levels of symbolic links"}, + {42, "ENOMSG", "no message of desired type"}, + {43, "EIDRM", "identifier removed"}, + {44, "ECHRNG", "channel number out of range"}, + {45, "EL2NSYNC", "level 2 not synchronized"}, + {46, "EL3HLT", "level 3 halted"}, + {47, "EL3RST", "level 3 reset"}, + {48, "ELNRNG", "link number out of range"}, + {49, "EUNATCH", "protocol driver not attached"}, + {50, "ENOCSI", "no CSI structure available"}, + {51, "EL2HLT", "level 2 halted"}, + {52, "EBADE", "invalid exchange"}, + {53, "EBADR", "invalid request descriptor"}, + {54, "EXFULL", "exchange full"}, + {55, "ENOANO", "no anode"}, + {56, "EBADRQC", "invalid request code"}, + {57, "EBADSLT", "invalid slot"}, + {58, "EDEADLOCK", "file locking deadlock error"}, + {59, "EBFONT", "bad font file format"}, + {60, "ENOSTR", "device not a stream"}, + {61, "ENODATA", "no data available"}, + {62, "ETIME", "timer expired"}, + {63, "ENOSR", "out of streams resources"}, + {64, "ENONET", "machine is not on the network"}, + {65, "ENOPKG", "package not installed"}, + {66, "EREMOTE", "object is remote"}, + {67, "ENOLINK", "link has been severed"}, + {68, "EADV", "advertise error"}, + {69, "ESRMNT", "srmount error"}, + {70, "ECOMM", "communication error on send"}, + {71, "EPROTO", "protocol error"}, + {72, "EMULTIHOP", "multihop attempted"}, + {73, "EDOTDOT", "RFS specific error"}, + {74, "EBADMSG", "bad message"}, + {75, "EOVERFLOW", "value too large for defined data type"}, + {76, "ENOTUNIQ", "name not unique on network"}, + {77, "EBADFD", "file descriptor in bad state"}, + {78, "EREMCHG", "remote address changed"}, + {79, "ELIBACC", "can not access a needed shared library"}, + {80, "ELIBBAD", "accessing a corrupted shared library"}, + {81, "ELIBSCN", ".lib section in a.out corrupted"}, + {82, "ELIBMAX", "attempting to link in too many shared libraries"}, + {83, "ELIBEXEC", "cannot exec a shared library directly"}, + {84, "EILSEQ", "invalid or incomplete multibyte or wide character"}, + {85, "ERESTART", "interrupted system call should be restarted"}, + {86, "ESTRPIPE", "streams pipe error"}, + {87, "EUSERS", "too many users"}, + {88, "ENOTSOCK", "socket operation on non-socket"}, + {89, "EDESTADDRREQ", "destination address required"}, + {90, "EMSGSIZE", "message too long"}, + {91, "EPROTOTYPE", "protocol wrong type for socket"}, + {92, "ENOPROTOOPT", "protocol not available"}, + {93, "EPROTONOSUPPORT", "protocol not supported"}, + {94, "ESOCKTNOSUPPORT", "socket type not supported"}, + {95, "ENOTSUP", "operation not supported"}, + {96, "EPFNOSUPPORT", "protocol family not supported"}, + {97, "EAFNOSUPPORT", "address family not supported by protocol"}, + {98, "EADDRINUSE", "address already in use"}, + {99, "EADDRNOTAVAIL", "cannot assign requested address"}, + {100, "ENETDOWN", "network is down"}, + {101, "ENETUNREACH", "network is unreachable"}, + {102, "ENETRESET", "network dropped connection on reset"}, + {103, "ECONNABORTED", "software caused connection abort"}, + {104, "ECONNRESET", "connection reset by peer"}, + {105, "ENOBUFS", "no buffer space available"}, + {106, "EISCONN", "transport endpoint is already connected"}, + {107, "ENOTCONN", "transport endpoint is not connected"}, + {108, "ESHUTDOWN", "cannot send after transport endpoint shutdown"}, + {109, "ETOOMANYREFS", "too many references: cannot splice"}, + {110, "ETIMEDOUT", "connection timed out"}, + {111, "ECONNREFUSED", "connection refused"}, + {112, "EHOSTDOWN", "host is down"}, + {113, "EHOSTUNREACH", "no route to host"}, + {114, "EALREADY", "operation already in progress"}, + {115, "EINPROGRESS", "operation now in progress"}, + {116, "ESTALE", "stale file handle"}, + {117, "EUCLEAN", "structure needs cleaning"}, + {118, "ENOTNAM", "not a XENIX named type file"}, + {119, "ENAVAIL", "no XENIX semaphores available"}, + {120, "EISNAM", "is a named type file"}, + {121, "EREMOTEIO", "remote I/O error"}, + {122, "EDQUOT", "disk quota exceeded"}, + {123, "ENOMEDIUM", "no medium found"}, + {124, "EMEDIUMTYPE", "wrong medium type"}, + {125, "ECANCELED", "operation canceled"}, + {126, "ENOKEY", "required key not available"}, + {127, "EKEYEXPIRED", "key has expired"}, + {128, "EKEYREVOKED", "key has been revoked"}, + {129, "EKEYREJECTED", "key was rejected by service"}, + {130, "EOWNERDEAD", "owner died"}, + {131, "ENOTRECOVERABLE", "state not recoverable"}, + {132, "ERFKILL", "operation not possible due to RF-kill"}, + {133, "EHWPOISON", "memory page has hardware error"}, +} + +// Signal table +var signalList = [...]struct { + num syscall.Signal + name string + desc string +}{ + {1, "SIGHUP", "hangup"}, + {2, "SIGINT", "interrupt"}, + {3, "SIGQUIT", "quit"}, + {4, "SIGILL", "illegal instruction"}, + {5, "SIGTRAP", "trace/breakpoint trap"}, + {6, "SIGABRT", "aborted"}, + {7, "SIGBUS", "bus error"}, + {8, "SIGFPE", "floating point exception"}, + {9, "SIGKILL", "killed"}, + {10, "SIGUSR1", "user defined signal 1"}, + {11, "SIGSEGV", "segmentation fault"}, + {12, "SIGUSR2", "user defined signal 2"}, + {13, "SIGPIPE", "broken pipe"}, + {14, "SIGALRM", "alarm clock"}, + {15, "SIGTERM", "terminated"}, + {16, "SIGSTKFLT", "stack fault"}, + {17, "SIGCHLD", "child exited"}, + {18, "SIGCONT", "continued"}, + {19, "SIGSTOP", "stopped (signal)"}, + {20, "SIGTSTP", "stopped"}, + {21, "SIGTTIN", "stopped (tty input)"}, + {22, "SIGTTOU", "stopped (tty output)"}, + {23, "SIGURG", "urgent I/O condition"}, + {24, "SIGXCPU", "CPU time limit exceeded"}, + {25, "SIGXFSZ", "file size limit exceeded"}, + {26, "SIGVTALRM", "virtual timer expired"}, + {27, "SIGPROF", "profiling timer expired"}, + {28, "SIGWINCH", "window changed"}, + {29, "SIGIO", "I/O possible"}, + {30, "SIGPWR", "power failure"}, + {31, "SIGSYS", "bad system call"}, +} diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index a508392d2582..6d30e6fd846a 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -212,6 +212,8 @@ const ( PTRACE_POKE_SYSTEM_CALL = 0x5008 PTRACE_PROT = 0x15 PTRACE_SINGLEBLOCK = 0xc + PTRACE_SYSEMU = 0x1f + PTRACE_SYSEMU_SINGLESTEP = 0x20 PTRACE_TE_ABORT_RAND = 0x5011 PT_ACR0 = 0x90 PT_ACR1 = 0x94 diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go index 65fb2c5cd83c..1afee6a08905 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go @@ -366,6 +366,7 @@ const ( HUPCL = 0x400 IBSHIFT = 0x10 ICANON = 0x2 + ICMP6_FILTER = 0x1 ICRNL = 0x100 IEXTEN = 0x8000 IFF_ADDRCONF = 0x80000 @@ -612,6 +613,7 @@ const ( IP_RECVPKTINFO = 0x1a IP_RECVRETOPTS = 0x6 IP_RECVSLLA = 0xa + IP_RECVTOS = 0xc IP_RECVTTL = 0xb IP_RETOPTS = 0x8 IP_REUSEADDR = 0x104 @@ -704,6 +706,7 @@ const ( O_APPEND = 0x8 O_CLOEXEC = 0x800000 O_CREAT = 0x100 + O_DIRECT = 0x2000000 O_DIRECTORY = 0x1000000 O_DSYNC = 0x40 O_EXCL = 0x400 diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go index 4117ce08a506..fc7d0506f6c0 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go @@ -67,24 +67,43 @@ const ( IPPORT_RESERVED = 1024 IPPORT_USERRESERVED = 5000 IPPROTO_AH = 51 + SOL_AH = 51 IPPROTO_DSTOPTS = 60 + SOL_DSTOPTS = 60 IPPROTO_EGP = 8 + SOL_EGP = 8 IPPROTO_ESP = 50 + SOL_ESP = 50 IPPROTO_FRAGMENT = 44 + SOL_FRAGMENT = 44 IPPROTO_GGP = 2 + SOL_GGP = 2 IPPROTO_HOPOPTS = 0 + SOL_HOPOPTS = 0 IPPROTO_ICMP = 1 + SOL_ICMP = 1 IPPROTO_ICMPV6 = 58 + SOL_ICMPV6 = 58 IPPROTO_IDP = 22 + SOL_IDP = 22 IPPROTO_IP = 0 + SOL_IP = 0 IPPROTO_IPV6 = 41 + SOL_IPV6 = 41 IPPROTO_MAX = 256 + SOL_MAX = 256 IPPROTO_NONE = 59 + SOL_NONE = 59 IPPROTO_PUP = 12 + SOL_PUP = 12 IPPROTO_RAW = 255 + SOL_RAW = 255 IPPROTO_ROUTING = 43 + SOL_ROUTING = 43 IPPROTO_TCP = 6 + SOL_TCP = 6 IPPROTO_UDP = 17 + SOL_UDP = 17 IPV6_ADDR_PREFERENCES = 32 IPV6_CHECKSUM = 19 IPV6_DONTFRAG = 29 @@ -137,6 +156,7 @@ const ( IP_TTL = 3 IP_UNBLOCK_SOURCE = 11 ICANON = 0x0010 + ICMP6_FILTER = 0x26 ICRNL = 0x0002 IEXTEN = 0x0020 IGNBRK = 0x0004 @@ -163,6 +183,12 @@ const ( MAP_PRIVATE = 0x1 // changes are private MAP_SHARED = 0x2 // changes are shared MAP_FIXED = 0x4 // place exactly + MCAST_JOIN_GROUP = 40 + MCAST_LEAVE_GROUP = 41 + MCAST_JOIN_SOURCE_GROUP = 42 + MCAST_LEAVE_SOURCE_GROUP = 43 + MCAST_BLOCK_SOURCE = 44 + MCAST_UNBLOCK_SOURCE = 45 MS_SYNC = 0x1 // msync - synchronous writes MS_ASYNC = 0x2 // asynchronous writes MS_INVALIDATE = 0x4 // invalidate mappings @@ -179,6 +205,7 @@ const ( MTM_SYNCHONLY = 0x00000200 MTM_REMOUNT = 0x00000100 MTM_NOSECURITY = 0x00000080 + NFDBITS = 0x20 O_ACCMODE = 0x03 O_APPEND = 0x08 O_ASYNCSIG = 0x0200 @@ -352,6 +379,8 @@ const ( S_IFMST = 0x00FF0000 TCP_KEEPALIVE = 0x8 TCP_NODELAY = 0x1 + TCP_INFO = 0xb + TCP_USER_TIMEOUT = 0x1 TIOCGWINSZ = 0x4008a368 TIOCSWINSZ = 0x8008a367 TIOCSBRK = 0x2000a77b diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.s b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.s index 00da1ebfca12..1c73a1921d72 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_13.s @@ -1,6 +1,7 @@ // go run mkasm_darwin.go 386 // Code generated by the command above; DO NOT EDIT. +//go:build go1.13 // +build go1.13 #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s index 1c53979a101e..8cc7928d9294 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s @@ -1,6 +1,7 @@ // go run mkasm_darwin.go 386 // Code generated by the command above; DO NOT EDIT. +//go:build go1.12 // +build go1.12 #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s index d671e8311fa7..ab59833fcd28 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s @@ -1,6 +1,7 @@ // go run mkasm_darwin.go amd64 // Code generated by the command above; DO NOT EDIT. +//go:build go1.13 // +build go1.13 #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s index c77bd6e20bdc..b8f316e676d5 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -1,6 +1,7 @@ // go run mkasm_darwin.go amd64 // Code generated by the command above; DO NOT EDIT. +//go:build go1.12 // +build go1.12 #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.s b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.s index 488e55707ab1..0cc80ad87ea2 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_13.s @@ -1,6 +1,7 @@ // go run mkasm_darwin.go arm // Code generated by the command above; DO NOT EDIT. +//go:build go1.13 // +build go1.13 #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s index 5eec5f1d9534..a99f9c1113e2 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s @@ -1,6 +1,7 @@ // go run mkasm_darwin.go arm // Code generated by the command above; DO NOT EDIT. +//go:build go1.12 // +build go1.12 #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s index b29dabb0f084..a5f96ffb07d3 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s @@ -1,6 +1,7 @@ // go run mkasm_darwin.go arm64 // Code generated by the command above; DO NOT EDIT. +//go:build go1.13 // +build go1.13 #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s index 53c402bf68b5..e30a69740718 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -1,6 +1,7 @@ // go run mkasm_darwin.go arm64 // Code generated by the command above; DO NOT EDIT. +//go:build go1.12 // +build go1.12 #include "textflag.h" diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go new file mode 100644 index 000000000000..927cf1a00f0d --- /dev/null +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go @@ -0,0 +1,762 @@ +// go run mksyscall.go -b32 -tags linux,ppc syscall_linux.go syscall_linux_ppc.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +//go:build linux && ppc +// +build linux,ppc + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) { + _, _, e1 := Syscall6(SYS_FANOTIFY_MARK, uintptr(fd), uintptr(flags), uintptr(mask>>32), uintptr(mask), uintptr(dirFd), uintptr(unsafe.Pointer(pathname))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { + _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off>>32), uintptr(off), uintptr(len>>32), uintptr(len)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { + r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0) + n = int64(int64(r0)<<32 | int64(r1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func dup2(oldfd int, newfd int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT64, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, _, e1 := Syscall(SYS_FTRUNCATE64, uintptr(fd), uintptr(length>>32), uintptr(length)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (euid int) { + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) + euid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyInit() (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ioperm(from int, num int, on int) (err error) { + _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Iopl(level int) (err error) { + _, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, n int) (err error) { + _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pause() (err error) { + _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset>>32), uintptr(offset), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset>>32), uintptr(offset), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { + r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0) + written = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setfsgid(gid int) (prev int, err error) { + r0, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0) + prev = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setfsuid(uid int) (prev int, err error) { + r0, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0) + prev = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setresgid(rgid int, egid int, sgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setresuid(ruid int, euid int, suid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) { + r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), uintptr(length>>32), uintptr(length)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(n int, list *_Gid_t) (nn int, err error) { + r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0) + nn = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(n int, list *_Gid_t) (err error) { + _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Gettimeofday(tv *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Time(t *Time_t) (tt Time_t, err error) { + r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0) + tt = Time_t(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Utime(path string, buf *Utimbuf) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset)) + xaddr = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getrlimit(resource int, rlim *rlimit32) (err error) { + _, _, e1 := RawSyscall(SYS_UGETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setrlimit(resource int, rlim *rlimit32) (err error) { + _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe(p *[2]_C_int) (err error) { + _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func syncFileRange2(fd int, flags int, off int64, n int64) (err error) { + _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(flags), uintptr(off>>32), uintptr(off), uintptr(n>>32), uintptr(n)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(cmdline) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_KEXEC_FILE_LOAD, uintptr(kernelFd), uintptr(initrdFd), uintptr(cmdlineLen), uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go index 8285ab8419e2..f2079457c6b2 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go @@ -364,6 +364,22 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Errno2() (er2 int) { + uer2, _, _ := syscall_syscall(SYS___ERRNO2, 0, 0, 0) + er2 = int(uer2) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Err2ad() (eadd *int) { + ueadd, _, _ := syscall_syscall(SYS___ERR2AD, 0, 0, 0) + eadd = (*int)(unsafe.Pointer(ueadd)) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Exit(code int) { syscall_syscall(SYS_EXIT, uintptr(code), 0, 0) return @@ -531,7 +547,18 @@ func W_Getmntent(buff *byte, size int) (lastsys int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Mount(path string, filesystem string, fstype string, mtm uint32, parmlen int32, parm string) (err error) { +func W_Getmntent_A(buff *byte, size int) (lastsys int, err error) { + r0, _, e1 := syscall_syscall(SYS___W_GETMNTENT_A, uintptr(unsafe.Pointer(buff)), uintptr(size), 0) + lastsys = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mount_LE(path string, filesystem string, fstype string, mtm uint32, parmlen int32, parm string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) if err != nil { @@ -561,7 +588,7 @@ func Mount(path string, filesystem string, fstype string, mtm uint32, parmlen in // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Unmount(filesystem string, mtm int) (err error) { +func unmount(filesystem string, mtm int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(filesystem) if err != nil { @@ -1215,3 +1242,14 @@ func utimes(path string, timeval *[2]Timeval) (err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(nmsgsfds int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (ret int, err error) { + r0, _, e1 := syscall_syscall6(SYS_SELECT, uintptr(nmsgsfds), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go index 8e5359713489..fbc59b7fdd25 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go @@ -438,4 +438,5 @@ const ( SYS_FACCESSAT2 = 439 SYS_PROCESS_MADVISE = 440 SYS_EPOLL_PWAIT2 = 441 + SYS_MOUNT_SETATTR = 442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index d7dceb769b3f..04d16d771ef7 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -360,4 +360,5 @@ const ( SYS_FACCESSAT2 = 439 SYS_PROCESS_MADVISE = 440 SYS_EPOLL_PWAIT2 = 441 + SYS_MOUNT_SETATTR = 442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go index 04093a69fd8a..3b1c10513736 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go @@ -402,4 +402,5 @@ const ( SYS_FACCESSAT2 = 439 SYS_PROCESS_MADVISE = 440 SYS_EPOLL_PWAIT2 = 441 + SYS_MOUNT_SETATTR = 442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index 48f94f135d6d..3198adcf77a1 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -305,4 +305,5 @@ const ( SYS_FACCESSAT2 = 439 SYS_PROCESS_MADVISE = 440 SYS_EPOLL_PWAIT2 = 441 + SYS_MOUNT_SETATTR = 442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go index 499978c3e402..c877ec6e6821 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -423,4 +423,5 @@ const ( SYS_FACCESSAT2 = 4439 SYS_PROCESS_MADVISE = 4440 SYS_EPOLL_PWAIT2 = 4441 + SYS_MOUNT_SETATTR = 4442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go index 10d1db2be0ce..b5f29037299a 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go @@ -353,4 +353,5 @@ const ( SYS_FACCESSAT2 = 5439 SYS_PROCESS_MADVISE = 5440 SYS_EPOLL_PWAIT2 = 5441 + SYS_MOUNT_SETATTR = 5442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go index 208d5dcd5a32..46077689ab1f 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go @@ -353,4 +353,5 @@ const ( SYS_FACCESSAT2 = 5439 SYS_PROCESS_MADVISE = 5440 SYS_EPOLL_PWAIT2 = 5441 + SYS_MOUNT_SETATTR = 5442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go index f8250602eb8e..80e6696b39db 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -423,4 +423,5 @@ const ( SYS_FACCESSAT2 = 4439 SYS_PROCESS_MADVISE = 4440 SYS_EPOLL_PWAIT2 = 4441 + SYS_MOUNT_SETATTR = 4442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go new file mode 100644 index 000000000000..b9d697ffb1c0 --- /dev/null +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go @@ -0,0 +1,434 @@ +// go run linux/mksysnum.go -Wall -Werror -static -I/tmp/include /tmp/include/asm/unistd.h +// Code generated by the command above; see README.md. DO NOT EDIT. + +//go:build ppc && linux +// +build ppc,linux + +package unix + +const ( + SYS_RESTART_SYSCALL = 0 + SYS_EXIT = 1 + SYS_FORK = 2 + SYS_READ = 3 + SYS_WRITE = 4 + SYS_OPEN = 5 + SYS_CLOSE = 6 + SYS_WAITPID = 7 + SYS_CREAT = 8 + SYS_LINK = 9 + SYS_UNLINK = 10 + SYS_EXECVE = 11 + SYS_CHDIR = 12 + SYS_TIME = 13 + SYS_MKNOD = 14 + SYS_CHMOD = 15 + SYS_LCHOWN = 16 + SYS_BREAK = 17 + SYS_OLDSTAT = 18 + SYS_LSEEK = 19 + SYS_GETPID = 20 + SYS_MOUNT = 21 + SYS_UMOUNT = 22 + SYS_SETUID = 23 + SYS_GETUID = 24 + SYS_STIME = 25 + SYS_PTRACE = 26 + SYS_ALARM = 27 + SYS_OLDFSTAT = 28 + SYS_PAUSE = 29 + SYS_UTIME = 30 + SYS_STTY = 31 + SYS_GTTY = 32 + SYS_ACCESS = 33 + SYS_NICE = 34 + SYS_FTIME = 35 + SYS_SYNC = 36 + SYS_KILL = 37 + SYS_RENAME = 38 + SYS_MKDIR = 39 + SYS_RMDIR = 40 + SYS_DUP = 41 + SYS_PIPE = 42 + SYS_TIMES = 43 + SYS_PROF = 44 + SYS_BRK = 45 + SYS_SETGID = 46 + SYS_GETGID = 47 + SYS_SIGNAL = 48 + SYS_GETEUID = 49 + SYS_GETEGID = 50 + SYS_ACCT = 51 + SYS_UMOUNT2 = 52 + SYS_LOCK = 53 + SYS_IOCTL = 54 + SYS_FCNTL = 55 + SYS_MPX = 56 + SYS_SETPGID = 57 + SYS_ULIMIT = 58 + SYS_OLDOLDUNAME = 59 + SYS_UMASK = 60 + SYS_CHROOT = 61 + SYS_USTAT = 62 + SYS_DUP2 = 63 + SYS_GETPPID = 64 + SYS_GETPGRP = 65 + SYS_SETSID = 66 + SYS_SIGACTION = 67 + SYS_SGETMASK = 68 + SYS_SSETMASK = 69 + SYS_SETREUID = 70 + SYS_SETREGID = 71 + SYS_SIGSUSPEND = 72 + SYS_SIGPENDING = 73 + SYS_SETHOSTNAME = 74 + SYS_SETRLIMIT = 75 + SYS_GETRLIMIT = 76 + SYS_GETRUSAGE = 77 + SYS_GETTIMEOFDAY = 78 + SYS_SETTIMEOFDAY = 79 + SYS_GETGROUPS = 80 + SYS_SETGROUPS = 81 + SYS_SELECT = 82 + SYS_SYMLINK = 83 + SYS_OLDLSTAT = 84 + SYS_READLINK = 85 + SYS_USELIB = 86 + SYS_SWAPON = 87 + SYS_REBOOT = 88 + SYS_READDIR = 89 + SYS_MMAP = 90 + SYS_MUNMAP = 91 + SYS_TRUNCATE = 92 + SYS_FTRUNCATE = 93 + SYS_FCHMOD = 94 + SYS_FCHOWN = 95 + SYS_GETPRIORITY = 96 + SYS_SETPRIORITY = 97 + SYS_PROFIL = 98 + SYS_STATFS = 99 + SYS_FSTATFS = 100 + SYS_IOPERM = 101 + SYS_SOCKETCALL = 102 + SYS_SYSLOG = 103 + SYS_SETITIMER = 104 + SYS_GETITIMER = 105 + SYS_STAT = 106 + SYS_LSTAT = 107 + SYS_FSTAT = 108 + SYS_OLDUNAME = 109 + SYS_IOPL = 110 + SYS_VHANGUP = 111 + SYS_IDLE = 112 + SYS_VM86 = 113 + SYS_WAIT4 = 114 + SYS_SWAPOFF = 115 + SYS_SYSINFO = 116 + SYS_IPC = 117 + SYS_FSYNC = 118 + SYS_SIGRETURN = 119 + SYS_CLONE = 120 + SYS_SETDOMAINNAME = 121 + SYS_UNAME = 122 + SYS_MODIFY_LDT = 123 + SYS_ADJTIMEX = 124 + SYS_MPROTECT = 125 + SYS_SIGPROCMASK = 126 + SYS_CREATE_MODULE = 127 + SYS_INIT_MODULE = 128 + SYS_DELETE_MODULE = 129 + SYS_GET_KERNEL_SYMS = 130 + SYS_QUOTACTL = 131 + SYS_GETPGID = 132 + SYS_FCHDIR = 133 + SYS_BDFLUSH = 134 + SYS_SYSFS = 135 + SYS_PERSONALITY = 136 + SYS_AFS_SYSCALL = 137 + SYS_SETFSUID = 138 + SYS_SETFSGID = 139 + SYS__LLSEEK = 140 + SYS_GETDENTS = 141 + SYS__NEWSELECT = 142 + SYS_FLOCK = 143 + SYS_MSYNC = 144 + SYS_READV = 145 + SYS_WRITEV = 146 + SYS_GETSID = 147 + SYS_FDATASYNC = 148 + SYS__SYSCTL = 149 + SYS_MLOCK = 150 + SYS_MUNLOCK = 151 + SYS_MLOCKALL = 152 + SYS_MUNLOCKALL = 153 + SYS_SCHED_SETPARAM = 154 + SYS_SCHED_GETPARAM = 155 + SYS_SCHED_SETSCHEDULER = 156 + SYS_SCHED_GETSCHEDULER = 157 + SYS_SCHED_YIELD = 158 + SYS_SCHED_GET_PRIORITY_MAX = 159 + SYS_SCHED_GET_PRIORITY_MIN = 160 + SYS_SCHED_RR_GET_INTERVAL = 161 + SYS_NANOSLEEP = 162 + SYS_MREMAP = 163 + SYS_SETRESUID = 164 + SYS_GETRESUID = 165 + SYS_QUERY_MODULE = 166 + SYS_POLL = 167 + SYS_NFSSERVCTL = 168 + SYS_SETRESGID = 169 + SYS_GETRESGID = 170 + SYS_PRCTL = 171 + SYS_RT_SIGRETURN = 172 + SYS_RT_SIGACTION = 173 + SYS_RT_SIGPROCMASK = 174 + SYS_RT_SIGPENDING = 175 + SYS_RT_SIGTIMEDWAIT = 176 + SYS_RT_SIGQUEUEINFO = 177 + SYS_RT_SIGSUSPEND = 178 + SYS_PREAD64 = 179 + SYS_PWRITE64 = 180 + SYS_CHOWN = 181 + SYS_GETCWD = 182 + SYS_CAPGET = 183 + SYS_CAPSET = 184 + SYS_SIGALTSTACK = 185 + SYS_SENDFILE = 186 + SYS_GETPMSG = 187 + SYS_PUTPMSG = 188 + SYS_VFORK = 189 + SYS_UGETRLIMIT = 190 + SYS_READAHEAD = 191 + SYS_MMAP2 = 192 + SYS_TRUNCATE64 = 193 + SYS_FTRUNCATE64 = 194 + SYS_STAT64 = 195 + SYS_LSTAT64 = 196 + SYS_FSTAT64 = 197 + SYS_PCICONFIG_READ = 198 + SYS_PCICONFIG_WRITE = 199 + SYS_PCICONFIG_IOBASE = 200 + SYS_MULTIPLEXER = 201 + SYS_GETDENTS64 = 202 + SYS_PIVOT_ROOT = 203 + SYS_FCNTL64 = 204 + SYS_MADVISE = 205 + SYS_MINCORE = 206 + SYS_GETTID = 207 + SYS_TKILL = 208 + SYS_SETXATTR = 209 + SYS_LSETXATTR = 210 + SYS_FSETXATTR = 211 + SYS_GETXATTR = 212 + SYS_LGETXATTR = 213 + SYS_FGETXATTR = 214 + SYS_LISTXATTR = 215 + SYS_LLISTXATTR = 216 + SYS_FLISTXATTR = 217 + SYS_REMOVEXATTR = 218 + SYS_LREMOVEXATTR = 219 + SYS_FREMOVEXATTR = 220 + SYS_FUTEX = 221 + SYS_SCHED_SETAFFINITY = 222 + SYS_SCHED_GETAFFINITY = 223 + SYS_TUXCALL = 225 + SYS_SENDFILE64 = 226 + SYS_IO_SETUP = 227 + SYS_IO_DESTROY = 228 + SYS_IO_GETEVENTS = 229 + SYS_IO_SUBMIT = 230 + SYS_IO_CANCEL = 231 + SYS_SET_TID_ADDRESS = 232 + SYS_FADVISE64 = 233 + SYS_EXIT_GROUP = 234 + SYS_LOOKUP_DCOOKIE = 235 + SYS_EPOLL_CREATE = 236 + SYS_EPOLL_CTL = 237 + SYS_EPOLL_WAIT = 238 + SYS_REMAP_FILE_PAGES = 239 + SYS_TIMER_CREATE = 240 + SYS_TIMER_SETTIME = 241 + SYS_TIMER_GETTIME = 242 + SYS_TIMER_GETOVERRUN = 243 + SYS_TIMER_DELETE = 244 + SYS_CLOCK_SETTIME = 245 + SYS_CLOCK_GETTIME = 246 + SYS_CLOCK_GETRES = 247 + SYS_CLOCK_NANOSLEEP = 248 + SYS_SWAPCONTEXT = 249 + SYS_TGKILL = 250 + SYS_UTIMES = 251 + SYS_STATFS64 = 252 + SYS_FSTATFS64 = 253 + SYS_FADVISE64_64 = 254 + SYS_RTAS = 255 + SYS_SYS_DEBUG_SETCONTEXT = 256 + SYS_MIGRATE_PAGES = 258 + SYS_MBIND = 259 + SYS_GET_MEMPOLICY = 260 + SYS_SET_MEMPOLICY = 261 + SYS_MQ_OPEN = 262 + SYS_MQ_UNLINK = 263 + SYS_MQ_TIMEDSEND = 264 + SYS_MQ_TIMEDRECEIVE = 265 + SYS_MQ_NOTIFY = 266 + SYS_MQ_GETSETATTR = 267 + SYS_KEXEC_LOAD = 268 + SYS_ADD_KEY = 269 + SYS_REQUEST_KEY = 270 + SYS_KEYCTL = 271 + SYS_WAITID = 272 + SYS_IOPRIO_SET = 273 + SYS_IOPRIO_GET = 274 + SYS_INOTIFY_INIT = 275 + SYS_INOTIFY_ADD_WATCH = 276 + SYS_INOTIFY_RM_WATCH = 277 + SYS_SPU_RUN = 278 + SYS_SPU_CREATE = 279 + SYS_PSELECT6 = 280 + SYS_PPOLL = 281 + SYS_UNSHARE = 282 + SYS_SPLICE = 283 + SYS_TEE = 284 + SYS_VMSPLICE = 285 + SYS_OPENAT = 286 + SYS_MKDIRAT = 287 + SYS_MKNODAT = 288 + SYS_FCHOWNAT = 289 + SYS_FUTIMESAT = 290 + SYS_FSTATAT64 = 291 + SYS_UNLINKAT = 292 + SYS_RENAMEAT = 293 + SYS_LINKAT = 294 + SYS_SYMLINKAT = 295 + SYS_READLINKAT = 296 + SYS_FCHMODAT = 297 + SYS_FACCESSAT = 298 + SYS_GET_ROBUST_LIST = 299 + SYS_SET_ROBUST_LIST = 300 + SYS_MOVE_PAGES = 301 + SYS_GETCPU = 302 + SYS_EPOLL_PWAIT = 303 + SYS_UTIMENSAT = 304 + SYS_SIGNALFD = 305 + SYS_TIMERFD_CREATE = 306 + SYS_EVENTFD = 307 + SYS_SYNC_FILE_RANGE2 = 308 + SYS_FALLOCATE = 309 + SYS_SUBPAGE_PROT = 310 + SYS_TIMERFD_SETTIME = 311 + SYS_TIMERFD_GETTIME = 312 + SYS_SIGNALFD4 = 313 + SYS_EVENTFD2 = 314 + SYS_EPOLL_CREATE1 = 315 + SYS_DUP3 = 316 + SYS_PIPE2 = 317 + SYS_INOTIFY_INIT1 = 318 + SYS_PERF_EVENT_OPEN = 319 + SYS_PREADV = 320 + SYS_PWRITEV = 321 + SYS_RT_TGSIGQUEUEINFO = 322 + SYS_FANOTIFY_INIT = 323 + SYS_FANOTIFY_MARK = 324 + SYS_PRLIMIT64 = 325 + SYS_SOCKET = 326 + SYS_BIND = 327 + SYS_CONNECT = 328 + SYS_LISTEN = 329 + SYS_ACCEPT = 330 + SYS_GETSOCKNAME = 331 + SYS_GETPEERNAME = 332 + SYS_SOCKETPAIR = 333 + SYS_SEND = 334 + SYS_SENDTO = 335 + SYS_RECV = 336 + SYS_RECVFROM = 337 + SYS_SHUTDOWN = 338 + SYS_SETSOCKOPT = 339 + SYS_GETSOCKOPT = 340 + SYS_SENDMSG = 341 + SYS_RECVMSG = 342 + SYS_RECVMMSG = 343 + SYS_ACCEPT4 = 344 + SYS_NAME_TO_HANDLE_AT = 345 + SYS_OPEN_BY_HANDLE_AT = 346 + SYS_CLOCK_ADJTIME = 347 + SYS_SYNCFS = 348 + SYS_SENDMMSG = 349 + SYS_SETNS = 350 + SYS_PROCESS_VM_READV = 351 + SYS_PROCESS_VM_WRITEV = 352 + SYS_FINIT_MODULE = 353 + SYS_KCMP = 354 + SYS_SCHED_SETATTR = 355 + SYS_SCHED_GETATTR = 356 + SYS_RENAMEAT2 = 357 + SYS_SECCOMP = 358 + SYS_GETRANDOM = 359 + SYS_MEMFD_CREATE = 360 + SYS_BPF = 361 + SYS_EXECVEAT = 362 + SYS_SWITCH_ENDIAN = 363 + SYS_USERFAULTFD = 364 + SYS_MEMBARRIER = 365 + SYS_MLOCK2 = 378 + SYS_COPY_FILE_RANGE = 379 + SYS_PREADV2 = 380 + SYS_PWRITEV2 = 381 + SYS_KEXEC_FILE_LOAD = 382 + SYS_STATX = 383 + SYS_PKEY_ALLOC = 384 + SYS_PKEY_FREE = 385 + SYS_PKEY_MPROTECT = 386 + SYS_RSEQ = 387 + SYS_IO_PGETEVENTS = 388 + SYS_SEMGET = 393 + SYS_SEMCTL = 394 + SYS_SHMGET = 395 + SYS_SHMCTL = 396 + SYS_SHMAT = 397 + SYS_SHMDT = 398 + SYS_MSGGET = 399 + SYS_MSGSND = 400 + SYS_MSGRCV = 401 + SYS_MSGCTL = 402 + SYS_CLOCK_GETTIME64 = 403 + SYS_CLOCK_SETTIME64 = 404 + SYS_CLOCK_ADJTIME64 = 405 + SYS_CLOCK_GETRES_TIME64 = 406 + SYS_CLOCK_NANOSLEEP_TIME64 = 407 + SYS_TIMER_GETTIME64 = 408 + SYS_TIMER_SETTIME64 = 409 + SYS_TIMERFD_GETTIME64 = 410 + SYS_TIMERFD_SETTIME64 = 411 + SYS_UTIMENSAT_TIME64 = 412 + SYS_PSELECT6_TIME64 = 413 + SYS_PPOLL_TIME64 = 414 + SYS_IO_PGETEVENTS_TIME64 = 416 + SYS_RECVMMSG_TIME64 = 417 + SYS_MQ_TIMEDSEND_TIME64 = 418 + SYS_MQ_TIMEDRECEIVE_TIME64 = 419 + SYS_SEMTIMEDOP_TIME64 = 420 + SYS_RT_SIGTIMEDWAIT_TIME64 = 421 + SYS_FUTEX_TIME64 = 422 + SYS_SCHED_RR_GET_INTERVAL_TIME64 = 423 + SYS_PIDFD_SEND_SIGNAL = 424 + SYS_IO_URING_SETUP = 425 + SYS_IO_URING_ENTER = 426 + SYS_IO_URING_REGISTER = 427 + SYS_OPEN_TREE = 428 + SYS_MOVE_MOUNT = 429 + SYS_FSOPEN = 430 + SYS_FSCONFIG = 431 + SYS_FSMOUNT = 432 + SYS_FSPICK = 433 + SYS_PIDFD_OPEN = 434 + SYS_CLONE3 = 435 + SYS_CLOSE_RANGE = 436 + SYS_OPENAT2 = 437 + SYS_PIDFD_GETFD = 438 + SYS_FACCESSAT2 = 439 + SYS_PROCESS_MADVISE = 440 + SYS_EPOLL_PWAIT2 = 441 + SYS_MOUNT_SETATTR = 442 +) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go index d5ed3ff5100e..08edc54d35de 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go @@ -402,4 +402,5 @@ const ( SYS_FACCESSAT2 = 439 SYS_PROCESS_MADVISE = 440 SYS_EPOLL_PWAIT2 = 441 + SYS_MOUNT_SETATTR = 442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go index e29b4424c245..33b33b08342d 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go @@ -402,4 +402,5 @@ const ( SYS_FACCESSAT2 = 439 SYS_PROCESS_MADVISE = 440 SYS_EPOLL_PWAIT2 = 441 + SYS_MOUNT_SETATTR = 442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index 41deed6c3a57..66c8a8e09e1a 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -304,4 +304,5 @@ const ( SYS_FACCESSAT2 = 439 SYS_PROCESS_MADVISE = 440 SYS_EPOLL_PWAIT2 = 441 + SYS_MOUNT_SETATTR = 442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index 8e53a9e8ceb6..aea5760cea26 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -367,4 +367,5 @@ const ( SYS_FACCESSAT2 = 439 SYS_PROCESS_MADVISE = 440 SYS_EPOLL_PWAIT2 = 441 + SYS_MOUNT_SETATTR = 442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index 596e5bc7d357..488ca848d176 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -381,4 +381,5 @@ const ( SYS_FACCESSAT2 = 439 SYS_PROCESS_MADVISE = 440 SYS_EPOLL_PWAIT2 = 441 + SYS_MOUNT_SETATTR = 442 ) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go index 54db43335554..883b64a27236 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go @@ -221,6 +221,12 @@ type IPMreq struct { Interface [4]byte /* in_addr */ } +type IPMreqn struct { + Multiaddr [4]byte /* in_addr */ + Address [4]byte /* in_addr */ + Ifindex int32 +} + type IPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 @@ -272,6 +278,7 @@ const ( SizeofLinger = 0x8 SizeofIovec = 0x8 SizeofIPMreq = 0x8 + SizeofIPMreqn = 0xc SizeofIPv6Mreq = 0x14 SizeofMsghdr = 0x1c SizeofCmsghdr = 0xc diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go index eb73e52fb68c..2673e6c5909c 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go @@ -233,6 +233,12 @@ type IPMreq struct { Interface [4]byte /* in_addr */ } +type IPMreqn struct { + Multiaddr [4]byte /* in_addr */ + Address [4]byte /* in_addr */ + Ifindex int32 +} + type IPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 @@ -285,6 +291,7 @@ const ( SizeofLinger = 0x8 SizeofIovec = 0x10 SizeofIPMreq = 0x8 + SizeofIPMreqn = 0xc SizeofIPv6Mreq = 0x14 SizeofMsghdr = 0x30 SizeofCmsghdr = 0xc diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go index 8606d654e568..eef513385744 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go @@ -221,6 +221,12 @@ type IPMreq struct { Interface [4]byte /* in_addr */ } +type IPMreqn struct { + Multiaddr [4]byte /* in_addr */ + Address [4]byte /* in_addr */ + Ifindex int32 +} + type IPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 @@ -272,6 +278,7 @@ const ( SizeofLinger = 0x8 SizeofIovec = 0x8 SizeofIPMreq = 0x8 + SizeofIPMreqn = 0xc SizeofIPv6Mreq = 0x14 SizeofMsghdr = 0x1c SizeofCmsghdr = 0xc diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go index dcb51f8404d6..1465cbcffe47 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go @@ -233,6 +233,12 @@ type IPMreq struct { Interface [4]byte /* in_addr */ } +type IPMreqn struct { + Multiaddr [4]byte /* in_addr */ + Address [4]byte /* in_addr */ + Ifindex int32 +} + type IPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 @@ -285,6 +291,7 @@ const ( SizeofLinger = 0x8 SizeofIovec = 0x10 SizeofIPMreq = 0x8 + SizeofIPMreqn = 0xc SizeofIPv6Mreq = 0x14 SizeofMsghdr = 0x30 SizeofCmsghdr = 0xc diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_illumos_amd64.go b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_illumos_amd64.go index 1137a5a1f4b5..236f37ef6f7e 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_illumos_amd64.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_illumos_amd64.go @@ -25,14 +25,14 @@ type strbuf struct { Buf *int8 } -type strioctl struct { +type Strioctl struct { Cmd int32 Timout int32 Len int32 Dp *int8 } -type lifreq struct { +type Lifreq struct { Name [32]int8 Lifru1 [4]byte Type uint32 diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_linux.go b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_linux.go index c769e73cd6f2..087323591e61 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -1016,7 +1016,10 @@ const ( PERF_SAMPLE_PHYS_ADDR = 0x80000 PERF_SAMPLE_AUX = 0x100000 PERF_SAMPLE_CGROUP = 0x200000 - PERF_SAMPLE_MAX = 0x1000000 + PERF_SAMPLE_DATA_PAGE_SIZE = 0x400000 + PERF_SAMPLE_CODE_PAGE_SIZE = 0x800000 + PERF_SAMPLE_WEIGHT_STRUCT = 0x1000000 + PERF_SAMPLE_MAX = 0x2000000 PERF_SAMPLE_BRANCH_USER_SHIFT = 0x0 PERF_SAMPLE_BRANCH_KERNEL_SHIFT = 0x1 PERF_SAMPLE_BRANCH_HV_SHIFT = 0x2 @@ -3126,7 +3129,8 @@ const ( DEVLINK_ATTR_REMOTE_RELOAD_STATS = 0xa1 DEVLINK_ATTR_RELOAD_ACTION_INFO = 0xa2 DEVLINK_ATTR_RELOAD_ACTION_STATS = 0xa3 - DEVLINK_ATTR_MAX = 0xa3 + DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 0xa4 + DEVLINK_ATTR_MAX = 0xa4 DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE = 0x0 DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX = 0x1 DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT = 0x0 @@ -3140,7 +3144,9 @@ const ( DEVLINK_RESOURCE_UNIT_ENTRY = 0x0 DEVLINK_PORT_FUNCTION_ATTR_UNSPEC = 0x0 DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR = 0x1 - DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x1 + DEVLINK_PORT_FN_ATTR_STATE = 0x2 + DEVLINK_PORT_FN_ATTR_OPSTATE = 0x3 + DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x3 ) type FsverityDigest struct { @@ -3509,7 +3515,8 @@ const ( ETHTOOL_A_LINKMODES_DUPLEX = 0x6 ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG = 0x7 ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE = 0x8 - ETHTOOL_A_LINKMODES_MAX = 0x8 + ETHTOOL_A_LINKMODES_LANES = 0x9 + ETHTOOL_A_LINKMODES_MAX = 0x9 ETHTOOL_A_LINKSTATE_UNSPEC = 0x0 ETHTOOL_A_LINKSTATE_HEADER = 0x1 ETHTOOL_A_LINKSTATE_LINK = 0x2 @@ -3698,6 +3705,21 @@ const ( ETHTOOL_A_TUNNEL_INFO_MAX = 0x2 ) +type EthtoolDrvinfo struct { + Cmd uint32 + Driver [32]byte + Version [32]byte + Fw_version [32]byte + Bus_info [32]byte + Erom_version [32]byte + Reserved2 [12]byte + N_priv_flags uint32 + N_stats uint32 + Testinfo_len uint32 + Eedump_len uint32 + Regdump_len uint32 +} + type ( HIDRawReportDescriptor struct { Size uint32 diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go new file mode 100644 index 000000000000..af7a72017e9f --- /dev/null +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go @@ -0,0 +1,627 @@ +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// Code generated by the command above; see README.md. DO NOT EDIT. + +//go:build ppc && linux +// +build ppc,linux + +package unix + +const ( + SizeofPtr = 0x4 + SizeofLong = 0x4 +) + +type ( + _C_long int32 +) + +type Timespec struct { + Sec int32 + Nsec int32 +} + +type Timeval struct { + Sec int32 + Usec int32 +} + +type Timex struct { + Modes uint32 + Offset int32 + Freq int32 + Maxerror int32 + Esterror int32 + Status int32 + Constant int32 + Precision int32 + Tolerance int32 + Time Timeval + Tick int32 + Ppsfreq int32 + Jitter int32 + Shift int32 + Stabil int32 + Jitcnt int32 + Calcnt int32 + Errcnt int32 + Stbcnt int32 + Tai int32 + _ [44]byte +} + +type Time_t int32 + +type Tms struct { + Utime int32 + Stime int32 + Cutime int32 + Cstime int32 +} + +type Utimbuf struct { + Actime int32 + Modtime int32 +} + +type Rusage struct { + Utime Timeval + Stime Timeval + Maxrss int32 + Ixrss int32 + Idrss int32 + Isrss int32 + Minflt int32 + Majflt int32 + Nswap int32 + Inblock int32 + Oublock int32 + Msgsnd int32 + Msgrcv int32 + Nsignals int32 + Nvcsw int32 + Nivcsw int32 +} + +type Stat_t struct { + Dev uint64 + Ino uint64 + Mode uint32 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev uint64 + _ uint16 + _ [4]byte + Size int64 + Blksize int32 + _ [4]byte + Blocks int64 + Atim Timespec + Mtim Timespec + Ctim Timespec + _ uint32 + _ uint32 +} + +type Dirent struct { + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]uint8 + _ [5]byte +} + +type Flock_t struct { + Type int16 + Whence int16 + _ [4]byte + Start int64 + Len int64 + Pid int32 + _ [4]byte +} + +type DmNameList struct { + Dev uint64 + Next uint32 + Name [0]byte + _ [4]byte +} + +const ( + FADV_DONTNEED = 0x4 + FADV_NOREUSE = 0x5 +) + +type RawSockaddr struct { + Family uint16 + Data [14]uint8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [96]uint8 +} + +type Iovec struct { + Base *byte + Len uint32 +} + +type Msghdr struct { + Name *byte + Namelen uint32 + Iov *Iovec + Iovlen uint32 + Control *byte + Controllen uint32 + Flags int32 +} + +type Cmsghdr struct { + Len uint32 + Level int32 + Type int32 +} + +const ( + SizeofIovec = 0x8 + SizeofMsghdr = 0x1c + SizeofCmsghdr = 0xc +) + +const ( + SizeofSockFprog = 0x8 +) + +type PtraceRegs struct { + Gpr [32]uint32 + Nip uint32 + Msr uint32 + Orig_gpr3 uint32 + Ctr uint32 + Link uint32 + Xer uint32 + Ccr uint32 + Mq uint32 + Trap uint32 + Dar uint32 + Dsisr uint32 + Result uint32 +} + +type FdSet struct { + Bits [32]int32 +} + +type Sysinfo_t struct { + Uptime int32 + Loads [3]uint32 + Totalram uint32 + Freeram uint32 + Sharedram uint32 + Bufferram uint32 + Totalswap uint32 + Freeswap uint32 + Procs uint16 + Pad uint16 + Totalhigh uint32 + Freehigh uint32 + Unit uint32 + _ [8]uint8 +} + +type Ustat_t struct { + Tfree int32 + Tinode uint32 + Fname [6]uint8 + Fpack [6]uint8 +} + +type EpollEvent struct { + Events uint32 + _ int32 + Fd int32 + Pad int32 +} + +const ( + POLLRDHUP = 0x2000 +) + +type Sigset_t struct { + Val [32]uint32 +} + +const _C__NSIG = 0x41 + +type Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [19]uint8 + Line uint8 + Ispeed uint32 + Ospeed uint32 +} + +type Taskstats struct { + Version uint16 + Ac_exitcode uint32 + Ac_flag uint8 + Ac_nice uint8 + _ [4]byte + Cpu_count uint64 + Cpu_delay_total uint64 + Blkio_count uint64 + Blkio_delay_total uint64 + Swapin_count uint64 + Swapin_delay_total uint64 + Cpu_run_real_total uint64 + Cpu_run_virtual_total uint64 + Ac_comm [32]uint8 + Ac_sched uint8 + Ac_pad [3]uint8 + _ [4]byte + Ac_uid uint32 + Ac_gid uint32 + Ac_pid uint32 + Ac_ppid uint32 + Ac_btime uint32 + _ [4]byte + Ac_etime uint64 + Ac_utime uint64 + Ac_stime uint64 + Ac_minflt uint64 + Ac_majflt uint64 + Coremem uint64 + Virtmem uint64 + Hiwater_rss uint64 + Hiwater_vm uint64 + Read_char uint64 + Write_char uint64 + Read_syscalls uint64 + Write_syscalls uint64 + Read_bytes uint64 + Write_bytes uint64 + Cancelled_write_bytes uint64 + Nvcsw uint64 + Nivcsw uint64 + Ac_utimescaled uint64 + Ac_stimescaled uint64 + Cpu_scaled_run_real_total uint64 + Freepages_count uint64 + Freepages_delay_total uint64 + Thrashing_count uint64 + Thrashing_delay_total uint64 + Ac_btime64 uint64 +} + +type cpuMask uint32 + +const ( + _NCPUBITS = 0x20 +) + +const ( + CBitFieldMaskBit0 = 0x8000000000000000 + CBitFieldMaskBit1 = 0x4000000000000000 + CBitFieldMaskBit2 = 0x2000000000000000 + CBitFieldMaskBit3 = 0x1000000000000000 + CBitFieldMaskBit4 = 0x800000000000000 + CBitFieldMaskBit5 = 0x400000000000000 + CBitFieldMaskBit6 = 0x200000000000000 + CBitFieldMaskBit7 = 0x100000000000000 + CBitFieldMaskBit8 = 0x80000000000000 + CBitFieldMaskBit9 = 0x40000000000000 + CBitFieldMaskBit10 = 0x20000000000000 + CBitFieldMaskBit11 = 0x10000000000000 + CBitFieldMaskBit12 = 0x8000000000000 + CBitFieldMaskBit13 = 0x4000000000000 + CBitFieldMaskBit14 = 0x2000000000000 + CBitFieldMaskBit15 = 0x1000000000000 + CBitFieldMaskBit16 = 0x800000000000 + CBitFieldMaskBit17 = 0x400000000000 + CBitFieldMaskBit18 = 0x200000000000 + CBitFieldMaskBit19 = 0x100000000000 + CBitFieldMaskBit20 = 0x80000000000 + CBitFieldMaskBit21 = 0x40000000000 + CBitFieldMaskBit22 = 0x20000000000 + CBitFieldMaskBit23 = 0x10000000000 + CBitFieldMaskBit24 = 0x8000000000 + CBitFieldMaskBit25 = 0x4000000000 + CBitFieldMaskBit26 = 0x2000000000 + CBitFieldMaskBit27 = 0x1000000000 + CBitFieldMaskBit28 = 0x800000000 + CBitFieldMaskBit29 = 0x400000000 + CBitFieldMaskBit30 = 0x200000000 + CBitFieldMaskBit31 = 0x100000000 + CBitFieldMaskBit32 = 0x80000000 + CBitFieldMaskBit33 = 0x40000000 + CBitFieldMaskBit34 = 0x20000000 + CBitFieldMaskBit35 = 0x10000000 + CBitFieldMaskBit36 = 0x8000000 + CBitFieldMaskBit37 = 0x4000000 + CBitFieldMaskBit38 = 0x2000000 + CBitFieldMaskBit39 = 0x1000000 + CBitFieldMaskBit40 = 0x800000 + CBitFieldMaskBit41 = 0x400000 + CBitFieldMaskBit42 = 0x200000 + CBitFieldMaskBit43 = 0x100000 + CBitFieldMaskBit44 = 0x80000 + CBitFieldMaskBit45 = 0x40000 + CBitFieldMaskBit46 = 0x20000 + CBitFieldMaskBit47 = 0x10000 + CBitFieldMaskBit48 = 0x8000 + CBitFieldMaskBit49 = 0x4000 + CBitFieldMaskBit50 = 0x2000 + CBitFieldMaskBit51 = 0x1000 + CBitFieldMaskBit52 = 0x800 + CBitFieldMaskBit53 = 0x400 + CBitFieldMaskBit54 = 0x200 + CBitFieldMaskBit55 = 0x100 + CBitFieldMaskBit56 = 0x80 + CBitFieldMaskBit57 = 0x40 + CBitFieldMaskBit58 = 0x20 + CBitFieldMaskBit59 = 0x10 + CBitFieldMaskBit60 = 0x8 + CBitFieldMaskBit61 = 0x4 + CBitFieldMaskBit62 = 0x2 + CBitFieldMaskBit63 = 0x1 +) + +type SockaddrStorage struct { + Family uint16 + _ [122]uint8 + _ uint32 +} + +type HDGeometry struct { + Heads uint8 + Sectors uint8 + Cylinders uint16 + Start uint32 +} + +type Statfs_t struct { + Type int32 + Bsize int32 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid Fsid + Namelen int32 + Frsize int32 + Flags int32 + Spare [4]int32 + _ [4]byte +} + +type TpacketHdr struct { + Status uint32 + Len uint32 + Snaplen uint32 + Mac uint16 + Net uint16 + Sec uint32 + Usec uint32 +} + +const ( + SizeofTpacketHdr = 0x18 +) + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int32 +} + +type BlkpgPartition struct { + Start int64 + Length int64 + Pno int32 + Devname [64]uint8 + Volname [64]uint8 + _ [4]byte +} + +const ( + BLKPG = 0x20001269 +) + +type XDPUmemReg struct { + Addr uint64 + Len uint64 + Size uint32 + Headroom uint32 + Flags uint32 + _ [4]byte +} + +type CryptoUserAlg struct { + Name [64]uint8 + Driver_name [64]uint8 + Module_name [64]uint8 + Type uint32 + Mask uint32 + Refcnt uint32 + Flags uint32 +} + +type CryptoStatAEAD struct { + Type [64]uint8 + Encrypt_cnt uint64 + Encrypt_tlen uint64 + Decrypt_cnt uint64 + Decrypt_tlen uint64 + Err_cnt uint64 +} + +type CryptoStatAKCipher struct { + Type [64]uint8 + Encrypt_cnt uint64 + Encrypt_tlen uint64 + Decrypt_cnt uint64 + Decrypt_tlen uint64 + Verify_cnt uint64 + Sign_cnt uint64 + Err_cnt uint64 +} + +type CryptoStatCipher struct { + Type [64]uint8 + Encrypt_cnt uint64 + Encrypt_tlen uint64 + Decrypt_cnt uint64 + Decrypt_tlen uint64 + Err_cnt uint64 +} + +type CryptoStatCompress struct { + Type [64]uint8 + Compress_cnt uint64 + Compress_tlen uint64 + Decompress_cnt uint64 + Decompress_tlen uint64 + Err_cnt uint64 +} + +type CryptoStatHash struct { + Type [64]uint8 + Hash_cnt uint64 + Hash_tlen uint64 + Err_cnt uint64 +} + +type CryptoStatKPP struct { + Type [64]uint8 + Setsecret_cnt uint64 + Generate_public_key_cnt uint64 + Compute_shared_secret_cnt uint64 + Err_cnt uint64 +} + +type CryptoStatRNG struct { + Type [64]uint8 + Generate_cnt uint64 + Generate_tlen uint64 + Seed_cnt uint64 + Err_cnt uint64 +} + +type CryptoStatLarval struct { + Type [64]uint8 +} + +type CryptoReportLarval struct { + Type [64]uint8 +} + +type CryptoReportHash struct { + Type [64]uint8 + Blocksize uint32 + Digestsize uint32 +} + +type CryptoReportCipher struct { + Type [64]uint8 + Blocksize uint32 + Min_keysize uint32 + Max_keysize uint32 +} + +type CryptoReportBlkCipher struct { + Type [64]uint8 + Geniv [64]uint8 + Blocksize uint32 + Min_keysize uint32 + Max_keysize uint32 + Ivsize uint32 +} + +type CryptoReportAEAD struct { + Type [64]uint8 + Geniv [64]uint8 + Blocksize uint32 + Maxauthsize uint32 + Ivsize uint32 +} + +type CryptoReportComp struct { + Type [64]uint8 +} + +type CryptoReportRNG struct { + Type [64]uint8 + Seedsize uint32 +} + +type CryptoReportAKCipher struct { + Type [64]uint8 +} + +type CryptoReportKPP struct { + Type [64]uint8 +} + +type CryptoReportAcomp struct { + Type [64]uint8 +} + +type LoopInfo struct { + Number int32 + Device uint32 + Inode uint32 + Rdevice uint32 + Offset int32 + Encrypt_type int32 + Encrypt_key_size int32 + Flags int32 + Name [64]uint8 + Encrypt_key [32]uint8 + Init [2]uint32 + Reserved [4]uint8 +} + +type TIPCSubscr struct { + Seq TIPCServiceRange + Timeout uint32 + Filter uint32 + Handle [8]uint8 +} + +type TIPCSIOCLNReq struct { + Peer uint32 + Id uint32 + Linkname [68]uint8 +} + +type TIPCSIOCNodeIDReq struct { + Peer uint32 + Id [16]uint8 +} + +type PPSKInfo struct { + Assert_sequence uint32 + Clear_sequence uint32 + Assert_tu PPSKTime + Clear_tu PPSKTime + Current_mode int32 + _ [4]byte +} + +const ( + PPS_GETPARAMS = 0x400470a1 + PPS_SETPARAMS = 0x800470a2 + PPS_GETCAP = 0x400470a3 + PPS_FETCH = 0xc00470a4 +) diff --git a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go index 8bffde78e58b..4ab638cb94c7 100644 --- a/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go +++ b/awsproviderlint/vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go @@ -347,6 +347,10 @@ type Dirent struct { Name [256]byte } +type FdSet struct { + Bits [64]int32 +} + // This struct is packed on z/OS so it can't be used directly. type Flock_t struct { Type int16 diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 9119c60c7d00..656e13681f31 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -259,7 +259,7 @@ github.com/hashicorp/go-getter/helper/url github.com/hashicorp/go-hclog # github.com/hashicorp/go-multierror v1.0.0 github.com/hashicorp/go-multierror -# github.com/hashicorp/go-plugin v1.4.0 +# github.com/hashicorp/go-plugin v1.4.1 github.com/hashicorp/go-plugin github.com/hashicorp/go-plugin/internal/plugin # github.com/hashicorp/go-safetemp v1.0.0 @@ -274,11 +274,11 @@ github.com/hashicorp/hcl/v2/ext/customdecode github.com/hashicorp/hcl/v2/hclsyntax # github.com/hashicorp/logutils v1.0.0 github.com/hashicorp/logutils -# github.com/hashicorp/terraform-exec v0.13.3 +# github.com/hashicorp/terraform-exec v0.14.0 github.com/hashicorp/terraform-exec/internal/version github.com/hashicorp/terraform-exec/tfexec github.com/hashicorp/terraform-exec/tfinstall -# github.com/hashicorp/terraform-json v0.10.0 +# github.com/hashicorp/terraform-json v0.12.0 github.com/hashicorp/terraform-json # github.com/hashicorp/terraform-plugin-go v0.3.0 github.com/hashicorp/terraform-plugin-go/tfprotov5 @@ -286,8 +286,13 @@ github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/fromproto github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/tfplugin5 github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/toproto github.com/hashicorp/terraform-plugin-go/tfprotov5/server +github.com/hashicorp/terraform-plugin-go/tfprotov6 +github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/fromproto +github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6 +github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/toproto +github.com/hashicorp/terraform-plugin-go/tfprotov6/server github.com/hashicorp/terraform-plugin-go/tftypes -# github.com/hashicorp/terraform-plugin-sdk/v2 v2.6.1 +# github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 ## explicit github.com/hashicorp/terraform-plugin-sdk/v2/diag github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging @@ -324,7 +329,7 @@ github.com/klauspost/compress/zstd/internal/xxhash github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.10 github.com/mattn/go-isatty -# github.com/mitchellh/copystructure v1.0.0 +# github.com/mitchellh/copystructure v1.2.0 github.com/mitchellh/copystructure # github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir @@ -334,7 +339,7 @@ github.com/mitchellh/go-testing-interface github.com/mitchellh/go-wordwrap # github.com/mitchellh/mapstructure v1.1.2 github.com/mitchellh/mapstructure -# github.com/mitchellh/reflectwalk v1.0.1 +# github.com/mitchellh/reflectwalk v1.0.2 github.com/mitchellh/reflectwalk # github.com/oklog/run v1.0.0 github.com/oklog/run @@ -346,7 +351,7 @@ github.com/ulikunitz/xz/lzma # github.com/vmihailenco/msgpack v4.0.4+incompatible github.com/vmihailenco/msgpack github.com/vmihailenco/msgpack/codes -# github.com/zclconf/go-cty v1.8.2 +# github.com/zclconf/go-cty v1.8.4 github.com/zclconf/go-cty/cty github.com/zclconf/go-cty/cty/convert github.com/zclconf/go-cty/cty/function @@ -371,7 +376,7 @@ go.opencensus.io/trace go.opencensus.io/trace/internal go.opencensus.io/trace/propagation go.opencensus.io/trace/tracestate -# golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 +# golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b golang.org/x/crypto/cast5 golang.org/x/crypto/openpgp golang.org/x/crypto/openpgp/armor @@ -400,7 +405,7 @@ golang.org/x/oauth2/google golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt -# golang.org/x/sys v0.0.0-20210324051608-47abb6519492 +# golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 golang.org/x/sys/internal/unsafeheader golang.org/x/sys/unix # golang.org/x/text v0.3.5 From 19d7ee958f6c0e4bceffadfaca234957af24381e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Jun 2021 11:07:39 -0400 Subject: [PATCH 0845/1208] r/aws_transfer_server: Read security group IDs via EC2 DecsribeVpcEndpoints API. Acceptance test output (failures expected): % make testacc TEST=./aws TESTARGS='-run=TestAccAWSTransfer_serial/Server/VPC$' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSTransfer_serial/Server/VPC -timeout 180m === RUN TestAccAWSTransfer_serial === RUN TestAccAWSTransfer_serial/Server === RUN TestAccAWSTransfer_serial/Server/VPCAddressAllocationIDs resource_aws_transfer_server_test.go:288: Step 3/3 error: Error running apply: exit status 1 2021/06/29 10:59:43 [DEBUG] Using modified User-Agent: Terraform/0.12.31 HashiCorp-terraform-exec/0.13.3 Error: error updating Transfer Server (s-45159289697f40d29): InvalidRequestException: Changing Security Group is not supported on terraform_plugin_test.tf line 66, in resource "aws_transfer_server" "test": 66: resource "aws_transfer_server" "test" { === RUN TestAccAWSTransfer_serial/Server/VPC resource_aws_transfer_server_test.go:237: Step 3/3 error: Error running apply: exit status 1 2021/06/29 11:00:57 [DEBUG] Using modified User-Agent: Terraform/0.12.31 HashiCorp-terraform-exec/0.13.3 Error: error updating Transfer Server (s-e9f52c9d825845e5a): InvalidRequestException: Changing Security Group is not supported on terraform_plugin_test.tf line 56, in resource "aws_transfer_server" "test": 56: resource "aws_transfer_server" "test" { === RUN TestAccAWSTransfer_serial/Server/VPCEndpointID === RUN TestAccAWSTransfer_serial/Server/VPCSecurityGroupIDs resource_aws_transfer_server_test.go:340: Step 3/3 error: Error running apply: exit status 1 2021/06/29 11:03:44 [DEBUG] Using modified User-Agent: Terraform/0.12.31 HashiCorp-terraform-exec/0.13.3 Error: error updating Transfer Server (s-1e131250f9944c45a): InvalidRequestException: Changing Security Group is not supported on terraform_plugin_test.tf line 65, in resource "aws_transfer_server" "test": 65: resource "aws_transfer_server" "test" { --- FAIL: TestAccAWSTransfer_serial (411.21s) --- FAIL: TestAccAWSTransfer_serial/Server (411.21s) --- FAIL: TestAccAWSTransfer_serial/Server/VPCAddressAllocationIDs (185.57s) --- FAIL: TestAccAWSTransfer_serial/Server/VPC (58.73s) --- PASS: TestAccAWSTransfer_serial/Server/VPCEndpointID (106.22s) --- FAIL: TestAccAWSTransfer_serial/Server/VPCSecurityGroupIDs (60.69s) FAIL FAIL github.com/terraform-providers/terraform-provider-aws/aws 414.320s FAIL make: *** [testacc] Error 1 --- aws/resource_aws_transfer_server.go | 26 +++- aws/resource_aws_transfer_server_test.go | 184 ++++++++++++++++++++++- aws/resource_aws_transfer_test.go | 24 +-- 3 files changed, 214 insertions(+), 20 deletions(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 7d91952c85f3..f249bd117d1f 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -15,6 +15,7 @@ import ( "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" + ec2finder "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" tftransfer "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/waiter" @@ -83,6 +84,7 @@ func resourceAwsTransferServer() *schema.Resource { "security_group_ids": { Type: schema.TypeSet, Optional: true, + Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, ConflictsWith: []string{"endpoint_details.0.vpc_endpoint_id"}, }, @@ -317,7 +319,23 @@ func resourceAwsTransferServerRead(d *schema.ResourceData, meta interface{}) err d.Set("domain", output.Domain) d.Set("endpoint", meta.(*AWSClient).RegionalHostname(fmt.Sprintf("%s.server.transfer", d.Id()))) if output.EndpointDetails != nil { - if err := d.Set("endpoint_details", []interface{}{flattenTransferEndpointDetails(output.EndpointDetails)}); err != nil { + securityGroupIDs := make([]*string, 0) + + // Security Group IDs are not returned for VPC endpoints. + if aws.StringValue(output.EndpointType) == transfer.EndpointTypeVpc && len(output.EndpointDetails.SecurityGroupIds) == 0 { + vpcEndpointID := aws.StringValue(output.EndpointDetails.VpcEndpointId) + output, err := ec2finder.VpcEndpointByID(meta.(*AWSClient).ec2conn, vpcEndpointID) + + if err != nil { + return fmt.Errorf("error reading Transfer Server (%s) VPC Endpoint (%s): %w", d.Id(), vpcEndpointID, err) + } + + for _, group := range output.Groups { + securityGroupIDs = append(securityGroupIDs, group.GroupId) + } + } + + if err := d.Set("endpoint_details", []interface{}{flattenTransferEndpointDetails(output.EndpointDetails, securityGroupIDs)}); err != nil { return fmt.Errorf("error setting endpoint_details: %w", err) } } else { @@ -538,7 +556,7 @@ func expandTransferEndpointDetails(tfMap map[string]interface{}) *transfer.Endpo return apiObject } -func flattenTransferEndpointDetails(apiObject *transfer.EndpointDetails) map[string]interface{} { +func flattenTransferEndpointDetails(apiObject *transfer.EndpointDetails, securityGroupIDs []*string) map[string]interface{} { if apiObject == nil { return nil } @@ -549,8 +567,10 @@ func flattenTransferEndpointDetails(apiObject *transfer.EndpointDetails) map[str tfMap["address_allocation_ids"] = aws.StringValueSlice(v) } - if v := apiObject.SecurityGroupIds; v != nil { + if v := apiObject.SecurityGroupIds; len(v) > 0 { tfMap["security_group_ids"] = aws.StringValueSlice(v) + } else if len(securityGroupIDs) > 0 { + tfMap["security_group_ids"] = aws.StringValueSlice(securityGroupIDs) } if v := apiObject.SubnetIds; v != nil { diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index efd9601cd4ac..c023576ef251 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -227,10 +227,60 @@ func testAccAWSTransferServer_securityPolicy(t *testing.T) { } func testAccAWSTransferServer_vpc(t *testing.T) { + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + defaultSecurityGroupResourceName := "aws_default_security_group.test" + subnetResourceName := "aws_subnet.test" + vpcResourceName := "aws_vpc.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferServerVpcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + { + Config: testAccAWSTransferServerVpcUpdateConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + }, + }) +} + +func testAccAWSTransferServer_vpcAddressAllocationIds(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" eip1ResourceName := "aws_eip.test.0" eip2ResourceName := "aws_eip.test.1" + defaultSecurityGroupResourceName := "aws_default_security_group.test" subnetResourceName := "aws_subnet.test" vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -242,13 +292,14 @@ func testAccAWSTransferServer_vpc(t *testing.T) { CheckDestroy: testAccCheckAWSTransferServerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSTransferServerVpcNoSecurityGroupsConfig(rName), + Config: testAccAWSTransferServerVpcAddressAllocationIdsNoSecurityGroupsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip1ResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), @@ -261,13 +312,14 @@ func testAccAWSTransferServer_vpc(t *testing.T) { ImportStateVerifyIgnore: []string{"force_destroy"}, }, { - Config: testAccAWSTransferServerVpcNoSecurityGroupsUpdateConfig(rName), + Config: testAccAWSTransferServerVpcAddressAllocationIdsNoSecurityGroupsUpdateConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip2ResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), @@ -277,6 +329,54 @@ func testAccAWSTransferServer_vpc(t *testing.T) { }) } +func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + securityGroup1ResourceName := "aws_security_group.test" + securityGroup2ResourceName := "aws_security_group.tes2" + vpcResourceName := "aws_vpc.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferServerVpcSecurityGroupIdsConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", securityGroup1ResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + { + Config: testAccAWSTransferServerVpcSecurityGroupIdsUpdateConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", securityGroup2ResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + }, + }) +} + // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/16556 /* func testAccAWSTransferServer_updateEndpointType(t *testing.T) { @@ -649,6 +749,10 @@ resource "aws_security_group" "test" { Name = %[1]q } } + +resource "aws_default_security_group" "test" { + vpc_id = aws_vpc.test.id +} `, rName) } @@ -887,7 +991,36 @@ resource "aws_transfer_server" "test" { `, rName)) } -func testAccAWSTransferServerVpcNoSecurityGroupsConfig(rName string) string { +func testAccAWSTransferServerVpcConfig(rName string) string { + return composeConfig( + testAccAWSTransferServerConfigBaseVpc(rName), + ` +resource "aws_transfer_server" "test" { + endpoint_type = "VPC" + + endpoint_details { + vpc_id = aws_vpc.test.id + } +} +`) +} + +func testAccAWSTransferServerVpcUpdateConfig(rName string) string { + return composeConfig( + testAccAWSTransferServerConfigBaseVpc(rName), + ` +resource "aws_transfer_server" "test" { + endpoint_type = "VPC" + + endpoint_details { + subnet_ids = [aws_subnet.test.id] + vpc_id = aws_vpc.test.id + } +} +`) +} + +func testAccAWSTransferServerVpcAddressAllocationIdsNoSecurityGroupsConfig(rName string) string { return composeConfig( testAccAWSTransferServerConfigBaseVpc(rName), fmt.Sprintf(` @@ -913,7 +1046,7 @@ resource "aws_transfer_server" "test" { `, rName)) } -func testAccAWSTransferServerVpcNoSecurityGroupsUpdateConfig(rName string) string { +func testAccAWSTransferServerVpcAddressAllocationIdsNoSecurityGroupsUpdateConfig(rName string) string { return composeConfig( testAccAWSTransferServerConfigBaseVpc(rName), fmt.Sprintf(` @@ -939,6 +1072,45 @@ resource "aws_transfer_server" "test" { `, rName)) } +func testAccAWSTransferServerVpcSecurityGroupIdsConfig(rName string) string { + return composeConfig( + testAccAWSTransferServerConfigBaseVpc(rName), + ` +resource "aws_transfer_server" "test" { + endpoint_type = "VPC" + + endpoint_details { + security_group_ids = [aws_security_group.test.id] + vpc_id = aws_vpc.test.id + } +} +`) +} + +func testAccAWSTransferServerVpcSecurityGroupIdsUpdateConfig(rName string) string { + return composeConfig( + testAccAWSTransferServerConfigBaseVpc(rName), + fmt.Sprintf(` +resource "aws_security_group" "test2" { + name = "%[1]s-2" + vpc_id = aws_vpc.test.id + + tags = { + Name = "%[1]s-2" + } +} + +resource "aws_transfer_server" "test" { + endpoint_type = "VPC" + + endpoint_details { + security_group_ids = [aws_security_group.test2.id] + vpc_id = aws_vpc.test.id + } +} +`, rName)) +} + func testAccAWSTransferServerHostKeyConfig(hostKey string) string { return fmt.Sprintf(` resource "aws_transfer_server" "test" { diff --git a/aws/resource_aws_transfer_test.go b/aws/resource_aws_transfer_test.go index 49a5ef44dad2..17e3adde8b7e 100644 --- a/aws/resource_aws_transfer_test.go +++ b/aws/resource_aws_transfer_test.go @@ -7,17 +7,19 @@ import ( func TestAccAWSTransfer_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "Server": { - "basic": testAccAWSTransferServer_basic, - "disappears": testAccAWSTransferServer_disappears, - "APIGateway": testAccAWSTransferServer_apiGateway, - "APIGatewayForceDestroy": testAccAWSTransferServer_apiGateway_forceDestroy, - "Domain": testAccAWSTransferServer_domain, - "ForceDestroy": testAccAWSTransferServer_forceDestroy, - "HostKey": testAccAWSTransferServer_hostKey, - "Protocols": testAccAWSTransferServer_protocols, - "SecurityPolicy": testAccAWSTransferServer_securityPolicy, - "VPC": testAccAWSTransferServer_vpc, - "VPCEndpointID": testAccAWSTransferServer_vpcEndpointId, + "basic": testAccAWSTransferServer_basic, + "disappears": testAccAWSTransferServer_disappears, + "APIGateway": testAccAWSTransferServer_apiGateway, + "APIGatewayForceDestroy": testAccAWSTransferServer_apiGateway_forceDestroy, + "Domain": testAccAWSTransferServer_domain, + "ForceDestroy": testAccAWSTransferServer_forceDestroy, + "HostKey": testAccAWSTransferServer_hostKey, + "Protocols": testAccAWSTransferServer_protocols, + "SecurityPolicy": testAccAWSTransferServer_securityPolicy, + "VPC": testAccAWSTransferServer_vpc, + "VPCAddressAllocationIDs": testAccAWSTransferServer_vpcAddressAllocationIds, + "VPCEndpointID": testAccAWSTransferServer_vpcEndpointId, + "VPCSecurityGroupIDs": testAccAWSTransferServer_vpcSecurityGroupIds, }, "SSHKey": { "basic": testAccAWSTransferSshKey_basic, From f67f2af4eaf99a4d3750da6bf4e2435b14901527 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Huynh Date: Tue, 29 Jun 2021 16:18:42 +0100 Subject: [PATCH 0846/1208] fix(r_aws_mwaa_environment): Changing the KMS key used by MWAA should recreation of the Airflow environment This is currently an issue when updating the cluster from `aws/airflow` KMS key to a CMK for example. The current implementation will show a diff, apply an update to the cluster but will not be able to change to another KMS key leading to a perpetual diff. ``` Terraform will perform the following actions: # module.airflow[0].aws_mwaa_environment.airflow will be updated in-place ~ resource "aws_mwaa_environment" "airflow" { id = "myairflow" + kms_key = "arn:aws:kms:us-east-1:redacted:key/redacted" name = "myairflow" tags = { "Name" = "myairflow" } # (21 unchanged attributes hidden) # (2 unchanged blocks hidden) } Plan: 0 to add, 1 to change, 0 to destroy. ``` --- aws/resource_aws_mwaa_environment.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_mwaa_environment.go b/aws/resource_aws_mwaa_environment.go index d913ee01be99..276bc090a092 100644 --- a/aws/resource_aws_mwaa_environment.go +++ b/aws/resource_aws_mwaa_environment.go @@ -61,6 +61,7 @@ func resourceAwsMwaaEnvironment() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validateArn, + ForceNew: true, }, "last_updated": { Type: schema.TypeList, From 76c318db487f014b3b469e10a79aa64841858be4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 14:54:54 -0400 Subject: [PATCH 0847/1208] tests/d/servicecat_launch_paths: Fix for assumed role --- aws/data_source_aws_servicecatalog_launch_paths_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/aws/data_source_aws_servicecatalog_launch_paths_test.go b/aws/data_source_aws_servicecatalog_launch_paths_test.go index 09ca1e09301d..2f7332b3e3ff 100644 --- a/aws/data_source_aws_servicecatalog_launch_paths_test.go +++ b/aws/data_source_aws_servicecatalog_launch_paths_test.go @@ -114,9 +114,13 @@ resource "aws_iam_role" "test" { data "aws_caller_identity" "current" {} +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + resource "aws_servicecatalog_principal_portfolio_association" "test" { portfolio_id = aws_servicecatalog_portfolio.test.id - principal_arn = data.aws_caller_identity.current.arn + principal_arn = data.aws_iam_session_context.current.issuer_arn } `, rName) } From 71680d0735ee9f8759f81235e4144112c4d4550a Mon Sep 17 00:00:00 2001 From: Kyle Kotowick Date: Tue, 29 Jun 2021 16:47:12 -0400 Subject: [PATCH 0848/1208] Fix typo in aws_lambda_function resource --- website/docs/r/lambda_function.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lambda_function.html.markdown b/website/docs/r/lambda_function.html.markdown index e395c1f83e56..3a41dc3f529c 100644 --- a/website/docs/r/lambda_function.html.markdown +++ b/website/docs/r/lambda_function.html.markdown @@ -251,7 +251,7 @@ Dead letter queue configuration that specifies the queue or topic where Lambda s ### file_system_config -Connection settings for an EFS file system. Before creating or updating Lambda functions with `file_system_config`, EFS mount targets much be in available lifecycle state. Use `depends_on` to explicitly declare this dependency. See [Using Amazon EFS with Lambda][12]. +Connection settings for an EFS file system. Before creating or updating Lambda functions with `file_system_config`, EFS mount targets must be in available lifecycle state. Use `depends_on` to explicitly declare this dependency. See [Using Amazon EFS with Lambda][12]. * `arn` - (Required) Amazon Resource Name (ARN) of the Amazon EFS Access Point that provides access to the file system. * `local_mount_path` - (Required) Path where the function can access the file system, starting with /mnt/. From dfbff597f0419748fd4b60e3ca6dd6b2d6c0e9a1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 29 Jun 2021 17:08:58 -0400 Subject: [PATCH 0849/1208] Add CHANGELOG entry. --- .changelog/19994.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19994.txt diff --git a/.changelog/19994.txt b/.changelog/19994.txt new file mode 100644 index 000000000000..8aa3871bb24c --- /dev/null +++ b/.changelog/19994.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_mwaa_environment: Changes to the `kms_key` argument force resource recreation +``` \ No newline at end of file From fedf8cd136de3654d85341dbf3d6aff6b438e5cf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 30 Jun 2021 12:17:38 -0400 Subject: [PATCH 0850/1208] r/aws_transfer_server: Additional tests. --- aws/resource_aws_transfer_server_test.go | 369 ++++++++++++++++++++++- aws/resource_aws_transfer_test.go | 28 +- 2 files changed, 377 insertions(+), 20 deletions(-) diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index c023576ef251..7067370b854e 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -245,10 +245,12 @@ func testAccAWSTransferServer_vpc(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, @@ -263,11 +265,13 @@ func testAccAWSTransferServer_vpc(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, @@ -292,16 +296,18 @@ func testAccAWSTransferServer_vpcAddressAllocationIds(t *testing.T) { CheckDestroy: testAccCheckAWSTransferServerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSTransferServerVpcAddressAllocationIdsNoSecurityGroupsConfig(rName), + Config: testAccAWSTransferServerVpcAddressAllocationIdsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip1ResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, @@ -312,16 +318,18 @@ func testAccAWSTransferServer_vpcAddressAllocationIds(t *testing.T) { ImportStateVerifyIgnore: []string{"force_destroy"}, }, { - Config: testAccAWSTransferServerVpcAddressAllocationIdsNoSecurityGroupsUpdateConfig(rName), + Config: testAccAWSTransferServerVpcAddressAllocationIdsUpdateConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip2ResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, @@ -333,7 +341,7 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" securityGroup1ResourceName := "aws_security_group.test" - securityGroup2ResourceName := "aws_security_group.tes2" + securityGroup2ResourceName := "aws_security_group.test2" vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -348,10 +356,12 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", securityGroup1ResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, @@ -366,10 +376,12 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", securityGroup2ResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, @@ -377,11 +389,70 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { }) } -// Reference: https://github.com/hashicorp/terraform-provider-aws/issues/16556 -/* -func testAccAWSTransferServer_updateEndpointType(t *testing.T) { +func testAccAWSTransferServer_vpcAddressAllocationIds_securityGroupIds(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" + eip1ResourceName := "aws_eip.test.0" + eip2ResourceName := "aws_eip.test.1" + securityGroup1ResourceName := "aws_security_group.test" + securityGroup2ResourceName := "aws_security_group.test2" + subnetResourceName := "aws_subnet.test" + vpcResourceName := "aws_vpc.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferServerVpcAddressAllocationIdsSecurityGroupIdsConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip1ResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", securityGroup1ResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + { + Config: testAccAWSTransferServerVpcAddressAllocationIdsSecurityGroupIdsUpdateConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip2ResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", securityGroup2ResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + }, + }) +} + +func testAccAWSTransferServer_updateEndpointType_publicToVpc(t *testing.T) { + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + defaultSecurityGroupResourceName := "aws_default_security_group.test" + vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.Test(t, resource.TestCase{ @@ -403,8 +474,219 @@ func testAccAWSTransferServer_updateEndpointType(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + +func testAccAWSTransferServer_updateEndpointType_publicToVpc_addressAllocationIds(t *testing.T) { + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + eipResourceName := "aws_eip.test.0" + defaultSecurityGroupResourceName := "aws_default_security_group.test" + subnetResourceName := "aws_subnet.test" + vpcResourceName := "aws_vpc.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferServerBasicConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "PUBLIC"), + ), + }, + { + Config: testAccAWSTransferServerVpcAddressAllocationIdsConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eipResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + +func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc(t *testing.T) { + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + defaultSecurityGroupResourceName := "aws_default_security_group.test" + vpcEndpointResourceName := "aws_vpc_endpoint.test" + vpcResourceName := "aws_vpc.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferServerVpcEndpointConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_endpoint_id", vpcEndpointResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.vpc_id", ""), + ), + }, + { + Config: testAccAWSTransferServerVpcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + +func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_addressAllocationIds(t *testing.T) { + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + eipResourceName := "aws_eip.test.0" + defaultSecurityGroupResourceName := "aws_default_security_group.test" + subnetResourceName := "aws_subnet.test" + vpcEndpointResourceName := "aws_vpc_endpoint.test" + vpcResourceName := "aws_vpc.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferServerVpcEndpointConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_endpoint_id", vpcEndpointResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.vpc_id", ""), + ), + }, + { + Config: testAccAWSTransferServerVpcAddressAllocationIdsConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eipResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + +func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_securityGroupIds(t *testing.T) { + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + securityGroupResourceName := "aws_security_group.test" + vpcEndpointResourceName := "aws_vpc_endpoint.test" + vpcResourceName := "aws_vpc.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferServerVpcEndpointConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_endpoint_id", vpcEndpointResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.vpc_id", ""), + ), + }, + { + Config: testAccAWSTransferServerVpcSecurityGroupIdsConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", securityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, { @@ -416,7 +698,6 @@ func testAccAWSTransferServer_updateEndpointType(t *testing.T) { }, }) } -*/ func testAccAWSTransferServer_protocols(t *testing.T) { var s transfer.DescribedServer @@ -604,6 +885,7 @@ func testAccAWSTransferServer_hostKey(t *testing.T) { func testAccAWSTransferServer_vpcEndpointId(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" + vpcEndpointResourceName := "aws_vpc_endpoint.test" rName := acctest.RandomWithPrefix("tf-acc-test") if testAccGetPartition() == "aws-us-gov" { @@ -621,6 +903,12 @@ func testAccAWSTransferServer_vpcEndpointId(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_endpoint_id", vpcEndpointResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.vpc_id", ""), ), }, { @@ -1020,7 +1308,59 @@ resource "aws_transfer_server" "test" { `) } -func testAccAWSTransferServerVpcAddressAllocationIdsNoSecurityGroupsConfig(rName string) string { +func testAccAWSTransferServerVpcAddressAllocationIdsConfig(rName string) string { + return composeConfig( + testAccAWSTransferServerConfigBaseVpc(rName), + fmt.Sprintf(` +resource "aws_eip" "test" { + count = 2 + + vpc = true + + tags = { + Name = %[1]q + } +} + +resource "aws_transfer_server" "test" { + endpoint_type = "VPC" + + endpoint_details { + address_allocation_ids = [aws_eip.test[0].id] + subnet_ids = [aws_subnet.test.id] + vpc_id = aws_vpc.test.id + } +} +`, rName)) +} + +func testAccAWSTransferServerVpcAddressAllocationIdsUpdateConfig(rName string) string { + return composeConfig( + testAccAWSTransferServerConfigBaseVpc(rName), + fmt.Sprintf(` +resource "aws_eip" "test" { + count = 2 + + vpc = true + + tags = { + Name = %[1]q + } +} + +resource "aws_transfer_server" "test" { + endpoint_type = "VPC" + + endpoint_details { + address_allocation_ids = [aws_eip.test[1].id] + subnet_ids = [aws_subnet.test.id] + vpc_id = aws_vpc.test.id + } +} +`, rName)) +} + +func testAccAWSTransferServerVpcAddressAllocationIdsSecurityGroupIdsConfig(rName string) string { return composeConfig( testAccAWSTransferServerConfigBaseVpc(rName), fmt.Sprintf(` @@ -1039,6 +1379,7 @@ resource "aws_transfer_server" "test" { endpoint_details { address_allocation_ids = [aws_eip.test[0].id] + security_group_ids = [aws_security_group.test.id] subnet_ids = [aws_subnet.test.id] vpc_id = aws_vpc.test.id } @@ -1046,10 +1387,19 @@ resource "aws_transfer_server" "test" { `, rName)) } -func testAccAWSTransferServerVpcAddressAllocationIdsNoSecurityGroupsUpdateConfig(rName string) string { +func testAccAWSTransferServerVpcAddressAllocationIdsSecurityGroupIdsUpdateConfig(rName string) string { return composeConfig( testAccAWSTransferServerConfigBaseVpc(rName), fmt.Sprintf(` +resource "aws_security_group" "test2" { + name = "%[1]s-2" + vpc_id = aws_vpc.test.id + + tags = { + Name = "%[1]s-2" + } +} + resource "aws_eip" "test" { count = 2 @@ -1065,6 +1415,7 @@ resource "aws_transfer_server" "test" { endpoint_details { address_allocation_ids = [aws_eip.test[1].id] + security_group_ids = [aws_security_group.test2.id] subnet_ids = [aws_subnet.test.id] vpc_id = aws_vpc.test.id } diff --git a/aws/resource_aws_transfer_test.go b/aws/resource_aws_transfer_test.go index 17e3adde8b7e..c076d6e4e199 100644 --- a/aws/resource_aws_transfer_test.go +++ b/aws/resource_aws_transfer_test.go @@ -7,19 +7,25 @@ import ( func TestAccAWSTransfer_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "Server": { - "basic": testAccAWSTransferServer_basic, - "disappears": testAccAWSTransferServer_disappears, - "APIGateway": testAccAWSTransferServer_apiGateway, - "APIGatewayForceDestroy": testAccAWSTransferServer_apiGateway_forceDestroy, - "Domain": testAccAWSTransferServer_domain, - "ForceDestroy": testAccAWSTransferServer_forceDestroy, - "HostKey": testAccAWSTransferServer_hostKey, - "Protocols": testAccAWSTransferServer_protocols, - "SecurityPolicy": testAccAWSTransferServer_securityPolicy, + "basic": testAccAWSTransferServer_basic, + "disappears": testAccAWSTransferServer_disappears, + "APIGateway": testAccAWSTransferServer_apiGateway, + "APIGatewayForceDestroy": testAccAWSTransferServer_apiGateway_forceDestroy, + "Domain": testAccAWSTransferServer_domain, + "ForceDestroy": testAccAWSTransferServer_forceDestroy, + "HostKey": testAccAWSTransferServer_hostKey, + "Protocols": testAccAWSTransferServer_protocols, + "SecurityPolicy": testAccAWSTransferServer_securityPolicy, + "UpdateEndpointTypePublicToVPC": testAccAWSTransferServer_updateEndpointType_publicToVpc, + "UpdateEndpointTypePublicToVPCAddressAllocationIDs": testAccAWSTransferServer_updateEndpointType_publicToVpc_addressAllocationIds, + "UpdateEndpointTypeVPCEndpointToVPC": testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc, + "UpdateEndpointTypeVPCEndpointToVPCAddressAllocationIDs": testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_addressAllocationIds, + "UpdateEndpointTypeVPCEndpointToVPCSecurityGroupIDs": testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_securityGroupIds, "VPC": testAccAWSTransferServer_vpc, "VPCAddressAllocationIDs": testAccAWSTransferServer_vpcAddressAllocationIds, - "VPCEndpointID": testAccAWSTransferServer_vpcEndpointId, - "VPCSecurityGroupIDs": testAccAWSTransferServer_vpcSecurityGroupIds, + "VPCAddressAllocationIDsSecurityGroupIDs": testAccAWSTransferServer_vpcAddressAllocationIds_securityGroupIds, + "VPCEndpointID": testAccAWSTransferServer_vpcEndpointId, + "VPCSecurityGroupIDs": testAccAWSTransferServer_vpcSecurityGroupIds, }, "SSHKey": { "basic": testAccAWSTransferSshKey_basic, From d4765613b646f75c4724683be48742c0d4063f3c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 30 Jun 2021 14:52:59 -0400 Subject: [PATCH 0851/1208] tests/d/servicecat_launch_paths: Juggle dependencies to avoid depends_on --- aws/data_source_aws_servicecatalog_launch_paths_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/aws/data_source_aws_servicecatalog_launch_paths_test.go b/aws/data_source_aws_servicecatalog_launch_paths_test.go index 2f7332b3e3ff..95e5d1898fc0 100644 --- a/aws/data_source_aws_servicecatalog_launch_paths_test.go +++ b/aws/data_source_aws_servicecatalog_launch_paths_test.go @@ -90,7 +90,7 @@ resource "aws_servicecatalog_portfolio" "test" { } resource "aws_servicecatalog_product_portfolio_association" "test" { - portfolio_id = aws_servicecatalog_portfolio.test.id + portfolio_id = aws_servicecatalog_principal_portfolio_association.test.portfolio_id product_id = aws_servicecatalog_product.test.id } @@ -129,8 +129,6 @@ func testAccAWSServiceCatalogLaunchPathsDataSourceConfig_basic(rName string) str return composeConfig(testAccAWSServiceCatalogLaunchPathsDataSourceConfig_base(rName), ` data "aws_servicecatalog_launch_paths" "test" { product_id = aws_servicecatalog_product_portfolio_association.test.product_id - - depends_on = [aws_servicecatalog_principal_portfolio_association.test] } `) } From f2da30da174d85618632868867e9227189cb9fdd Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 30 Jun 2021 19:42:28 +0000 Subject: [PATCH 0852/1208] Update CHANGELOG.md for #20001 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b858d4b4e8c..55693ebbb39f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ENHANCEMENTS: BUG FIXES: * resource/aws_cloudwatch_event_target: Don't crash if `sqs_target` configuration block is empty. ([#19946](https://github.com/hashicorp/terraform-provider-aws/issues/19946)) +* resource/aws_mwaa_environment: Changes to the `kms_key` argument force resource recreation ([#19994](https://github.com/hashicorp/terraform-provider-aws/issues/19994)) ## 3.47.0 (June 24, 2021) From 5d26d2a81a5becf8ff722f9591c537e548124c9e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 30 Jun 2021 16:04:03 -0400 Subject: [PATCH 0853/1208] r/aws_transfer_server: Use Amazon EC2 ModifyVpcEndpoint API to modify security_group_ids. --- aws/resource_aws_transfer_server.go | 145 ++++++++++++++++------- aws/resource_aws_transfer_server_test.go | 45 +++++++ aws/resource_aws_transfer_test.go | 11 +- 3 files changed, 152 insertions(+), 49 deletions(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index f249bd117d1f..fc06e68e4624 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -7,6 +7,7 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/transfer" "github.com/hashicorp/aws-sdk-go-base/tfawserr" multierror "github.com/hashicorp/go-multierror" @@ -16,6 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ec2finder "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + ec2waiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" tftransfer "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/waiter" @@ -186,7 +188,6 @@ func resourceAwsTransferServer() *schema.Resource { } func resourceAwsTransferServerCreate(d *schema.ResourceData, meta interface{}) error { - updateAfterCreate := false conn := meta.(*AWSClient).transferconn defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) @@ -201,15 +202,15 @@ func resourceAwsTransferServerCreate(d *schema.ResourceData, meta interface{}) e input.Domain = aws.String(v.(string)) } + var addressAllocationIDs []*string + if v, ok := d.GetOk("endpoint_details"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.EndpointDetails = expandTransferEndpointDetails(v.([]interface{})[0].(map[string]interface{})) // Prevent the following error: InvalidRequestException: AddressAllocationIds cannot be set in CreateServer // Reference: https://docs.aws.amazon.com/transfer/latest/userguide/API_EndpointDetails.html#TransferFamily-Type-EndpointDetails-AddressAllocationIds - if input.EndpointDetails != nil && len(input.EndpointDetails.AddressAllocationIds) > 0 { - input.EndpointDetails.AddressAllocationIds = nil - updateAfterCreate = true - } + addressAllocationIDs = input.EndpointDetails.AddressAllocationIds + input.EndpointDetails.AddressAllocationIds = nil } if v, ok := d.GetOk("endpoint_type"); ok { @@ -271,18 +272,17 @@ func resourceAwsTransferServerCreate(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("error waiting for Transfer Server (%s) to create: %w", d.Id(), err) } - if updateAfterCreate { + // AddressAllocationIds is only valid in the UpdateServer API. + if len(addressAllocationIDs) > 0 { if err := stopTransferServer(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return err } - // TODO - // TODO You can edit the SecurityGroupIds property in the UpdateServer API only if you are changing the EndpointType from PUBLIC or VPC_ENDPOINT to VPC. To change security groups associated with your server's VPC endpoint after creation, use the Amazon EC2 ModifyVpcEndpoint API. - // TODO - input := &transfer.UpdateServerInput{ - ServerId: aws.String(d.Id()), - EndpointDetails: expandTransferEndpointDetails(d.Get("endpoint_details").([]interface{})[0].(map[string]interface{})), + ServerId: aws.String(d.Id()), + EndpointDetails: &transfer.EndpointDetails{ + AddressAllocationIds: addressAllocationIDs, + }, } if err := updateTransferServer(conn, input); err != nil { @@ -376,18 +376,96 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e conn := meta.(*AWSClient).transferconn if d.HasChangesExcept("tags", "tags_all") { - stopFlag := false + //TODO var addressAllocationIDs []*string + var offlineUpdate bool input := &transfer.UpdateServerInput{ ServerId: aws.String(d.Id()), } - if d.HasChange("logging_role") { - input.LoggingRole = aws.String(d.Get("logging_role").(string)) + if d.HasChange("certificate") { + input.Certificate = aws.String(d.Get("certificate").(string)) } - if d.HasChange("security_policy_name") { - input.SecurityPolicyName = aws.String(d.Get("security_policy_name").(string)) + if d.HasChange("endpoint_details") { + var newEndpointTypeVpc bool + var oldEndpointTypeVpc bool + + if v, ok := d.GetOk("endpoint_details"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.EndpointDetails = expandTransferEndpointDetails(v.([]interface{})[0].(map[string]interface{})) + + old, new := d.GetChange("endpoint_type") + + if old, new := old.(string), new.(string); new != old && new == transfer.EndpointTypeVpc { + newEndpointTypeVpc = true + } else if new == old && new == transfer.EndpointTypeVpc { + newEndpointTypeVpc = true + oldEndpointTypeVpc = true + } + + if newEndpointTypeVpc && !oldEndpointTypeVpc { + // TODO ???? + // Prevent the following error: InvalidRequestException: Cannot specify AddressAllocationids when updating server to EndpointType: VPC + // addressAllocationIDs = input.EndpointDetails.AddressAllocationIds + // input.EndpointDetails.AddressAllocationIds = nil + + // Prevent the following error: InvalidRequestException: VPC Endpoint ID unsupported for EndpointType: VPC + input.EndpointDetails.VpcEndpointId = nil + } else if newEndpointTypeVpc && oldEndpointTypeVpc { + // Prevent the following error: InvalidRequestException: Server must be OFFLINE to change AddressAllocationIds + if d.HasChange("endpoint_details.0.address_allocation_ids") { + offlineUpdate = true + } + + // Prevent the following error: InvalidRequestException: Changing Security Group is not supported + input.EndpointDetails.SecurityGroupIds = nil + } + } + + // You can edit the SecurityGroupIds property in the UpdateServer API only if you are changing the EndpointType from PUBLIC or VPC_ENDPOINT to VPC. + // To change security groups associated with your server's VPC endpoint after creation, use the Amazon EC2 ModifyVpcEndpoint API. + if d.HasChange("endpoint_details.0.security_group_ids") && newEndpointTypeVpc && oldEndpointTypeVpc { + conn := meta.(*AWSClient).ec2conn + + vpcEndpointID := d.Get("endpoint_details.0.vpc_endpoint_id").(string) + input := &ec2.ModifyVpcEndpointInput{ + VpcEndpointId: aws.String(vpcEndpointID), + } + + old, new := d.GetChange("endpoint_details.0.security_group_ids") + + if add := expandStringSet(new.(*schema.Set).Difference(old.(*schema.Set))); len(add) > 0 { + input.AddSecurityGroupIds = add + } + + if del := expandStringSet(old.(*schema.Set).Difference(new.(*schema.Set))); len(del) > 0 { + input.RemoveSecurityGroupIds = del + } + + log.Printf("[DEBUG] Updating VPC Endpoint: %s", input) + if _, err := conn.ModifyVpcEndpoint(input); err != nil { + return fmt.Errorf("error updating Transfer Server (%s) VPC Endpoint (%s): %w", d.Id(), vpcEndpointID, err) + } + + _, err := ec2waiter.VpcEndpointAvailable(conn, vpcEndpointID, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("error waiting for Transfer Server (%s) VPC Endpoint (%s) to become available: %w", d.Id(), vpcEndpointID, err) + } + } + } + + if d.HasChange("endpoint_type") { + input.EndpointType = aws.String(d.Get("endpoint_type").(string)) + + // Prevent the following error: InvalidRequestException: Server must be OFFLINE to change EndpointType + offlineUpdate = true + } + + if d.HasChange("host_key") { + if attr, ok := d.GetOk("host_key"); ok { + input.HostKey = aws.String(attr.(string)) + } } if d.HasChanges("invocation_role", "url") { @@ -404,40 +482,19 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e input.IdentityProviderDetails = identityProviderDetails } - if d.HasChange("endpoint_type") { - input.EndpointType = aws.String(d.Get("endpoint_type").(string)) - } - - if d.HasChange("certificate") { - input.Certificate = aws.String(d.Get("certificate").(string)) + if d.HasChange("logging_role") { + input.LoggingRole = aws.String(d.Get("logging_role").(string)) } if d.HasChange("protocols") { input.Protocols = expandStringSet(d.Get("protocols").(*schema.Set)) } - if d.HasChange("endpoint_details") { - if v, ok := d.GetOk("endpoint_details"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - input.EndpointDetails = expandTransferEndpointDetails(v.([]interface{})[0].(map[string]interface{})) - } - - // Prevent the following error: InvalidRequestException: Server must be OFFLINE to change AddressAllocationIds - if d.HasChange("endpoint_details.0.address_allocation_ids") { - stopFlag = true - } - - // TODO - // TODO You can edit the SecurityGroupIds property in the UpdateServer API only if you are changing the EndpointType from PUBLIC or VPC_ENDPOINT to VPC. To change security groups associated with your server's VPC endpoint after creation, use the Amazon EC2 ModifyVpcEndpoint API. - // TODO - } - - if d.HasChange("host_key") { - if attr, ok := d.GetOk("host_key"); ok { - input.HostKey = aws.String(attr.(string)) - } + if d.HasChange("security_policy_name") { + input.SecurityPolicyName = aws.String(d.Get("security_policy_name").(string)) } - if stopFlag { + if offlineUpdate { if err := stopTransferServer(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { return err } @@ -448,7 +505,7 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e return err } - if stopFlag { + if offlineUpdate { if err := startTransferServer(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { return err } diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index 7067370b854e..c1226b6f0bca 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -699,6 +699,51 @@ func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_securityGroupI }) } +func testAccAWSTransferServer_updateEndpointType_vpcToPublic(t *testing.T) { + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + defaultSecurityGroupResourceName := "aws_default_security_group.test" + vpcResourceName := "aws_vpc.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferServerVpcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, + { + Config: testAccAWSTransferServerBasicConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "PUBLIC"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + func testAccAWSTransferServer_protocols(t *testing.T) { var s transfer.DescribedServer var ca acmpca.CertificateAuthority diff --git a/aws/resource_aws_transfer_test.go b/aws/resource_aws_transfer_test.go index c076d6e4e199..a06c3fe02898 100644 --- a/aws/resource_aws_transfer_test.go +++ b/aws/resource_aws_transfer_test.go @@ -21,11 +21,12 @@ func TestAccAWSTransfer_serial(t *testing.T) { "UpdateEndpointTypeVPCEndpointToVPC": testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc, "UpdateEndpointTypeVPCEndpointToVPCAddressAllocationIDs": testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_addressAllocationIds, "UpdateEndpointTypeVPCEndpointToVPCSecurityGroupIDs": testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_securityGroupIds, - "VPC": testAccAWSTransferServer_vpc, - "VPCAddressAllocationIDs": testAccAWSTransferServer_vpcAddressAllocationIds, - "VPCAddressAllocationIDsSecurityGroupIDs": testAccAWSTransferServer_vpcAddressAllocationIds_securityGroupIds, - "VPCEndpointID": testAccAWSTransferServer_vpcEndpointId, - "VPCSecurityGroupIDs": testAccAWSTransferServer_vpcSecurityGroupIds, + "UpdateEndpointTypeVPCToPublic": testAccAWSTransferServer_updateEndpointType_vpcToPublic, + "VPC": testAccAWSTransferServer_vpc, + "VPCAddressAllocationIDs": testAccAWSTransferServer_vpcAddressAllocationIds, + "VPCAddressAllocationIDsSecurityGroupIDs": testAccAWSTransferServer_vpcAddressAllocationIds_securityGroupIds, + "VPCEndpointID": testAccAWSTransferServer_vpcEndpointId, + "VPCSecurityGroupIDs": testAccAWSTransferServer_vpcSecurityGroupIds, }, "SSHKey": { "basic": testAccAWSTransferSshKey_basic, From c8fd523982b80f60c5c1af38c7443e841316262a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 14:31:57 -0400 Subject: [PATCH 0854/1208] provider: Add servicecat_provisioned_product --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index 3b620d89fc44..e71d04dfcf18 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1053,6 +1053,7 @@ func Provider() *schema.Provider { "aws_servicecatalog_portfolio": resourceAwsServiceCatalogPortfolio(), "aws_servicecatalog_portfolio_share": resourceAwsServiceCatalogPortfolioShare(), "aws_servicecatalog_product": resourceAwsServiceCatalogProduct(), + "aws_servicecatalog_provisioned_product": resourceAwsServiceCatalogProvisionedProduct(), "aws_servicecatalog_service_action": resourceAwsServiceCatalogServiceAction(), "aws_servicecatalog_tag_option": resourceAwsServiceCatalogTagOption(), "aws_servicecatalog_tag_option_resource_association": resourceAwsServiceCatalogTagOptionResourceAssociation(), From 526cdfde086e276cdc8a48b489a71ac0ddf53f07 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 14:32:54 -0400 Subject: [PATCH 0855/1208] r/servicecat_prov_prod: New resource --- ..._aws_servicecatalog_provisioned_product.go | 449 ++++++++++++++++++ 1 file changed, 449 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_provisioned_product.go diff --git a/aws/resource_aws_servicecatalog_provisioned_product.go b/aws/resource_aws_servicecatalog_provisioned_product.go new file mode 100644 index 000000000000..354ea50e9a7a --- /dev/null +++ b/aws/resource_aws_servicecatalog_provisioned_product.go @@ -0,0 +1,449 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "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" + iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsServiceCatalogProvisionedProductCreate, + Read: resourceAwsServiceCatalogProvisionedProductRead, + Update: resourceAwsServiceCatalogProvisionedProductUpdate, + Delete: resourceAwsServiceCatalogProvisionedProductDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "accept_language": { //iu + Type: schema.TypeString, + Optional: true, + Default: "en", + ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), + }, + "created_time": { //o + Type: schema.TypeString, + Computed: true, + }, + "launch_role_arn": { //o + Type: schema.TypeString, + Computed: true, + }, + "name": { //oi + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "notification_arns": { //i + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "path_id": { //oiu + Type: schema.TypeString, + Optional: true, + Computed: true, + ExactlyOneOf: []string{ + "path_id", + "path_name", + }, + }, + "path_name": { //iu + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{ + "path_id", + "path_name", + }, + }, + "product_id": { //oiu + Type: schema.TypeString, + Optional: true, + Computed: true, + ExactlyOneOf: []string{ + "product_id", + "product_name", + }, + }, + "product_name": { //iu + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{ + "product_id", + "product_name", + }, + }, + "provisioning_artifact_id": { //oiu + Type: schema.TypeString, + Optional: true, + Computed: true, + ExactlyOneOf: []string{ + "provisioning_artifact_id", + "provisioning_artifact_name", + }, + }, + "provisioning_artifact_name": { //iu + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{ + "provisioning_artifact_id", + "provisioning_artifact_name", + }, + }, + "provisioning_parameters": { //iu + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { //i + Type: schema.TypeString, + Optional: true, + }, + "value": { //i + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "provisioning_preferences": { //iu + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "accounts": { //i + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "failure_tolerance_count": { //i + Type: schema.TypeInt, + Optional: true, + ExactlyOneOf: []string{ + "provisioning_preferences.0.failure_tolerance_count", + "provisioning_preferences.0.failure_tolerance_percentage", + }, + }, + "failure_tolerance_percentage": { //i + Type: schema.TypeInt, + Optional: true, + ExactlyOneOf: []string{ + "provisioning_preferences.0.failure_tolerance_count", + "provisioning_preferences.0.failure_tolerance_percentage", + }, + }, + "max_concurrency_count": { //i + Type: schema.TypeInt, + Optional: true, + ExactlyOneOf: []string{ + "provisioning_preferences.0.max_concurrency_count", + "provisioning_preferences.0.max_concurrency_percentage", + }, + }, + "max_concurrency_percentage": { //i + Type: schema.TypeInt, + Optional: true, + ExactlyOneOf: []string{ + "provisioning_preferences.0.max_concurrency_count", + "provisioning_preferences.0.max_concurrency_percentage", + }, + }, + "regions": { //i + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "record_errors": { //o + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "record_id": { //o + Type: schema.TypeString, + Computed: true, + }, + "record_type": { //o + Type: schema.TypeString, + Computed: true, + }, + "status": { //o + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), //iou + "tags_all": tagsSchemaComputed(), //iou + "type": { //o + Type: schema.TypeString, + Computed: true, + }, + "updated_time": { //o + Type: schema.TypeString, + Computed: true, + }, + }, + + CustomizeDiff: SetTagsDiff, + } +} + +func resourceAwsServiceCatalogProvisionedProductCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) + + input := &servicecatalog.CreateProductInput{ + IdempotencyToken: aws.String(resource.UniqueId()), + Name: aws.String(d.Get("name").(string)), + Owner: aws.String(d.Get("owner").(string)), + ProductType: aws.String(d.Get("type").(string)), + ProvisioningArtifactParameters: expandProvisioningArtifactParameters( + d.Get("provisioning_artifact_parameters").([]interface{})[0].(map[string]interface{}), + ), + } + + if v, ok := d.GetOk("accept_language"); ok { + input.AcceptLanguage = aws.String(v.(string)) + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("distributor"); ok { + input.Distributor = aws.String(v.(string)) + } + + if v, ok := d.GetOk("support_description"); ok { + input.SupportDescription = aws.String(v.(string)) + } + + if v, ok := d.GetOk("support_email"); ok { + input.SupportEmail = aws.String(v.(string)) + } + + if v, ok := d.GetOk("support_url"); ok { + input.SupportUrl = aws.String(v.(string)) + } + + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().ServicecatalogTags() + } + + var output *servicecatalog.CreateProductOutput + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + var err error + + output, err = conn.CreateProduct(input) + + if tfawserr.ErrMessageContains(err, servicecatalog.ErrCodeInvalidParametersException, "profile does not exist") { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + output, err = conn.CreateProduct(input) + } + + if err != nil { + return fmt.Errorf("error creating Service Catalog Provisioned Product: %w", err) + } + + if output == nil { + return fmt.Errorf("error creating Service Catalog Provisioned Product: empty response") + } + + if output.ProductViewDetail == nil || output.ProductViewDetail.ProductViewSummary == nil { + return fmt.Errorf("error creating Service Catalog Provisioned Product: no product view detail or summary") + } + + if output.ProvisioningArtifactDetail == nil { + return fmt.Errorf("error creating Service Catalog Provisioned Product: no provisioning artifact detail") + } + + d.SetId(aws.StringValue(output.ProductViewDetail.ProductViewSummary.ProductId)) + + if _, err := waiter.ProductReady(conn, aws.StringValue(input.AcceptLanguage), + aws.StringValue(output.ProductViewDetail.ProductViewSummary.ProductId)); err != nil { + return fmt.Errorf("error waiting for Service Catalog Provisioned Product (%s) to be ready: %w", d.Id(), err) + } + + return resourceAwsServiceCatalogProvisionedProductRead(d, meta) +} + +func resourceAwsServiceCatalogProvisionedProductRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + output, err := waiter.ProductReady(conn, d.Get("accept_language").(string), d.Id()) + + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + log.Printf("[WARN] Service Catalog Provisioned Product (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error describing Service Catalog Provisioned Product (%s): %w", d.Id(), err) + } + + if output == nil || output.ProductViewDetail == nil || output.ProductViewDetail.ProductViewSummary == nil { + return fmt.Errorf("error getting Service Catalog Provisioned Product (%s): empty response", d.Id()) + } + + pvs := output.ProductViewDetail.ProductViewSummary + + d.Set("arn", output.ProductViewDetail.ProductARN) + if output.ProductViewDetail.CreatedTime != nil { + d.Set("created_time", output.ProductViewDetail.CreatedTime.Format(time.RFC3339)) + } + d.Set("description", pvs.ShortDescription) + d.Set("distributor", pvs.Distributor) + d.Set("has_default_path", pvs.HasDefaultPath) + d.Set("name", pvs.Name) + d.Set("owner", pvs.Owner) + d.Set("status", output.ProductViewDetail.Status) + d.Set("support_description", pvs.SupportDescription) + d.Set("support_email", pvs.SupportEmail) + d.Set("support_url", pvs.SupportUrl) + d.Set("type", pvs.Type) + + tags := keyvaluetags.ServicecatalogKeyValueTags(output.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_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) + } + + return nil +} + +func resourceAwsServiceCatalogProvisionedProductUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + if d.HasChangesExcept("tags", "tags_all") { + input := &servicecatalog.UpdateProductInput{ + Id: aws.String(d.Id()), + } + + if v, ok := d.GetOk("accept_language"); ok { + input.AcceptLanguage = aws.String(v.(string)) + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("distributor"); ok { + input.Distributor = aws.String(v.(string)) + } + + if v, ok := d.GetOk("name"); ok { + input.Name = aws.String(v.(string)) + } + + if v, ok := d.GetOk("owner"); ok { + input.Owner = aws.String(v.(string)) + } + + if v, ok := d.GetOk("support_description"); ok { + input.SupportDescription = aws.String(v.(string)) + } + + if v, ok := d.GetOk("support_email"); ok { + input.SupportEmail = aws.String(v.(string)) + } + + if v, ok := d.GetOk("support_url"); ok { + input.SupportUrl = aws.String(v.(string)) + } + + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + _, err := conn.UpdateProduct(input) + + if tfawserr.ErrMessageContains(err, servicecatalog.ErrCodeInvalidParametersException, "profile does not exist") { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if tfresource.TimedOut(err) { + _, err = conn.UpdateProduct(input) + } + + if err != nil { + return fmt.Errorf("error updating Service Catalog Provisioned Product (%s): %w", d.Id(), err) + } + } + + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + + if err := keyvaluetags.ServiceCatalogProvisionedProductUpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating tags for Service Catalog Provisioned Product (%s): %w", d.Id(), err) + } + } + + return resourceAwsServiceCatalogProvisionedProductRead(d, meta) +} + +func resourceAwsServiceCatalogProvisionedProductDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + input := &servicecatalog.DeleteProductInput{ + Id: aws.String(d.Id()), + } + + if v, ok := d.GetOk("accept_language"); ok { + input.AcceptLanguage = aws.String(v.(string)) + } + + _, err := conn.DeleteProduct(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Service Catalog Provisioned Product (%s): %w", d.Id(), err) + } + + if _, err := waiter.ProductDeleted(conn, d.Get("accept_language").(string), d.Id()); err != nil { + return fmt.Errorf("error waiting for Service Catalog Provisioned Product (%s) to be deleted: %w", d.Id(), err) + } + + return nil +} From cc65a1cd4e857297bfb0c92c377ed20b8dc65710 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 14:33:32 -0400 Subject: [PATCH 0856/1208] tests/r/servicecat_prov_prod: New resource --- ...servicecatalog_provisioned_product_test.go | 465 ++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 aws/resource_aws_servicecatalog_provisioned_product_test.go diff --git a/aws/resource_aws_servicecatalog_provisioned_product_test.go b/aws/resource_aws_servicecatalog_provisioned_product_test.go new file mode 100644 index 000000000000..ff7c8a237cd9 --- /dev/null +++ b/aws/resource_aws_servicecatalog_provisioned_product_test.go @@ -0,0 +1,465 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + multierror "github.com/hashicorp/go-multierror" + "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" +) + +// add sweeper to delete known test servicecat products +func init() { + resource.AddTestSweepers("aws_servicecatalog_product", &resource.Sweeper{ + Name: "aws_servicecatalog_product", + Dependencies: []string{}, + F: testSweepServiceCatalogProducts, + }) +} + +func testSweepServiceCatalogProducts(region string) error { + client, err := sharedClientForRegion(region) + + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + + conn := client.(*AWSClient).scconn + sweepResources := make([]*testSweepResource, 0) + var errs *multierror.Error + + input := &servicecatalog.SearchProductsAsAdminInput{} + + err = conn.SearchProductsAsAdminPages(input, func(page *servicecatalog.SearchProductsAsAdminOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, pvd := range page.ProductViewDetails { + if pvd == nil || pvd.ProductViewSummary == nil { + continue + } + + id := aws.StringValue(pvd.ProductViewSummary.ProductId) + + r := resourceAwsServiceCatalogProduct() + d := r.Data(nil) + d.SetId(id) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } + + return !lastPage + }) + + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("error describing Service Catalog Products for %s: %w", region, err)) + } + + if err = testSweepResourceOrchestrator(sweepResources); err != nil { + errs = multierror.Append(errs, fmt.Errorf("error sweeping Service Catalog Products for %s: %w", region, err)) + } + + if testSweepSkipSweepError(errs.ErrorOrNil()) { + log.Printf("[WARN] Skipping Service Catalog Products sweep for %s: %s", region, errs) + return nil + } + + return errs.ErrorOrNil() +} + +func TestAccAWSServiceCatalogProduct_basic(t *testing.T) { + resourceName := "aws_servicecatalog_product.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProductConfig_basic(rName, "beskrivning", "supportbeskrivning"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProductExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "catalog", regexp.MustCompile(`product/prod-.*`)), + resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + testAccCheckResourceAttrRfc3339(resourceName, "created_time"), + resource.TestCheckResourceAttr(resourceName, "description", "beskrivning"), + resource.TestCheckResourceAttr(resourceName, "distributor", "distributör"), + resource.TestCheckResourceAttr(resourceName, "has_default_path", "false"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "owner", "ägare"), + resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.#", "1"), + resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.description", "artefaktbeskrivning"), + resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.disable_template_validation", "true"), + resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.name", rName), + resource.TestCheckResourceAttrSet(resourceName, "provisioning_artifact_parameters.0.template_url"), + resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.type", servicecatalog.ProvisioningArtifactTypeCloudFormationTemplate), + resource.TestCheckResourceAttr(resourceName, "status", waiter.ProductStatusCreated), + resource.TestCheckResourceAttr(resourceName, "support_description", "supportbeskrivning"), + resource.TestCheckResourceAttr(resourceName, "support_email", "support@example.com"), + resource.TestCheckResourceAttr(resourceName, "support_url", "http://example.com"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + resource.TestCheckResourceAttr(resourceName, "type", servicecatalog.ProductTypeCloudFormationTemplate), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "accept_language", + "provisioning_artifact_parameters", + }, + }, + }, + }) +} + +func TestAccAWSServiceCatalogProduct_disappears(t *testing.T) { + resourceName := "aws_servicecatalog_product.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProductConfig_basic(rName, rName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProductExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsServiceCatalogProduct(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSServiceCatalogProduct_update(t *testing.T) { + resourceName := "aws_servicecatalog_product.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProductConfig_basic(rName, "beskrivning", "supportbeskrivning"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProductExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", "beskrivning"), + resource.TestCheckResourceAttr(resourceName, "support_description", "supportbeskrivning"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + ), + }, + { + Config: testAccAWSServiceCatalogProductConfig_basic(rName, "ny beskrivning", "ny supportbeskrivning"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProductExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", "ny beskrivning"), + resource.TestCheckResourceAttr(resourceName, "support_description", "ny supportbeskrivning"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + ), + }, + }, + }) +} + +func TestAccAWSServiceCatalogProduct_updateTags(t *testing.T) { + resourceName := "aws_servicecatalog_product.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProductConfig_basic(rName, "beskrivning", "supportbeskrivning"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProductExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + ), + }, + { + Config: testAccAWSServiceCatalogProductConfig_updateTags(rName, "beskrivning", "supportbeskrivning"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProductExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.Yak", rName), + resource.TestCheckResourceAttr(resourceName, "tags.Environment", "natural"), + ), + }, + }, + }) +} + +func TestAccAWSServiceCatalogProduct_physicalID(t *testing.T) { + resourceName := "aws_servicecatalog_product.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProductConfig_physicalID(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProductExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "catalog", regexp.MustCompile(`product/prod-.*`)), + resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.#", "1"), + resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.description", "artefaktbeskrivning"), + resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.name", rName), + resource.TestCheckResourceAttrSet(resourceName, "provisioning_artifact_parameters.0.template_physical_id"), + testAccMatchResourceAttrRegionalARN( + resourceName, + "provisioning_artifact_parameters.0.template_physical_id", + "cloudformation", + regexp.MustCompile(fmt.Sprintf(`stack/%s/.*`, rName)), + ), + resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.type", servicecatalog.ProvisioningArtifactTypeCloudFormationTemplate), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "accept_language", + "provisioning_artifact_parameters", + }, + }, + }, + }) +} + +func testAccCheckAwsServiceCatalogProductDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).scconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_servicecatalog_product" { + continue + } + + input := &servicecatalog.DescribeProductAsAdminInput{ + Id: aws.String(rs.Primary.ID), + } + + output, err := conn.DescribeProductAsAdmin(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + continue + } + + if err != nil { + return fmt.Errorf("error getting Service Catalog Product (%s): %w", rs.Primary.ID, err) + } + + if output != nil { + return fmt.Errorf("Service Catalog Product (%s) still exists", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckAwsServiceCatalogProductExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + + if !ok { + return fmt.Errorf("resource not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).scconn + + input := &servicecatalog.DescribeProductAsAdminInput{ + Id: aws.String(rs.Primary.ID), + } + + _, err := conn.DescribeProductAsAdmin(input) + + if err != nil { + return fmt.Errorf("error describing Service Catalog Product (%s): %w", rs.Primary.ID, err) + } + + return nil + } +} + +func testAccAWSServiceCatalogProductConfigTemplateURLBase(rName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "test" { + bucket = %[1]q + acl = "private" + force_destroy = true +} + +resource "aws_s3_bucket_object" "test" { + bucket = aws_s3_bucket.test.id + key = "%[1]s.json" + + content = < Date: Thu, 20 May 2021 14:33:51 -0400 Subject: [PATCH 0857/1208] docs/r/servicecat_prov_prod: New resource --- ...ecatalog_provisioned_product.html.markdown | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 website/docs/r/servicecatalog_provisioned_product.html.markdown diff --git a/website/docs/r/servicecatalog_provisioned_product.html.markdown b/website/docs/r/servicecatalog_provisioned_product.html.markdown new file mode 100644 index 000000000000..d87ec6756a72 --- /dev/null +++ b/website/docs/r/servicecatalog_provisioned_product.html.markdown @@ -0,0 +1,84 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_product" +description: |- + Manages a Service Catalog Product +--- + +# Resource: aws_servicecatalog_product + +Manages a Service Catalog Product. + +~> **NOTE:** The user or role that uses this resources must have the `cloudformation:GetTemplate` IAM policy permission. This policy permission is required when using the `template_physical_id` argument. + +-> A "provisioning artifact" is also referred to as a "version." A "distributor" is also referred to as a "vendor." + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_servicecatalog_product" "example" { + name = "example" + owner = [aws_security_group.example.id] + type = aws_subnet.main.id + + provisioning_artifact_parameters { + template_url = "https://s3.amazonaws.com/cf-templates-ozkq9d3hgiq2-us-east-1/temp1.json" + } + + tags = { + foo = "bar" + } +} +``` + +## Argument Reference + +The following arguments are required: + +* `name` - (Required) Name of the product. +* `owner` - (Required) Owner of the product. +* `provisioning_artifact_parameters` - (Required) Configuration block for provisioning artifact (i.e., version) parameters. Detailed below. +* `type` - (Required) Type of product. Valid values are `CLOUD_FORMATION_TEMPLATE`, `MARKETPLACE`. + +The following arguments are optional: + +* `accept_language` - (Optional) Language code. Valid values: `en` (English), `jp` (Japanese), `zh` (Chinese). Default value is `en`. +* `description` - (Optional) Description of the product. +* `distributor` - (Optional) Distributor (i.e., vendor) of the product. +* `support_description` - (Optional) Support information about the product. +* `support_email` - (Optional) Contact email for product support. +* `support_url` - (Optional) Contact URL for product support. +* `tags` - (Optional) Tags to apply to the product. 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. + +### provisioning_artifact_parameters + +The following arguments are supported: + +* `description` - (Optional) Description of the provisioning artifact (i.e., version), including how it differs from the previous provisioning artifact. +* `disable_template_validation` - (Optional) Whether AWS Service Catalog stops validating the specified provisioning artifact template even if it is invalid. +* `name` - (Optional) Name of the provisioning artifact (for example, `v1`, `v2beta`). No spaces are allowed. +* `template_physical_id` - (Required if `template_url` is not provided) Template source as the physical ID of the resource that contains the template. Currently only supports CloudFormation stack ARN. Specify the physical ID as `arn:[partition]:cloudformation:[region]:[account ID]:stack/[stack name]/[resource ID]`. +* `template_url` - (Required if `template_physical_id` is not provided) Template source as URL of the CloudFormation template in Amazon S3. +* `type` - (Optional) Type of provisioning artifact. Valid values: `CLOUD_FORMATION_TEMPLATE`, `MARKETPLACE_AMI`, `MARKETPLACE_CAR` (Marketplace Clusters and AWS Resources). + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - ARN of the product. +* `created_time` - Time when the product was created. +* `has_default_path` - Whether the product has a default path. If the product does not have a default path, call `ListLaunchPaths` to disambiguate between paths. Otherwise, `ListLaunchPaths` is not required, and the output of ProductViewSummary can be used directly with `DescribeProvisioningParameters`. +* `id` - Product ID. +* `status` - Status of the product. +* `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_servicecatalog_product` can be imported using the product ID, e.g. + +``` +$ terraform import aws_servicecatalog_product.example arn:aws:catalog:us-east-1:123456789012:product/prod-dnigbtea24ste +``` From 648733db49cf8041d1e77979e4c283d5737be93f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 20 May 2021 14:35:37 -0400 Subject: [PATCH 0858/1208] r/servicecat_prov_prod: Add changelog --- .changelog/19459.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19459.txt diff --git a/.changelog/19459.txt b/.changelog/19459.txt new file mode 100644 index 000000000000..97b0e518160a --- /dev/null +++ b/.changelog/19459.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_servicecatalog_provisioned_product +``` \ No newline at end of file From 691222720d2bc7467b5d0b0035ddb7f4c41b03fb Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 09:41:18 -0400 Subject: [PATCH 0859/1208] servicecat: Work with RecordTags --- .../keyvaluetags/servicecatalog_tags.go | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/aws/internal/keyvaluetags/servicecatalog_tags.go b/aws/internal/keyvaluetags/servicecatalog_tags.go index 283247de2f95..9ad0c93da098 100644 --- a/aws/internal/keyvaluetags/servicecatalog_tags.go +++ b/aws/internal/keyvaluetags/servicecatalog_tags.go @@ -60,3 +60,38 @@ func ServiceCatalogProductUpdateTags(conn *servicecatalog.ServiceCatalog, identi return nil } + +func ServicecatalogRecordKeyValueTags(tags []*servicecatalog.RecordTag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +func ServiceCatalogProvisionedProductUpdateTags(conn *servicecatalog.ServiceCatalog, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + input := &servicecatalog.UpdateProductInput{ + Id: aws.String(identifier), + } + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input.RemoveTags = aws.StringSlice(removedTags.IgnoreAws().Keys()) + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input.AddTags = updatedTags.IgnoreAws().ServicecatalogTags() + } + + _, err := conn.UpdateProduct(input) + + if err != nil { + return fmt.Errorf("error updating tags for Service Catalog Product (%s): %w", identifier, err) + } + + return nil +} From 2575d13052371c1f3e60317f8295196b2ce54f2f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 09:43:04 -0400 Subject: [PATCH 0860/1208] i/r/servicecat_prov_prod: Add statuser --- .../service/servicecatalog/waiter/status.go | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/aws/internal/service/servicecatalog/waiter/status.go b/aws/internal/service/servicecatalog/waiter/status.go index f68a028e0a52..d1f39a9489af 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -356,3 +356,64 @@ func LaunchPathsStatus(conn *servicecatalog.ServiceCatalog, acceptLanguage, prod return summaries, servicecatalog.StatusAvailable, err } } + +func ProvisionedProductStatus(conn *servicecatalog.ServiceCatalog, acceptLanguage, id, name string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &servicecatalog.DescribeProvisionedProductInput{} + + if acceptLanguage != "" { + input.AcceptLanguage = aws.String(acceptLanguage) + } + + // one or the other but not both + if id != "" { + input.Id = aws.String(id) + } else if name != "" { + input.Name = aws.String(name) + } + + output, err := conn.DescribeProvisionedProduct(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil, StatusNotFound, err + } + + if err != nil { + return nil, servicecatalog.StatusFailed, err + } + + if output == nil || output.ProvisionedProductDetail == nil { + return nil, StatusNotFound, err + } + + return output, aws.StringValue(output.ProvisionedProductDetail.Status), err + } +} + +func RecordStatus(conn *servicecatalog.ServiceCatalog, acceptLanguage, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &servicecatalog.DescribeRecordInput{ + Id: aws.String(id), + } + + if acceptLanguage != "" { + input.AcceptLanguage = aws.String(acceptLanguage) + } + + output, err := conn.DescribeRecord(input) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil, StatusNotFound, err + } + + if err != nil { + return nil, servicecatalog.StatusFailed, err + } + + if output == nil || output.RecordDetail == nil { + return nil, StatusNotFound, err + } + + return output, aws.StringValue(output.RecordDetail.Status), err + } +} From 5b3c95982d5837c04cf19a83f6045f9e044db3a7 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 09:43:31 -0400 Subject: [PATCH 0861/1208] i/r/servicecat_prov_prod: Add waiter --- .../service/servicecatalog/waiter/waiter.go | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index 18162d265f92..0b1bd60785a1 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -43,6 +43,11 @@ const ( LaunchPathsReadyTimeout = 3 * time.Minute + ProvisionedProductReadyTimeout = 3 * time.Minute + ProvisionedProductDeleteTimeout = 3 * time.Minute + + RecordReadyTimeout = 3 * time.Minute + StatusNotFound = "NOT_FOUND" StatusUnavailable = "UNAVAILABLE" @@ -462,3 +467,50 @@ func LaunchPathsReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, produ return nil, err } + +func ProvisionedProductReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, id, name string) (*servicecatalog.DescribeProvisionedProductOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusNotFound, StatusUnavailable, servicecatalog.ProvisionedProductStatusUnderChange, servicecatalog.ProvisionedProductStatusPlanInProgress}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: ProvisionedProductStatus(conn, acceptLanguage, id, name), + Timeout: ProvisionedProductReadyTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*servicecatalog.DescribeProvisionedProductOutput); ok { + return output, err + } + + return nil, err +} + +func ProvisionedProductTerminated(conn *servicecatalog.ServiceCatalog, acceptLanguage, id, name string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{servicecatalog.StatusAvailable, servicecatalog.ProvisionedProductStatusUnderChange}, + Target: []string{StatusNotFound, StatusUnavailable}, + Refresh: ProvisionedProductStatus(conn, acceptLanguage, id, name), + Timeout: ProvisionedProductDeleteTimeout, + } + + _, err := stateConf.WaitForState() + + return err +} + +func RecordReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, id string) (*servicecatalog.DescribeRecordOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusNotFound, StatusUnavailable, servicecatalog.ProvisionedProductStatusUnderChange, servicecatalog.ProvisionedProductStatusPlanInProgress}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: RecordStatus(conn, acceptLanguage, id), + Timeout: RecordReadyTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*servicecatalog.DescribeRecordOutput); ok { + return output, err + } + + return nil, err +} From 6b7ff33a4d9d8ec10dfbf2beb1494c56d5739186 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 09:44:13 -0400 Subject: [PATCH 0862/1208] r/servicecat_prov_prod: Add guts of resource --- ..._aws_servicecatalog_provisioned_product.go | 544 +++++++++++++----- 1 file changed, 404 insertions(+), 140 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product.go b/aws/resource_aws_servicecatalog_provisioned_product.go index 354ea50e9a7a..9b47b2464585 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product.go +++ b/aws/resource_aws_servicecatalog_provisioned_product.go @@ -28,6 +28,15 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { State: schema.ImportStatePassthrough, }, + //i without u is ForceNew + //o = computed=true forcenew=nil + //u = computed=nil forcenew=nil (strange) + //uo = computed=true forcenew=nil (strange) + //i = computed=nil forcenew=true + //io = computed=true forcenew=true + //iu = computed=nil forcenew=nil + //iuo = computed=true forcenew=nil + Schema: map[string]*schema.Schema{ "accept_language": { //iu Type: schema.TypeString, @@ -35,15 +44,41 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { Default: "en", ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, - "created_time": { //o + "arn": { //o=ppd + Type: schema.TypeString, + Computed: true, + }, + "cloudwatch_dashboard_names": { //o=ppd + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "created_time": { //o=ppd,o=rd + Type: schema.TypeString, + Computed: true, + }, + "ignore_errors": { //d + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "last_provisioning_record_id": { //o=ppd + Type: schema.TypeString, + Computed: true, + }, + "last_record_id": { //o=ppd Type: schema.TypeString, Computed: true, }, - "launch_role_arn": { //o + "last_successful_provisioning_record_id": { //o=ppd Type: schema.TypeString, Computed: true, }, - "name": { //oi + "launch_role_arn": { //o=ppd,o=rd + Type: schema.TypeString, + Computed: true, + }, + "name": { //io=ppd,o=rd Type: schema.TypeString, Required: true, ForceNew: true, @@ -51,26 +86,25 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "notification_arns": { //i Type: schema.TypeList, Optional: true, + ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "path_id": { //oiu + "path_id": { //iuo=rd Type: schema.TypeString, Optional: true, Computed: true, - ExactlyOneOf: []string{ - "path_id", + ConflictsWith: []string{ "path_name", }, }, "path_name": { //iu Type: schema.TypeString, Optional: true, - ExactlyOneOf: []string{ + ConflictsWith: []string{ "path_id", - "path_name", }, }, - "product_id": { //oiu + "product_id": { //iuo=ppd,o=rd Type: schema.TypeString, Optional: true, Computed: true, @@ -87,7 +121,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "product_name", }, }, - "provisioning_artifact_id": { //oiu + "provisioning_artifact_id": { //iuo=ppd,o=rd Type: schema.TypeString, Optional: true, Computed: true, @@ -109,11 +143,15 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "key": { //i + "key": { //iu Type: schema.TypeString, + Required: true, + }, + "use_previous_value": { //u + Type: schema.TypeBool, Optional: true, }, - "value": { //i + "value": { //iu Type: schema.TypeString, Optional: true, }, @@ -126,12 +164,12 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "accounts": { //i + "accounts": { //iu Type: schema.TypeList, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "failure_tolerance_count": { //i + "failure_tolerance_count": { //iu Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ @@ -139,7 +177,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "provisioning_preferences.0.failure_tolerance_percentage", }, }, - "failure_tolerance_percentage": { //i + "failure_tolerance_percentage": { //iu Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ @@ -147,7 +185,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "provisioning_preferences.0.failure_tolerance_percentage", }, }, - "max_concurrency_count": { //i + "max_concurrency_count": { //iu Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ @@ -155,7 +193,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "provisioning_preferences.0.max_concurrency_percentage", }, }, - "max_concurrency_percentage": { //i + "max_concurrency_percentage": { //iu Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ @@ -163,7 +201,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "provisioning_preferences.0.max_concurrency_percentage", }, }, - "regions": { //i + "regions": { //iu Type: schema.TypeList, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, @@ -171,30 +209,22 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { }, }, }, - "record_errors": { //o - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "record_id": { //o - Type: schema.TypeString, - Computed: true, - }, - "record_type": { //o - Type: schema.TypeString, - Computed: true, + "retain_physical_resources": { //d + Type: schema.TypeBool, + Optional: true, + Default: false, }, - "status": { //o + "status": { //o=ppd,o=rd Type: schema.TypeString, Computed: true, }, - "tags": tagsSchema(), //iou - "tags_all": tagsSchemaComputed(), //iou - "type": { //o + "status_message": { //o=ppd Type: schema.TypeString, Computed: true, }, - "updated_time": { //o + "tags": tagsSchema(), //iuo=rd + "tags_all": tagsSchemaComputed(), //iuo=rd + "type": { //o=ppd,o=rd Type: schema.TypeString, Computed: true, }, @@ -206,52 +236,65 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { func resourceAwsServiceCatalogProvisionedProductCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).scconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) - input := &servicecatalog.CreateProductInput{ - IdempotencyToken: aws.String(resource.UniqueId()), - Name: aws.String(d.Get("name").(string)), - Owner: aws.String(d.Get("owner").(string)), - ProductType: aws.String(d.Get("type").(string)), - ProvisioningArtifactParameters: expandProvisioningArtifactParameters( - d.Get("provisioning_artifact_parameters").([]interface{})[0].(map[string]interface{}), - ), + input := &servicecatalog.ProvisionProductInput{ + ProvisionToken: aws.String(resource.UniqueId()), + ProvisionedProductName: aws.String(d.Get("name").(string)), } if v, ok := d.GetOk("accept_language"); ok { input.AcceptLanguage = aws.String(v.(string)) } - if v, ok := d.GetOk("description"); ok { - input.Description = aws.String(v.(string)) + if v, ok := d.GetOk("notification_arns"); ok && len(v.([]interface{})) > 0 { + input.NotificationArns = expandStringList(v.([]interface{})) + } + + if v, ok := d.GetOk("path_id"); ok { + input.PathId = aws.String(v.(string)) + } + + if v, ok := d.GetOk("path_name"); ok { + input.PathName = aws.String(v.(string)) } - if v, ok := d.GetOk("distributor"); ok { - input.Distributor = aws.String(v.(string)) + if v, ok := d.GetOk("product_id"); ok { + input.ProductId = aws.String(v.(string)) } - if v, ok := d.GetOk("support_description"); ok { - input.SupportDescription = aws.String(v.(string)) + if v, ok := d.GetOk("product_name"); ok { + input.ProductName = aws.String(v.(string)) } - if v, ok := d.GetOk("support_email"); ok { - input.SupportEmail = aws.String(v.(string)) + if v, ok := d.GetOk("provisioning_artifact_id"); ok { + input.ProvisioningArtifactId = aws.String(v.(string)) } - if v, ok := d.GetOk("support_url"); ok { - input.SupportUrl = aws.String(v.(string)) + if v, ok := d.GetOk("provisioning_artifact_name"); ok { + input.ProvisioningArtifactName = aws.String(v.(string)) + } + + if v, ok := d.GetOk("provisioning_parameters"); ok && len(v.([]interface{})) > 0 { + input.ProvisioningParameters = expandServiceCatalogProvisioningParameters(v.([]interface{})) + } + + if v, ok := d.GetOk("provisioning_preferences"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.ProvisioningPreferences = expandServiceCatalogProvisioningPreferences(v.([]interface{})[0].(map[string]interface{})) } if len(tags) > 0 { input.Tags = tags.IgnoreAws().ServicecatalogTags() } - var output *servicecatalog.CreateProductOutput + var output *servicecatalog.ProvisionProductOutput + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { var err error - output, err = conn.CreateProduct(input) + output, err = conn.ProvisionProduct(input) if tfawserr.ErrMessageContains(err, servicecatalog.ErrCodeInvalidParametersException, "profile does not exist") { return resource.RetryableError(err) @@ -265,31 +308,22 @@ func resourceAwsServiceCatalogProvisionedProductCreate(d *schema.ResourceData, m }) if tfresource.TimedOut(err) { - output, err = conn.CreateProduct(input) + output, err = conn.ProvisionProduct(input) } if err != nil { - return fmt.Errorf("error creating Service Catalog Provisioned Product: %w", err) + return fmt.Errorf("error provisioning Service Catalog Product: %w", err) } if output == nil { - return fmt.Errorf("error creating Service Catalog Provisioned Product: empty response") - } - - if output.ProductViewDetail == nil || output.ProductViewDetail.ProductViewSummary == nil { - return fmt.Errorf("error creating Service Catalog Provisioned Product: no product view detail or summary") + return fmt.Errorf("error provisioning Service Catalog Product: empty response") } - if output.ProvisioningArtifactDetail == nil { - return fmt.Errorf("error creating Service Catalog Provisioned Product: no provisioning artifact detail") + if output.RecordDetail == nil { + return fmt.Errorf("error provisioning Service Catalog Product: no product view detail or summary") } - d.SetId(aws.StringValue(output.ProductViewDetail.ProductViewSummary.ProductId)) - - if _, err := waiter.ProductReady(conn, aws.StringValue(input.AcceptLanguage), - aws.StringValue(output.ProductViewDetail.ProductViewSummary.ProductId)); err != nil { - return fmt.Errorf("error waiting for Service Catalog Provisioned Product (%s) to be ready: %w", d.Id(), err) - } + d.SetId(aws.StringValue(output.RecordDetail.ProvisionedProductId)) return resourceAwsServiceCatalogProvisionedProductRead(d, meta) } @@ -299,7 +333,20 @@ func resourceAwsServiceCatalogProvisionedProductRead(d *schema.ResourceData, met defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - output, err := waiter.ProductReady(conn, d.Get("accept_language").(string), d.Id()) + // There are two API operations for getting information about provisioned products: + // 1. DescribeProvisionedProduct (used in waiter.ProvisionedProductReady) and + // 2. DescribeRecord (used in waiter.RecordReady) + + // They provide some overlapping information. Most of the unique information available from + // DescribeRecord is available in the data source aws_servicecatalog_record. + + acceptLanguage := tfservicecatalog.ServiceCatalogAcceptLanguageEnglish + + if v, ok := d.GetOk("accept_language"); ok && v.(string) != "" { + acceptLanguage = v.(string) + } + + output, err := waiter.ProvisionedProductReady(conn, acceptLanguage, d.Id(), "") if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { log.Printf("[WARN] Service Catalog Provisioned Product (%s) not found, removing from state", d.Id()) @@ -311,28 +358,52 @@ func resourceAwsServiceCatalogProvisionedProductRead(d *schema.ResourceData, met return fmt.Errorf("error describing Service Catalog Provisioned Product (%s): %w", d.Id(), err) } - if output == nil || output.ProductViewDetail == nil || output.ProductViewDetail.ProductViewSummary == nil { + if output == nil || output.ProvisionedProductDetail == nil { return fmt.Errorf("error getting Service Catalog Provisioned Product (%s): empty response", d.Id()) } - pvs := output.ProductViewDetail.ProductViewSummary + detail := output.ProvisionedProductDetail - d.Set("arn", output.ProductViewDetail.ProductARN) - if output.ProductViewDetail.CreatedTime != nil { - d.Set("created_time", output.ProductViewDetail.CreatedTime.Format(time.RFC3339)) + d.Set("arn", detail.Arn) + d.Set("cloudwatch_dashboard_names", aws.StringValueSlice(flattenServiceCatalogCloudWatchDashboards(output.CloudWatchDashboards))) + + if detail.CreatedTime != nil { + d.Set("created_time", detail.CreatedTime.Format(time.RFC3339)) + } else { + d.Set("created_time", nil) } - d.Set("description", pvs.ShortDescription) - d.Set("distributor", pvs.Distributor) - d.Set("has_default_path", pvs.HasDefaultPath) - d.Set("name", pvs.Name) - d.Set("owner", pvs.Owner) - d.Set("status", output.ProductViewDetail.Status) - d.Set("support_description", pvs.SupportDescription) - d.Set("support_email", pvs.SupportEmail) - d.Set("support_url", pvs.SupportUrl) - d.Set("type", pvs.Type) - tags := keyvaluetags.ServicecatalogKeyValueTags(output.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + d.Set("last_provisioning_record_id", detail.LastProvisioningRecordId) + d.Set("last_record_id", detail.LastRecordId) + d.Set("last_successful_provisioning_record_id", detail.LastSuccessfulProvisioningRecordId) + d.Set("launch_role_arn", detail.LaunchRoleArn) + d.Set("name", detail.Name) + d.Set("product_id", detail.ProductId) + d.Set("provisioning_artifact_id", detail.ProvisioningArtifactId) + d.Set("status", detail.Status) + d.Set("status_message", detail.StatusMessage) + d.Set("type", detail.Type) + + // tags are only available from the record tied to the provisioned product + + recordOutput, err := waiter.RecordReady(conn, acceptLanguage, aws.StringValue(detail.LastProvisioningRecordId)) + + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + log.Printf("[WARN] Service Catalog Provisioned Product (%s) Record (%s) not found, unable to set tags", d.Id(), aws.StringValue(detail.LastProvisioningRecordId)) + return nil + } + + if err != nil { + return fmt.Errorf("error describing Service Catalog Provisioned Product (%s) Record (%s): %w", d.Id(), aws.StringValue(detail.LastProvisioningRecordId), err) + } + + if recordOutput == nil || recordOutput.RecordDetail == nil { + return fmt.Errorf("error getting Service Catalog Provisioned Product (%s) Record (%s): empty response", d.Id(), aws.StringValue(detail.LastProvisioningRecordId)) + } + + d.Set("path_id", recordOutput.RecordDetail.PathId) + + tags := keyvaluetags.ServicecatalogRecordKeyValueTags(recordOutput.RecordDetail.RecordTags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { @@ -349,72 +420,78 @@ func resourceAwsServiceCatalogProvisionedProductRead(d *schema.ResourceData, met func resourceAwsServiceCatalogProvisionedProductUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).scconn - if d.HasChangesExcept("tags", "tags_all") { - input := &servicecatalog.UpdateProductInput{ - Id: aws.String(d.Id()), - } + input := &servicecatalog.UpdateProvisionedProductInput{ + UpdateToken: aws.String(resource.UniqueId()), + ProvisionedProductId: aws.String(d.Id()), + } - if v, ok := d.GetOk("accept_language"); ok { - input.AcceptLanguage = aws.String(v.(string)) - } + if v, ok := d.GetOk("accept_language"); ok { + input.AcceptLanguage = aws.String(v.(string)) + } - if v, ok := d.GetOk("description"); ok { - input.Description = aws.String(v.(string)) - } + if v, ok := d.GetOk("path_id"); ok { + input.PathId = aws.String(v.(string)) + } - if v, ok := d.GetOk("distributor"); ok { - input.Distributor = aws.String(v.(string)) - } + if v, ok := d.GetOk("path_name"); ok { + input.PathName = aws.String(v.(string)) + } - if v, ok := d.GetOk("name"); ok { - input.Name = aws.String(v.(string)) - } + if v, ok := d.GetOk("product_id"); ok { + input.ProductId = aws.String(v.(string)) + } - if v, ok := d.GetOk("owner"); ok { - input.Owner = aws.String(v.(string)) - } + if v, ok := d.GetOk("product_name"); ok { + input.ProductName = aws.String(v.(string)) + } - if v, ok := d.GetOk("support_description"); ok { - input.SupportDescription = aws.String(v.(string)) - } + if v, ok := d.GetOk("provisioning_artifact_id"); ok { + input.ProvisionedProductId = aws.String(v.(string)) + } - if v, ok := d.GetOk("support_email"); ok { - input.SupportEmail = aws.String(v.(string)) - } + if v, ok := d.GetOk("provisioning_artifact_name"); ok { + input.ProvisionedProductName = aws.String(v.(string)) + } - if v, ok := d.GetOk("support_url"); ok { - input.SupportUrl = aws.String(v.(string)) - } + if v, ok := d.GetOk("provisioning_parameters"); ok && len(v.([]interface{})) > 0 { + input.ProvisioningParameters = expandServiceCatalogUpdateProvisioningParameters(v.([]interface{})) + } - err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { - _, err := conn.UpdateProduct(input) + if v, ok := d.GetOk("provisioning_preferences"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.ProvisioningPreferences = expandServiceCatalogUpdateProvisioningPreferences(v.([]interface{})[0].(map[string]interface{})) + } - if tfawserr.ErrMessageContains(err, servicecatalog.ErrCodeInvalidParametersException, "profile does not exist") { - return resource.RetryableError(err) - } + if d.HasChanges("tags", "tags_all") { + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) - if err != nil { - return resource.NonRetryableError(err) - } + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().ServicecatalogTags() + } else { + input.Tags = nil + } + } - return nil - }) + err := resource.Retry(iamwaiter.PropagationTimeout, func() *resource.RetryError { + _, err := conn.UpdateProvisionedProduct(input) - if tfresource.TimedOut(err) { - _, err = conn.UpdateProduct(input) + if tfawserr.ErrMessageContains(err, servicecatalog.ErrCodeInvalidParametersException, "profile does not exist") { + return resource.RetryableError(err) } if err != nil { - return fmt.Errorf("error updating Service Catalog Provisioned Product (%s): %w", d.Id(), err) + return resource.NonRetryableError(err) } - } - if d.HasChange("tags_all") { - o, n := d.GetChange("tags_all") + return nil + }) - if err := keyvaluetags.ServiceCatalogProvisionedProductUpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating tags for Service Catalog Provisioned Product (%s): %w", d.Id(), err) - } + if tfresource.TimedOut(err) { + _, err = conn.UpdateProvisionedProduct(input) + } + + if err != nil { + return fmt.Errorf("error updating Service Catalog Provisioned Product (%s): %w", d.Id(), err) } return resourceAwsServiceCatalogProvisionedProductRead(d, meta) @@ -423,27 +500,214 @@ func resourceAwsServiceCatalogProvisionedProductUpdate(d *schema.ResourceData, m func resourceAwsServiceCatalogProvisionedProductDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).scconn - input := &servicecatalog.DeleteProductInput{ - Id: aws.String(d.Id()), + input := &servicecatalog.TerminateProvisionedProductInput{ + TerminateToken: aws.String(resource.UniqueId()), + ProvisionedProductId: aws.String(d.Id()), } if v, ok := d.GetOk("accept_language"); ok { input.AcceptLanguage = aws.String(v.(string)) } - _, err := conn.DeleteProduct(input) + if v, ok := d.GetOk("ignore_errors"); ok { + input.IgnoreErrors = aws.Bool(v.(bool)) + } + + if v, ok := d.GetOk("retain_physical_resources"); ok { + input.RetainPhysicalResources = aws.Bool(v.(bool)) + } + + _, err := conn.TerminateProvisionedProduct(input) if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { return nil } if err != nil { - return fmt.Errorf("error deleting Service Catalog Provisioned Product (%s): %w", d.Id(), err) + return fmt.Errorf("error terminating Service Catalog Provisioned Product (%s): %w", d.Id(), err) } - if _, err := waiter.ProductDeleted(conn, d.Get("accept_language").(string), d.Id()); err != nil { - return fmt.Errorf("error waiting for Service Catalog Provisioned Product (%s) to be deleted: %w", d.Id(), err) + if err := waiter.ProvisionedProductTerminated(conn, d.Get("accept_language").(string), d.Id(), ""); err != nil { + return fmt.Errorf("error waiting for Service Catalog Provisioned Product (%s) to be terminated: %w", d.Id(), err) } return nil } + +func expandServiceCatalogProvisioningParameter(tfMap map[string]interface{}) *servicecatalog.ProvisioningParameter { + if tfMap == nil { + return nil + } + + apiObject := &servicecatalog.ProvisioningParameter{} + + if v, ok := tfMap["key"].(string); ok && v != "" { + apiObject.Key = aws.String(v) + } + + if v, ok := tfMap["value"].(string); ok && v != "" { + apiObject.Value = aws.String(v) + } + + return apiObject +} + +func expandServiceCatalogProvisioningParameters(tfList []interface{}) []*servicecatalog.ProvisioningParameter { + if len(tfList) == 0 { + return nil + } + + var apiObjects []*servicecatalog.ProvisioningParameter + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + + if !ok { + continue + } + + apiObject := expandServiceCatalogProvisioningParameter(tfMap) + + if apiObject == nil { + continue + } + + apiObjects = append(apiObjects, apiObject) + } + + return apiObjects +} + +func expandServiceCatalogProvisioningPreferences(tfMap map[string]interface{}) *servicecatalog.ProvisioningPreferences { + if tfMap == nil { + return nil + } + + apiObject := &servicecatalog.ProvisioningPreferences{} + + if v, ok := tfMap["account"].([]interface{}); ok && len(v) > 0 { + apiObject.StackSetAccounts = expandStringList(v) + } + + if v, ok := tfMap["failure_tolerance_count"].(int64); ok && v != 0 { + apiObject.StackSetFailureToleranceCount = aws.Int64(v) + } + + if v, ok := tfMap["failure_tolerance_percentage"].(int64); ok && v != 0 { + apiObject.StackSetFailureTolerancePercentage = aws.Int64(v) + } + + if v, ok := tfMap["max_concurrency_count"].(int64); ok && v != 0 { + apiObject.StackSetMaxConcurrencyCount = aws.Int64(v) + } + + if v, ok := tfMap["max_concurrency_percentage"].(int64); ok && v != 0 { + apiObject.StackSetMaxConcurrencyPercentage = aws.Int64(v) + } + + if v, ok := tfMap["regions"].([]interface{}); ok && len(v) > 0 { + apiObject.StackSetRegions = expandStringList(v) + } + + return apiObject +} + +func expandServiceCatalogUpdateProvisioningParameter(tfMap map[string]interface{}) *servicecatalog.UpdateProvisioningParameter { + if tfMap == nil { + return nil + } + + apiObject := &servicecatalog.UpdateProvisioningParameter{} + + if v, ok := tfMap["key"].(string); ok && v != "" { + apiObject.Key = aws.String(v) + } + + if v, ok := tfMap["use_previous_value"].(bool); ok && v { + apiObject.UsePreviousValue = aws.Bool(v) + } + + if v, ok := tfMap["value"].(string); ok && v != "" { + apiObject.Value = aws.String(v) + } + + return apiObject +} + +func expandServiceCatalogUpdateProvisioningParameters(tfList []interface{}) []*servicecatalog.UpdateProvisioningParameter { + if len(tfList) == 0 { + return nil + } + + var apiObjects []*servicecatalog.UpdateProvisioningParameter + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + + if !ok { + continue + } + + apiObject := expandServiceCatalogUpdateProvisioningParameter(tfMap) + + if apiObject == nil { + continue + } + + apiObjects = append(apiObjects, apiObject) + } + + return apiObjects +} + +func expandServiceCatalogUpdateProvisioningPreferences(tfMap map[string]interface{}) *servicecatalog.UpdateProvisioningPreferences { + if tfMap == nil { + return nil + } + + apiObject := &servicecatalog.UpdateProvisioningPreferences{} + + if v, ok := tfMap["account"].([]interface{}); ok && len(v) > 0 { + apiObject.StackSetAccounts = expandStringList(v) + } + + if v, ok := tfMap["failure_tolerance_count"].(int64); ok && v != 0 { + apiObject.StackSetFailureToleranceCount = aws.Int64(v) + } + + if v, ok := tfMap["failure_tolerance_percentage"].(int64); ok && v != 0 { + apiObject.StackSetFailureTolerancePercentage = aws.Int64(v) + } + + if v, ok := tfMap["max_concurrency_count"].(int64); ok && v != 0 { + apiObject.StackSetMaxConcurrencyCount = aws.Int64(v) + } + + if v, ok := tfMap["max_concurrency_percentage"].(int64); ok && v != 0 { + apiObject.StackSetMaxConcurrencyPercentage = aws.Int64(v) + } + + if v, ok := tfMap["regions"].([]interface{}); ok && len(v) > 0 { + apiObject.StackSetRegions = expandStringList(v) + } + + return apiObject +} + +func flattenServiceCatalogCloudWatchDashboards(apiObjects []*servicecatalog.CloudWatchDashboard) []*string { + if len(apiObjects) == 0 { + return nil + } + + var tfList []*string + + for _, apiObject := range apiObjects { + if apiObject == nil { + continue + } + + tfList = append(tfList, apiObject.Name) + } + + return tfList +} From 81c0fb95bcdd7fc8985b1eb8ae1d3e928ecc7358 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 09:44:53 -0400 Subject: [PATCH 0863/1208] tests/r/servicecat_prov_prod: Add test foundations --- ...servicecatalog_provisioned_product_test.go | 373 ++++-------------- 1 file changed, 81 insertions(+), 292 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product_test.go b/aws/resource_aws_servicecatalog_provisioned_product_test.go index ff7c8a237cd9..5341c9524988 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product_test.go +++ b/aws/resource_aws_servicecatalog_provisioned_product_test.go @@ -13,19 +13,20 @@ import ( "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" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" ) -// add sweeper to delete known test servicecat products +// add sweeper to delete known test servicecat provisioned products func init() { - resource.AddTestSweepers("aws_servicecatalog_product", &resource.Sweeper{ - Name: "aws_servicecatalog_product", + resource.AddTestSweepers("aws_servicecatalog_provisioned_product", &resource.Sweeper{ + Name: "aws_servicecatalog_provisioned_product", Dependencies: []string{}, - F: testSweepServiceCatalogProducts, + F: testSweepServiceCatalogProvisionedProducts, }) } -func testSweepServiceCatalogProducts(region string) error { +func testSweepServiceCatalogProvisionedProducts(region string) error { client, err := sharedClientForRegion(region) if err != nil { @@ -36,23 +37,26 @@ func testSweepServiceCatalogProducts(region string) error { sweepResources := make([]*testSweepResource, 0) var errs *multierror.Error - input := &servicecatalog.SearchProductsAsAdminInput{} + input := &servicecatalog.SearchProvisionedProductsInput{ + AccessLevelFilter: &servicecatalog.AccessLevelFilter{ + Key: aws.String(servicecatalog.AccessLevelFilterKeyAccount), + Value: aws.String(client.(*AWSClient).accountid), + }, + } - err = conn.SearchProductsAsAdminPages(input, func(page *servicecatalog.SearchProductsAsAdminOutput, lastPage bool) bool { + err = conn.SearchProvisionedProductsPages(input, func(page *servicecatalog.SearchProvisionedProductsOutput, lastPage bool) bool { if page == nil { return !lastPage } - for _, pvd := range page.ProductViewDetails { - if pvd == nil || pvd.ProductViewSummary == nil { + for _, detail := range page.ProvisionedProducts { + if detail == nil { continue } - id := aws.StringValue(pvd.ProductViewSummary.ProductId) - - r := resourceAwsServiceCatalogProduct() + r := resourceAwsServiceCatalogProvisionedProduct() d := r.Data(nil) - d.SetId(id) + d.SetId(aws.StringValue(detail.Id)) sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } @@ -61,86 +65,74 @@ func testSweepServiceCatalogProducts(region string) error { }) if err != nil { - errs = multierror.Append(errs, fmt.Errorf("error describing Service Catalog Products for %s: %w", region, err)) + errs = multierror.Append(errs, fmt.Errorf("error describing Service Catalog Provisioned Products for %s: %w", region, err)) } if err = testSweepResourceOrchestrator(sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("error sweeping Service Catalog Products for %s: %w", region, err)) + errs = multierror.Append(errs, fmt.Errorf("error sweeping Service Catalog Provisioned Products for %s: %w", region, err)) } if testSweepSkipSweepError(errs.ErrorOrNil()) { - log.Printf("[WARN] Skipping Service Catalog Products sweep for %s: %s", region, errs) + log.Printf("[WARN] Skipping Service Catalog Provisioned Products sweep for %s: %s", region, errs) return nil } return errs.ErrorOrNil() } -func TestAccAWSServiceCatalogProduct_basic(t *testing.T) { - resourceName := "aws_servicecatalog_product.test" +func TestAccAWSServiceCatalogProvisionedProduct_basic(t *testing.T) { + resourceName := "aws_servicecatalog_provisioned_product.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), Providers: testAccProviders, - CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, + CheckDestroy: testAccCheckAwsServiceCatalogProvisionedProductDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSServiceCatalogProductConfig_basic(rName, "beskrivning", "supportbeskrivning"), + Config: testAccAWSServiceCatalogProvisionedProductConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsServiceCatalogProductExists(resourceName), + testAccCheckAwsServiceCatalogProvisionedProductExists(resourceName), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "catalog", regexp.MustCompile(`product/prod-.*`)), + testAccMatchResourceAttrRegionalARN(resourceName, "launch_role_arn", "catalog", regexp.MustCompile(`product/prod-.*`)), resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), testAccCheckResourceAttrRfc3339(resourceName, "created_time"), - resource.TestCheckResourceAttr(resourceName, "description", "beskrivning"), - resource.TestCheckResourceAttr(resourceName, "distributor", "distributör"), - resource.TestCheckResourceAttr(resourceName, "has_default_path", "false"), resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttr(resourceName, "owner", "ägare"), - resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.#", "1"), - resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.description", "artefaktbeskrivning"), - resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.disable_template_validation", "true"), - resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.name", rName), - resource.TestCheckResourceAttrSet(resourceName, "provisioning_artifact_parameters.0.template_url"), - resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.type", servicecatalog.ProvisioningArtifactTypeCloudFormationTemplate), - resource.TestCheckResourceAttr(resourceName, "status", waiter.ProductStatusCreated), - resource.TestCheckResourceAttr(resourceName, "support_description", "supportbeskrivning"), - resource.TestCheckResourceAttr(resourceName, "support_email", "support@example.com"), - resource.TestCheckResourceAttr(resourceName, "support_url", "http://example.com"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - resource.TestCheckResourceAttr(resourceName, "type", servicecatalog.ProductTypeCloudFormationTemplate), + resource.TestCheckResourceAttrPair(resourceName, "product_id", "aws_servicecatalog_product", "id"), + resource.TestCheckResourceAttrPair(resourceName, "provisioning_artifact_name", "aws_servicecatalog_product", "provisioning_artifact_parameters.0.name"), + resource.TestCheckResourceAttrSet(resourceName, "last_provisioning_record_id"), + resource.TestCheckResourceAttrSet(resourceName, "last_record_id"), + resource.TestCheckResourceAttrSet(resourceName, "last_successful_provisioning_record_id"), + resource.TestCheckResourceAttr(resourceName, "status", servicecatalog.StatusAvailable), + resource.TestCheckResourceAttr(resourceName, "type", "CFN_STACKSET"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "accept_language", - "provisioning_artifact_parameters", - }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{}, }, }, }) } -func TestAccAWSServiceCatalogProduct_disappears(t *testing.T) { - resourceName := "aws_servicecatalog_product.test" +func TestAccAWSServiceCatalogProvisionedProduct_disappears(t *testing.T) { + resourceName := "aws_servicecatalog_provisioned_product.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), Providers: testAccProviders, - CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, + CheckDestroy: testAccCheckAwsServiceCatalogProvisionedProductDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSServiceCatalogProductConfig_basic(rName, rName, rName), + Config: testAccAWSServiceCatalogProvisionedProductConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsServiceCatalogProductExists(resourceName), - testAccCheckResourceDisappears(testAccProvider, resourceAwsServiceCatalogProduct(), resourceName), + testAccCheckAwsServiceCatalogProvisionedProductExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsServiceCatalogProvisionedProduct(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -148,143 +140,29 @@ func TestAccAWSServiceCatalogProduct_disappears(t *testing.T) { }) } -func TestAccAWSServiceCatalogProduct_update(t *testing.T) { - resourceName := "aws_servicecatalog_product.test" - rName := acctest.RandomWithPrefix("tf-acc-test") - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSServiceCatalogProductConfig_basic(rName, "beskrivning", "supportbeskrivning"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAwsServiceCatalogProductExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "description", "beskrivning"), - resource.TestCheckResourceAttr(resourceName, "support_description", "supportbeskrivning"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - ), - }, - { - Config: testAccAWSServiceCatalogProductConfig_basic(rName, "ny beskrivning", "ny supportbeskrivning"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAwsServiceCatalogProductExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "description", "ny beskrivning"), - resource.TestCheckResourceAttr(resourceName, "support_description", "ny supportbeskrivning"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - ), - }, - }, - }) -} - -func TestAccAWSServiceCatalogProduct_updateTags(t *testing.T) { - resourceName := "aws_servicecatalog_product.test" - rName := acctest.RandomWithPrefix("tf-acc-test") - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSServiceCatalogProductConfig_basic(rName, "beskrivning", "supportbeskrivning"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAwsServiceCatalogProductExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - ), - }, - { - Config: testAccAWSServiceCatalogProductConfig_updateTags(rName, "beskrivning", "supportbeskrivning"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAwsServiceCatalogProductExists(resourceName), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.Yak", rName), - resource.TestCheckResourceAttr(resourceName, "tags.Environment", "natural"), - ), - }, - }, - }) -} - -func TestAccAWSServiceCatalogProduct_physicalID(t *testing.T) { - resourceName := "aws_servicecatalog_product.test" - rName := acctest.RandomWithPrefix("tf-acc-test") - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsServiceCatalogProductDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSServiceCatalogProductConfig_physicalID(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAwsServiceCatalogProductExists(resourceName), - testAccMatchResourceAttrRegionalARN(resourceName, "arn", "catalog", regexp.MustCompile(`product/prod-.*`)), - resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.#", "1"), - resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.description", "artefaktbeskrivning"), - resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.name", rName), - resource.TestCheckResourceAttrSet(resourceName, "provisioning_artifact_parameters.0.template_physical_id"), - testAccMatchResourceAttrRegionalARN( - resourceName, - "provisioning_artifact_parameters.0.template_physical_id", - "cloudformation", - regexp.MustCompile(fmt.Sprintf(`stack/%s/.*`, rName)), - ), - resource.TestCheckResourceAttr(resourceName, "provisioning_artifact_parameters.0.type", servicecatalog.ProvisioningArtifactTypeCloudFormationTemplate), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "accept_language", - "provisioning_artifact_parameters", - }, - }, - }, - }) -} - -func testAccCheckAwsServiceCatalogProductDestroy(s *terraform.State) error { +func testAccCheckAwsServiceCatalogProvisionedProductDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).scconn for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_servicecatalog_product" { + if rs.Type != "aws_servicecatalog_provisioned_product" { continue } - input := &servicecatalog.DescribeProductAsAdminInput{ - Id: aws.String(rs.Primary.ID), - } - - output, err := conn.DescribeProductAsAdmin(input) + err := waiter.ProvisionedProductTerminated(conn, tfservicecatalog.ServiceCatalogAcceptLanguageEnglish, rs.Primary.ID, "") if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { continue } if err != nil { - return fmt.Errorf("error getting Service Catalog Product (%s): %w", rs.Primary.ID, err) - } - - if output != nil { - return fmt.Errorf("Service Catalog Product (%s) still exists", rs.Primary.ID) + return fmt.Errorf("error getting Service Catalog Provisioned Product (%s): %w", rs.Primary.ID, err) } } return nil } -func testAccCheckAwsServiceCatalogProductExists(resourceName string) resource.TestCheckFunc { +func testAccCheckAwsServiceCatalogProvisionedProductExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -294,21 +172,17 @@ func testAccCheckAwsServiceCatalogProductExists(resourceName string) resource.Te conn := testAccProvider.Meta().(*AWSClient).scconn - input := &servicecatalog.DescribeProductAsAdminInput{ - Id: aws.String(rs.Primary.ID), - } - - _, err := conn.DescribeProductAsAdmin(input) + _, err := waiter.ProvisionedProductReady(conn, tfservicecatalog.ServiceCatalogAcceptLanguageEnglish, rs.Primary.ID, "") if err != nil { - return fmt.Errorf("error describing Service Catalog Product (%s): %w", rs.Primary.ID, err) + return fmt.Errorf("error describing Service Catalog Provisioned Product (%s): %w", rs.Primary.ID, err) } return nil } } -func testAccAWSServiceCatalogProductConfigTemplateURLBase(rName string) string { +func testAccAWSServiceCatalogProvisionedProductConfigTemplateURLBase(rName string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = %[1]q @@ -320,46 +194,36 @@ resource "aws_s3_bucket_object" "test" { bucket = aws_s3_bucket.test.id key = "%[1]s.json" - content = < Date: Wed, 26 May 2021 09:45:30 -0400 Subject: [PATCH 0864/1208] docs/r/servicecat_prod: Fix import typo --- website/docs/r/servicecatalog_product.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/servicecatalog_product.html.markdown b/website/docs/r/servicecatalog_product.html.markdown index d87ec6756a72..7eed80accaa9 100644 --- a/website/docs/r/servicecatalog_product.html.markdown +++ b/website/docs/r/servicecatalog_product.html.markdown @@ -71,7 +71,7 @@ In addition to all arguments above, the following attributes are exported: * `arn` - ARN of the product. * `created_time` - Time when the product was created. * `has_default_path` - Whether the product has a default path. If the product does not have a default path, call `ListLaunchPaths` to disambiguate between paths. Otherwise, `ListLaunchPaths` is not required, and the output of ProductViewSummary can be used directly with `DescribeProvisioningParameters`. -* `id` - Product ID. +* `id` - Product ID. For example, `prod-dnigbtea24ste`. * `status` - Status of the product. * `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). @@ -80,5 +80,5 @@ In addition to all arguments above, the following attributes are exported: `aws_servicecatalog_product` can be imported using the product ID, e.g. ``` -$ terraform import aws_servicecatalog_product.example arn:aws:catalog:us-east-1:123456789012:product/prod-dnigbtea24ste +$ terraform import aws_servicecatalog_product.example prod-dnigbtea24ste ``` From 3a8f2640608020e66b327571b7df5f43a208794a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 09:45:55 -0400 Subject: [PATCH 0865/1208] docs/r/servicecat_prov_prod: Add bulk of docs --- ...ecatalog_provisioned_product.html.markdown | 96 ++++++++++++------- 1 file changed, 64 insertions(+), 32 deletions(-) diff --git a/website/docs/r/servicecatalog_provisioned_product.html.markdown b/website/docs/r/servicecatalog_provisioned_product.html.markdown index d87ec6756a72..7ed6d59567fd 100644 --- a/website/docs/r/servicecatalog_provisioned_product.html.markdown +++ b/website/docs/r/servicecatalog_provisioned_product.html.markdown @@ -1,25 +1,29 @@ --- subcategory: "Service Catalog" layout: "aws" -page_title: "AWS: aws_servicecatalog_product" +page_title: "AWS: aws_servicecatalog_provisioned_product" description: |- - Manages a Service Catalog Product + Manages a Service Catalog Provisioned Product --- -# Resource: aws_servicecatalog_product +# Resource: aws_servicecatalog_provisioned_product -Manages a Service Catalog Product. +This resource provisions and manages a Service Catalog provisioned product. -~> **NOTE:** The user or role that uses this resources must have the `cloudformation:GetTemplate` IAM policy permission. This policy permission is required when using the `template_physical_id` argument. +A provisioned product is a resourced instance of a product. For example, provisioning a product based on a CloudFormation template launches a CloudFormation stack and its underlying resources. --> A "provisioning artifact" is also referred to as a "version." A "distributor" is also referred to as a "vendor." +Like this resource, the `aws_servicecatalog_record` data source also provides information about a provisioned product. Although a Service Catalog record provides some overlapping information with this resource, a record is tied to a provisioned product event, such as provisioning, termination, and updating. + +-> **Tip:** If you include conflicted keys as tags, AWS will report an error, "Parameter validation failed: Missing required parameter in Tags[N]:Value". + +-> **Tip:** A "provisioning artifact" is also referred to as a "version." A "distributor" is also referred to as a "vendor." ## Example Usage ### Basic Usage ```terraform -resource "aws_servicecatalog_product" "example" { +resource "aws_servicecatalog_provisioned_product" "example" { name = "example" owner = [aws_security_group.example.id] type = aws_subnet.main.id @@ -38,47 +42,75 @@ resource "aws_servicecatalog_product" "example" { The following arguments are required: -* `name` - (Required) Name of the product. -* `owner` - (Required) Owner of the product. -* `provisioning_artifact_parameters` - (Required) Configuration block for provisioning artifact (i.e., version) parameters. Detailed below. -* `type` - (Required) Type of product. Valid values are `CLOUD_FORMATION_TEMPLATE`, `MARKETPLACE`. +* `name` - (Required) User-friendly name of the provisioned product. The following arguments are optional: * `accept_language` - (Optional) Language code. Valid values: `en` (English), `jp` (Japanese), `zh` (Chinese). Default value is `en`. -* `description` - (Optional) Description of the product. -* `distributor` - (Optional) Distributor (i.e., vendor) of the product. -* `support_description` - (Optional) Support information about the product. -* `support_email` - (Optional) Contact email for product support. -* `support_url` - (Optional) Contact URL for product support. -* `tags` - (Optional) Tags to apply to the product. 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. +* `ignore_errors` - (Optional) _Only applies to deleting._ If set to `true`, AWS Service Catalog stops managing the specified provisioned product even if it cannot delete the underlying resources. The default value is `false`. +* `notification_arns` - (Optional) Passed to CloudFormation. The SNS topic ARNs to which to publish stack-related events. +* `path_id` - (Optional) Path identifier of the product. This value is optional if the product has a default path, and required if the product has more than one path. To list the paths for a product, use `aws_servicecatalog_launch_paths`. When required, you must provide `path_id` or `path_name`, but not both. +* `path_name` - (Optional) Name of the path. You must provide `path_id` or `path_name`, but not both. +* `product_id` - (Optional) Product identifier. For example, `prod-abcdzk7xy33qa`. You must provide `product_id` or `product_name`, but not both. +* `product_name` - (Optional) Name of the product. You must provide `product_id` or `product_name`, but not both. +* `provisioning_artifact_id` - (Optional) Identifier of the provisioning artifact. For example, `pa-4abcdjnxjj6ne`. You must provide the `provisioning_artifact_id` or `provisioning_artifact_name`, but not both. +* `provisioning_artifact_name` - (Optional) Name of the provisioning artifact. You must provide the `provisioning_artifact_id` or `provisioning_artifact_name`, but not both. +* `provisioning_parameters` - (Optional) Configuration block with parameters specified by the administrator that are required for provisioning the product. See details below. +* `provisioning_preferences` - (Optional) Configuration block with information about the provisioning preferences for a stack set. See details below. +* `retain_physical_resources` - (Optional) _Only applies to deleting._ Whether to delete the Service Catalog provisioned product but leave the CloudFormation stack, stack set, or the underlying resources of the deleted provisioned product. The default value is `false`. +* `tags` - (Optional) Tags to apply to the provisioned product. 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. + +### provisioning_parameters + +The following arguments are supported: + +* `key` - (Required) Parameter key. +* `use_previous_value` - (Optional) Whether to ignore `value` and keep the previous parameter value. Ignored when initially provisioning a product. +* `value` - (Optional) Parameter value. + +### provisioning_preferences -### provisioning_artifact_parameters +All of the `provisioning_preferences` are only applicable to a `CFN_STACKSET` provisioned product type. The following arguments are supported: -* `description` - (Optional) Description of the provisioning artifact (i.e., version), including how it differs from the previous provisioning artifact. -* `disable_template_validation` - (Optional) Whether AWS Service Catalog stops validating the specified provisioning artifact template even if it is invalid. -* `name` - (Optional) Name of the provisioning artifact (for example, `v1`, `v2beta`). No spaces are allowed. -* `template_physical_id` - (Required if `template_url` is not provided) Template source as the physical ID of the resource that contains the template. Currently only supports CloudFormation stack ARN. Specify the physical ID as `arn:[partition]:cloudformation:[region]:[account ID]:stack/[stack name]/[resource ID]`. -* `template_url` - (Required if `template_physical_id` is not provided) Template source as URL of the CloudFormation template in Amazon S3. -* `type` - (Optional) Type of provisioning artifact. Valid values: `CLOUD_FORMATION_TEMPLATE`, `MARKETPLACE_AMI`, `MARKETPLACE_CAR` (Marketplace Clusters and AWS Resources). +* `accounts` - (Optional) One or more AWS accounts that will have access to the provisioned product. The AWS accounts specified should be within the list of accounts in the STACKSET constraint. To get the list of accounts in the STACKSET constraint, use the `aws_servicecatalog_provisioning_parameters` data source. If no values are specified, the default value is all accounts from the STACKSET constraint. +* `failure_tolerance_count` - (Optional) Number of accounts, per region, for which this operation can fail before AWS Service Catalog stops the operation in that region. If the operation is stopped in a region, AWS Service Catalog doesn't attempt the operation in any subsequent regions. You must specify either `failure_tolerance_count` or `failure_tolerance_percentage`, but not both. The default value is 0 if no value is specified. +* `failure_tolerance_percentage` - (Optional) Percentage of accounts, per region, for which this stack operation can fail before AWS Service Catalog stops the operation in that region. If the operation is stopped in a region, AWS Service Catalog doesn't attempt the operation in any subsequent regions. When calculating the number of accounts based on the specified percentage, AWS Service Catalog rounds down to the next whole number. You must specify either `failure_tolerance_count` or `failure_tolerance_percentage`, but not both. +* `max_concurrency_count` - (Optional) Maximum number of accounts in which to perform this operation at one time. This is dependent on the value of `failure_tolerance_count`. `max_concurrency_count` is at most one more than the `failure_tolerance_count`. Note that this setting lets you specify the maximum for operations. For large deployments, under certain circumstances the actual number of accounts acted upon concurrently may be lower due to service throttling. You must specify either `max_concurrency_count` or `max_concurrency_percentage`, but not both. +* `max_concurrency_percentage` - (Optional) Maximum percentage of accounts in which to perform this operation at one time. When calculating the number of accounts based on the specified percentage, AWS Service Catalog rounds down to the next whole number. This is true except in cases where rounding down would result is zero. In this case, AWS Service Catalog sets the number as 1 instead. Note that this setting lets you specify the maximum for operations. For large deployments, under certain circumstances the actual number of accounts acted upon concurrently may be lower due to service throttling. You must specify either `max_concurrency_count` or `max_concurrency_percentage`, but not both. +* `regions` - (Optional) One or more AWS Regions where the provisioned product will be available. The specified regions should be within the list of regions from the STACKSET constraint. To get the list of regions in the STACKSET constraint, use the `aws_servicecatalog_provisioning_parameters` data source. If no values are specified, the default value is all regions from the STACKSET constraint. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `arn` - ARN of the product. -* `created_time` - Time when the product was created. -* `has_default_path` - Whether the product has a default path. If the product does not have a default path, call `ListLaunchPaths` to disambiguate between paths. Otherwise, `ListLaunchPaths` is not required, and the output of ProductViewSummary can be used directly with `DescribeProvisioningParameters`. -* `id` - Product ID. -* `status` - Status of the product. -* `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). +* `arn` - ARN of the provisioned product. +* `cloudwatch_dashboard_names` - Set of CloudWatch dashboards that were created when provisioning the product. +* `created_time` - Time when the provisioned product was created. +* `id` - Provisioned Product ID. +* `last_provisioning_record_id` - Record identifier of the last request performed on this provisioned product of the following types: `ProvisionedProduct`, `UpdateProvisionedProduct`, `ExecuteProvisionedProductPlan`, `TerminateProvisionedProduct`. +* `last_record_id` - Record identifier of the last request performed on this provisioned product. +* `last_successful_provisioning_record_id` - Record identifier of the last successful request performed on this provisioned product of the following types: `ProvisionedProduct`, `UpdateProvisionedProduct`, `ExecuteProvisionedProductPlan`, `TerminateProvisionedProduct`. +* `launch_role_arn` - ARN of the launch role associated with the provisioned product. +* `status` - Current status of the provisioned product. See meanings below. +* `status_message` - Current status message of the provisioned product. +* `tags_all` - 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). +* `type` - Type of provisioned product. Valid values are `CFN_STACK` and `CFN_STACKSET`. + +### status Meanings + +* `AVAILABLE` - Stable state, ready to perform any operation. The most recent operation succeeded and completed. +* `UNDER_CHANGE` - Transitive state. Operations performed might not have +valid results. Wait for an `AVAILABLE` status before performing operations. +* `TAINTED` - Stable state, ready to perform any operation. The stack has completed the requested operation but is not exactly what was requested. For example, a request to update to a new version failed and the stack rolled back to the current version. +* `ERROR` - An unexpected error occurred. The provisioned product exists but the stack is not running. For example, CloudFormation received a parameter value that was not valid and could not launch the stack. +* `PLAN_IN_PROGRESS` - Transitive state. The plan operations were performed to provision a new product, but resources have not yet been created. After reviewing the list of resources to be created, execute the plan. Wait for an `AVAILABLE` status before performing operations. ## Import -`aws_servicecatalog_product` can be imported using the product ID, e.g. +`aws_servicecatalog_provisioned_product` can be imported using the provisioned product ID, e.g. ``` -$ terraform import aws_servicecatalog_product.example arn:aws:catalog:us-east-1:123456789012:product/prod-dnigbtea24ste +$ terraform import aws_servicecatalog_provisioned_product.example pp-dnigbtea24ste ``` From 7cf4fb5ec4ebbf808675addcd1a3d91b4960182a Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 26 May 2021 14:01:15 -0400 Subject: [PATCH 0866/1208] r/servicecat_prov_prod: Remove extraneous check --- aws/resource_aws_servicecatalog_provisioned_product.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product.go b/aws/resource_aws_servicecatalog_provisioned_product.go index 9b47b2464585..de6f78f64b18 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product.go +++ b/aws/resource_aws_servicecatalog_provisioned_product.go @@ -342,7 +342,7 @@ func resourceAwsServiceCatalogProvisionedProductRead(d *schema.ResourceData, met acceptLanguage := tfservicecatalog.ServiceCatalogAcceptLanguageEnglish - if v, ok := d.GetOk("accept_language"); ok && v.(string) != "" { + if v, ok := d.GetOk("accept_language"); ok { acceptLanguage = v.(string) } From ac9d0c4a389ea10dacac9521abd16f42367a0f90 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 10:28:51 -0400 Subject: [PATCH 0867/1208] r/servicecat_prov_prod: Update enum --- aws/resource_aws_servicecatalog_provisioned_product.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product.go b/aws/resource_aws_servicecatalog_provisioned_product.go index de6f78f64b18..1b266afe7e71 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product.go +++ b/aws/resource_aws_servicecatalog_provisioned_product.go @@ -340,7 +340,7 @@ func resourceAwsServiceCatalogProvisionedProductRead(d *schema.ResourceData, met // They provide some overlapping information. Most of the unique information available from // DescribeRecord is available in the data source aws_servicecatalog_record. - acceptLanguage := tfservicecatalog.ServiceCatalogAcceptLanguageEnglish + acceptLanguage := tfservicecatalog.AcceptLanguageEnglish if v, ok := d.GetOk("accept_language"); ok { acceptLanguage = v.(string) From f249a760abe26bd3bc09199d1550a662c7e9e324 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 10:29:34 -0400 Subject: [PATCH 0868/1208] tests/r/servicecat_prov_prod: Build up tests --- ...servicecatalog_provisioned_product_test.go | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product_test.go b/aws/resource_aws_servicecatalog_provisioned_product_test.go index 5341c9524988..53b878f803f1 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product_test.go +++ b/aws/resource_aws_servicecatalog_provisioned_product_test.go @@ -148,7 +148,7 @@ func testAccCheckAwsServiceCatalogProvisionedProductDestroy(s *terraform.State) continue } - err := waiter.ProvisionedProductTerminated(conn, tfservicecatalog.ServiceCatalogAcceptLanguageEnglish, rs.Primary.ID, "") + err := waiter.ProvisionedProductTerminated(conn, tfservicecatalog.AcceptLanguageEnglish, rs.Primary.ID, "") if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { continue @@ -172,7 +172,7 @@ func testAccCheckAwsServiceCatalogProvisionedProductExists(resourceName string) conn := testAccProvider.Meta().(*AWSClient).scconn - _, err := waiter.ProvisionedProductReady(conn, tfservicecatalog.ServiceCatalogAcceptLanguageEnglish, rs.Primary.ID, "") + _, err := waiter.ProvisionedProductReady(conn, tfservicecatalog.AcceptLanguageEnglish, rs.Primary.ID, "") if err != nil { return fmt.Errorf("error describing Service Catalog Provisioned Product (%s): %w", rs.Primary.ID, err) @@ -239,6 +239,34 @@ resource "aws_servicecatalog_product" "test" { Name = %[1]q } } + +resource "aws_servicecatalog_portfolio" "test" { + name = %[1]q + description = %[1]q + provider_name = %[1]q +} + +resource "aws_servicecatalog_product_portfolio_association" "test" { + portfolio_id = aws_servicecatalog_portfolio.test.id + product_id = aws_servicecatalog_product.test.id +} + +data "aws_caller_identity" "current" {} + +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + +resource "aws_servicecatalog_principal_portfolio_association" "test" { + portfolio_id = aws_servicecatalog_portfolio.test.id + principal_arn = data.aws_iam_session_context.current.issuer_arn # unfortunately, you cannot get launch_path for arbitrary role - only caller +} + +data "aws_servicecatalog_launch_paths" "test" { + product_id = aws_servicecatalog_product_portfolio_association.test.product_id # less depends_on + + depends_on = [aws_servicecatalog_principal_portfolio_association.test] +} `, rName) } @@ -248,7 +276,7 @@ resource "aws_servicecatalog_provisioned_product" "test" { name = %[1]q product_id = aws_servicecatalog_product.test.id provisioning_artifact_name = %[1]q - path_name = %[1]q + path_id = data.aws_servicecatalog_launch_paths.test.summaries.0.path_id } `, rName)) } From 99320de7412277a279c734f14f34d9f751973c0e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 11:48:11 -0400 Subject: [PATCH 0869/1208] i/servicecatalog: Add waiter status --- aws/internal/service/servicecatalog/waiter/waiter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index 0b1bd60785a1..28558273fd39 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -501,7 +501,7 @@ func ProvisionedProductTerminated(conn *servicecatalog.ServiceCatalog, acceptLan func RecordReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, id string) (*servicecatalog.DescribeRecordOutput, error) { stateConf := &resource.StateChangeConf{ Pending: []string{StatusNotFound, StatusUnavailable, servicecatalog.ProvisionedProductStatusUnderChange, servicecatalog.ProvisionedProductStatusPlanInProgress}, - Target: []string{servicecatalog.StatusAvailable}, + Target: []string{servicecatalog.RecordStatusSucceeded, servicecatalog.StatusAvailable}, Refresh: RecordStatus(conn, acceptLanguage, id), Timeout: RecordReadyTimeout, } From c112efd8824b35b8a263acf705f4b522693b85aa Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 11:49:25 -0400 Subject: [PATCH 0870/1208] tests/r/servicecat_prov_prod: Fix response if wait finds none --- aws/resource_aws_servicecatalog_provisioned_product.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product.go b/aws/resource_aws_servicecatalog_provisioned_product.go index 1b266afe7e71..63e1796ab37c 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product.go +++ b/aws/resource_aws_servicecatalog_provisioned_product.go @@ -527,7 +527,13 @@ func resourceAwsServiceCatalogProvisionedProductDelete(d *schema.ResourceData, m return fmt.Errorf("error terminating Service Catalog Provisioned Product (%s): %w", d.Id(), err) } - if err := waiter.ProvisionedProductTerminated(conn, d.Get("accept_language").(string), d.Id(), ""); err != nil { + err = waiter.ProvisionedProductTerminated(conn, d.Get("accept_language").(string), d.Id(), "") + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { return fmt.Errorf("error waiting for Service Catalog Provisioned Product (%s) to be terminated: %w", d.Id(), err) } From ab4eadce8d45ab40edf8178f96dba68ac304dbe8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 11:52:35 -0400 Subject: [PATCH 0871/1208] tests/r/servicecat_prov_prod: Put tests right --- ...servicecatalog_provisioned_product_test.go | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product_test.go b/aws/resource_aws_servicecatalog_provisioned_product_test.go index 53b878f803f1..115b9e91eb91 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product_test.go +++ b/aws/resource_aws_servicecatalog_provisioned_product_test.go @@ -94,25 +94,30 @@ func TestAccAWSServiceCatalogProvisionedProduct_basic(t *testing.T) { Config: testAccAWSServiceCatalogProvisionedProductConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsServiceCatalogProvisionedProductExists(resourceName), - testAccMatchResourceAttrRegionalARN(resourceName, "arn", "catalog", regexp.MustCompile(`product/prod-.*`)), - testAccMatchResourceAttrRegionalARN(resourceName, "launch_role_arn", "catalog", regexp.MustCompile(`product/prod-.*`)), - resource.TestCheckResourceAttr(resourceName, "accept_language", "en"), + resource.TestCheckResourceAttr(resourceName, "accept_language", tfservicecatalog.AcceptLanguageEnglish), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", servicecatalog.ServiceName, regexp.MustCompile(fmt.Sprintf(`stack/%s/pp-.*`, rName))), testAccCheckResourceAttrRfc3339(resourceName, "created_time"), - resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttrPair(resourceName, "product_id", "aws_servicecatalog_product", "id"), - resource.TestCheckResourceAttrPair(resourceName, "provisioning_artifact_name", "aws_servicecatalog_product", "provisioning_artifact_parameters.0.name"), resource.TestCheckResourceAttrSet(resourceName, "last_provisioning_record_id"), resource.TestCheckResourceAttrSet(resourceName, "last_record_id"), resource.TestCheckResourceAttrSet(resourceName, "last_successful_provisioning_record_id"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "path_id", "data.aws_servicecatalog_launch_paths.test", "summaries.0.path_id"), + resource.TestCheckResourceAttrPair(resourceName, "product_id", "aws_servicecatalog_product.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "provisioning_artifact_name", "aws_servicecatalog_product.test", "provisioning_artifact_parameters.0.name"), resource.TestCheckResourceAttr(resourceName, "status", servicecatalog.StatusAvailable), - resource.TestCheckResourceAttr(resourceName, "type", "CFN_STACKSET"), + resource.TestCheckResourceAttr(resourceName, "type", "CFN_STACK"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "accept_language", + "ignore_errors", + "provisioning_artifact_name", + "retain_physical_resources", + }, }, }, }) From 118dde5fe5f1a6018d38a8bbe09643dfacec0136 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 11:59:45 -0400 Subject: [PATCH 0872/1208] tests/r/servicecat_prov_prod: Placate linter dragon --- aws/resource_aws_servicecatalog_provisioned_product_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product_test.go b/aws/resource_aws_servicecatalog_provisioned_product_test.go index 115b9e91eb91..27126827928e 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product_test.go +++ b/aws/resource_aws_servicecatalog_provisioned_product_test.go @@ -281,7 +281,7 @@ resource "aws_servicecatalog_provisioned_product" "test" { name = %[1]q product_id = aws_servicecatalog_product.test.id provisioning_artifact_name = %[1]q - path_id = data.aws_servicecatalog_launch_paths.test.summaries.0.path_id + path_id = data.aws_servicecatalog_launch_paths.test.summaries[0].path_id } `, rName)) } From 488fc844c266bc9f004a79e8cfc1827bd56c6cc0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 14:01:41 -0400 Subject: [PATCH 0873/1208] internal/keyvaluetags: Remove unused func --- .../keyvaluetags/servicecatalog_tags.go | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/aws/internal/keyvaluetags/servicecatalog_tags.go b/aws/internal/keyvaluetags/servicecatalog_tags.go index 9ad0c93da098..ee5bcdd42c90 100644 --- a/aws/internal/keyvaluetags/servicecatalog_tags.go +++ b/aws/internal/keyvaluetags/servicecatalog_tags.go @@ -70,28 +70,3 @@ func ServicecatalogRecordKeyValueTags(tags []*servicecatalog.RecordTag) KeyValue return New(m) } - -func ServiceCatalogProvisionedProductUpdateTags(conn *servicecatalog.ServiceCatalog, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { - oldTags := New(oldTagsMap) - newTags := New(newTagsMap) - - input := &servicecatalog.UpdateProductInput{ - Id: aws.String(identifier), - } - - if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { - input.RemoveTags = aws.StringSlice(removedTags.IgnoreAws().Keys()) - } - - if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { - input.AddTags = updatedTags.IgnoreAws().ServicecatalogTags() - } - - _, err := conn.UpdateProduct(input) - - if err != nil { - return fmt.Errorf("error updating tags for Service Catalog Product (%s): %w", identifier, err) - } - - return nil -} From 6be8983ee9dd33675e24e0fba079e82b924d48f9 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 14:02:49 -0400 Subject: [PATCH 0874/1208] tests/r/servicecat_prov_prod: Add new test for tags, udpate --- ...servicecatalog_provisioned_product_test.go | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/aws/resource_aws_servicecatalog_provisioned_product_test.go b/aws/resource_aws_servicecatalog_provisioned_product_test.go index 27126827928e..762273181f42 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product_test.go +++ b/aws/resource_aws_servicecatalog_provisioned_product_test.go @@ -145,6 +145,36 @@ func TestAccAWSServiceCatalogProvisionedProduct_disappears(t *testing.T) { }) } +func TestAccAWSServiceCatalogProvisionedProduct_tags(t *testing.T) { + resourceName := "aws_servicecatalog_provisioned_product.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsServiceCatalogProvisionedProductDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogProvisionedProductConfig_tags(rName, "Name", rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProvisionedProductExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + ), + }, + { + Config: testAccAWSServiceCatalogProvisionedProductConfig_tags(rName, "NotName", rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsServiceCatalogProvisionedProductExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.NotName", rName), + ), + }, + }, + }) +} + func testAccCheckAwsServiceCatalogProvisionedProductDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).scconn @@ -251,6 +281,20 @@ resource "aws_servicecatalog_portfolio" "test" { provider_name = %[1]q } +resource "aws_servicecatalog_constraint" "test" { + description = %[1]q + portfolio_id = aws_servicecatalog_product_portfolio_association.test.portfolio_id + product_id = aws_servicecatalog_product_portfolio_association.test.product_id + type = "RESOURCE_UPDATE" + + parameters = jsonencode({ + Version = "2.0" + Properties = { + TagUpdateOnProvisionedProduct = "ALLOWED" + } + }) +} + resource "aws_servicecatalog_product_portfolio_association" "test" { portfolio_id = aws_servicecatalog_portfolio.test.id product_id = aws_servicecatalog_product.test.id @@ -285,3 +329,18 @@ resource "aws_servicecatalog_provisioned_product" "test" { } `, rName)) } + +func testAccAWSServiceCatalogProvisionedProductConfig_tags(rName, tagKey, tagValue string) string { + return composeConfig(testAccAWSServiceCatalogProvisionedProductConfigTemplateURLBase(rName), fmt.Sprintf(` +resource "aws_servicecatalog_provisioned_product" "test" { + name = %[1]q + product_id = aws_servicecatalog_constraint.test.product_id + provisioning_artifact_name = %[1]q + path_id = data.aws_servicecatalog_launch_paths.test.summaries[0].path_id + + tags = { + %[2]s = %[3]q + } +} +`, rName, tagKey, tagValue)) +} From 623d7b1d876c9eda70084196f33745ac2503000f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 14:03:42 -0400 Subject: [PATCH 0875/1208] r/servicecat_prov_prod: Cleanup, make sure only one of either/or --- ..._aws_servicecatalog_provisioned_product.go | 93 ++++++++----------- 1 file changed, 39 insertions(+), 54 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product.go b/aws/resource_aws_servicecatalog_provisioned_product.go index 63e1796ab37c..45710ed3ed0f 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product.go +++ b/aws/resource_aws_servicecatalog_provisioned_product.go @@ -28,68 +28,59 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { State: schema.ImportStatePassthrough, }, - //i without u is ForceNew - //o = computed=true forcenew=nil - //u = computed=nil forcenew=nil (strange) - //uo = computed=true forcenew=nil (strange) - //i = computed=nil forcenew=true - //io = computed=true forcenew=true - //iu = computed=nil forcenew=nil - //iuo = computed=true forcenew=nil - Schema: map[string]*schema.Schema{ - "accept_language": { //iu + "accept_language": { Type: schema.TypeString, Optional: true, Default: "en", ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, - "arn": { //o=ppd + "arn": { Type: schema.TypeString, Computed: true, }, - "cloudwatch_dashboard_names": { //o=ppd + "cloudwatch_dashboard_names": { Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "created_time": { //o=ppd,o=rd + "created_time": { Type: schema.TypeString, Computed: true, }, - "ignore_errors": { //d + "ignore_errors": { Type: schema.TypeBool, Optional: true, Default: false, }, - "last_provisioning_record_id": { //o=ppd + "last_provisioning_record_id": { Type: schema.TypeString, Computed: true, }, - "last_record_id": { //o=ppd + "last_record_id": { Type: schema.TypeString, Computed: true, }, - "last_successful_provisioning_record_id": { //o=ppd + "last_successful_provisioning_record_id": { Type: schema.TypeString, Computed: true, }, - "launch_role_arn": { //o=ppd,o=rd + "launch_role_arn": { Type: schema.TypeString, Computed: true, }, - "name": { //io=ppd,o=rd + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "notification_arns": { //i + "notification_arns": { Type: schema.TypeList, Optional: true, ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "path_id": { //iuo=rd + "path_id": { Type: schema.TypeString, Optional: true, Computed: true, @@ -97,14 +88,14 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "path_name", }, }, - "path_name": { //iu + "path_name": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{ "path_id", }, }, - "product_id": { //iuo=ppd,o=rd + "product_id": { Type: schema.TypeString, Optional: true, Computed: true, @@ -113,7 +104,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "product_name", }, }, - "product_name": { //iu + "product_name": { Type: schema.TypeString, Optional: true, ExactlyOneOf: []string{ @@ -121,7 +112,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "product_name", }, }, - "provisioning_artifact_id": { //iuo=ppd,o=rd + "provisioning_artifact_id": { Type: schema.TypeString, Optional: true, Computed: true, @@ -130,7 +121,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "provisioning_artifact_name", }, }, - "provisioning_artifact_name": { //iu + "provisioning_artifact_name": { Type: schema.TypeString, Optional: true, ExactlyOneOf: []string{ @@ -138,38 +129,38 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "provisioning_artifact_name", }, }, - "provisioning_parameters": { //iu + "provisioning_parameters": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "key": { //iu + "key": { Type: schema.TypeString, Required: true, }, - "use_previous_value": { //u + "use_previous_value": { Type: schema.TypeBool, Optional: true, }, - "value": { //iu + "value": { Type: schema.TypeString, Optional: true, }, }, }, }, - "provisioning_preferences": { //iu + "provisioning_preferences": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "accounts": { //iu + "accounts": { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, - "failure_tolerance_count": { //iu + "failure_tolerance_count": { Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ @@ -177,7 +168,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "provisioning_preferences.0.failure_tolerance_percentage", }, }, - "failure_tolerance_percentage": { //iu + "failure_tolerance_percentage": { Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ @@ -185,7 +176,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "provisioning_preferences.0.failure_tolerance_percentage", }, }, - "max_concurrency_count": { //iu + "max_concurrency_count": { Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ @@ -193,7 +184,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "provisioning_preferences.0.max_concurrency_percentage", }, }, - "max_concurrency_percentage": { //iu + "max_concurrency_percentage": { Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ @@ -201,7 +192,7 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { "provisioning_preferences.0.max_concurrency_percentage", }, }, - "regions": { //iu + "regions": { Type: schema.TypeList, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, @@ -209,22 +200,22 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { }, }, }, - "retain_physical_resources": { //d + "retain_physical_resources": { Type: schema.TypeBool, Optional: true, Default: false, }, - "status": { //o=ppd,o=rd + "status": { Type: schema.TypeString, Computed: true, }, - "status_message": { //o=ppd + "status_message": { Type: schema.TypeString, Computed: true, }, - "tags": tagsSchema(), //iuo=rd - "tags_all": tagsSchemaComputed(), //iuo=rd - "type": { //o=ppd,o=rd + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), + "type": { Type: schema.TypeString, Computed: true, }, @@ -431,26 +422,20 @@ func resourceAwsServiceCatalogProvisionedProductUpdate(d *schema.ResourceData, m if v, ok := d.GetOk("path_id"); ok { input.PathId = aws.String(v.(string)) - } - - if v, ok := d.GetOk("path_name"); ok { + } else if v, ok := d.GetOk("path_name"); ok { input.PathName = aws.String(v.(string)) } if v, ok := d.GetOk("product_id"); ok { input.ProductId = aws.String(v.(string)) - } - - if v, ok := d.GetOk("product_name"); ok { + } else if v, ok := d.GetOk("product_name"); ok { input.ProductName = aws.String(v.(string)) } if v, ok := d.GetOk("provisioning_artifact_id"); ok { - input.ProvisionedProductId = aws.String(v.(string)) - } - - if v, ok := d.GetOk("provisioning_artifact_name"); ok { - input.ProvisionedProductName = aws.String(v.(string)) + input.ProvisioningArtifactId = aws.String(v.(string)) + } else if v, ok := d.GetOk("provisioning_artifact_name"); ok { + input.ProvisioningArtifactName = aws.String(v.(string)) } if v, ok := d.GetOk("provisioning_parameters"); ok && len(v.([]interface{})) > 0 { From 57d6dcbe7fb54868d412c0023529ca932ee30195 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 14:15:01 -0400 Subject: [PATCH 0876/1208] tests/r/servicecat_prov_prod: Appease linter --- aws/resource_aws_servicecatalog_provisioned_product_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product_test.go b/aws/resource_aws_servicecatalog_provisioned_product_test.go index 762273181f42..7f467b7b1e34 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product_test.go +++ b/aws/resource_aws_servicecatalog_provisioned_product_test.go @@ -339,7 +339,7 @@ resource "aws_servicecatalog_provisioned_product" "test" { path_id = data.aws_servicecatalog_launch_paths.test.summaries[0].path_id tags = { - %[2]s = %[3]q + %[2]q = %[3]q } } `, rName, tagKey, tagValue)) From 177b7faba9a79d95d5a51b7bb4d58cb8cc27f408 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 14:18:42 -0400 Subject: [PATCH 0877/1208] r/servicecatalog_prov_prod: Lintery --- aws/resource_aws_servicecatalog_provisioned_product_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product_test.go b/aws/resource_aws_servicecatalog_provisioned_product_test.go index 7f467b7b1e34..03c8ed001c48 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product_test.go +++ b/aws/resource_aws_servicecatalog_provisioned_product_test.go @@ -287,7 +287,7 @@ resource "aws_servicecatalog_constraint" "test" { product_id = aws_servicecatalog_product_portfolio_association.test.product_id type = "RESOURCE_UPDATE" - parameters = jsonencode({ + parameters = jsonencode({ Version = "2.0" Properties = { TagUpdateOnProvisionedProduct = "ALLOWED" From 4d4b4e05f125c079fafcdc3750456e82c34b33af Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 14:24:39 -0400 Subject: [PATCH 0878/1208] r/servicecat_prov_prod: Rename argument --- ..._aws_servicecatalog_provisioned_product.go | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product.go b/aws/resource_aws_servicecatalog_provisioned_product.go index 45710ed3ed0f..b6d9cda7c248 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product.go +++ b/aws/resource_aws_servicecatalog_provisioned_product.go @@ -149,7 +149,12 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { }, }, }, - "provisioning_preferences": { + "retain_physical_resources": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "stack_set_provisioning_preferences": { Type: schema.TypeList, Optional: true, MaxItems: 1, @@ -164,32 +169,32 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ - "provisioning_preferences.0.failure_tolerance_count", - "provisioning_preferences.0.failure_tolerance_percentage", + "stack_set_provisioning_preferences.0.failure_tolerance_count", + "stack_set_provisioning_preferences.0.failure_tolerance_percentage", }, }, "failure_tolerance_percentage": { Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ - "provisioning_preferences.0.failure_tolerance_count", - "provisioning_preferences.0.failure_tolerance_percentage", + "stack_set_provisioning_preferences.0.failure_tolerance_count", + "stack_set_provisioning_preferences.0.failure_tolerance_percentage", }, }, "max_concurrency_count": { Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ - "provisioning_preferences.0.max_concurrency_count", - "provisioning_preferences.0.max_concurrency_percentage", + "stack_set_provisioning_preferences.0.max_concurrency_count", + "stack_set_provisioning_preferences.0.max_concurrency_percentage", }, }, "max_concurrency_percentage": { Type: schema.TypeInt, Optional: true, ExactlyOneOf: []string{ - "provisioning_preferences.0.max_concurrency_count", - "provisioning_preferences.0.max_concurrency_percentage", + "stack_set_provisioning_preferences.0.max_concurrency_count", + "stack_set_provisioning_preferences.0.max_concurrency_percentage", }, }, "regions": { @@ -200,11 +205,6 @@ func resourceAwsServiceCatalogProvisionedProduct() *schema.Resource { }, }, }, - "retain_physical_resources": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, "status": { Type: schema.TypeString, Computed: true, @@ -272,7 +272,7 @@ func resourceAwsServiceCatalogProvisionedProductCreate(d *schema.ResourceData, m input.ProvisioningParameters = expandServiceCatalogProvisioningParameters(v.([]interface{})) } - if v, ok := d.GetOk("provisioning_preferences"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + if v, ok := d.GetOk("stack_set_provisioning_preferences"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.ProvisioningPreferences = expandServiceCatalogProvisioningPreferences(v.([]interface{})[0].(map[string]interface{})) } @@ -442,7 +442,7 @@ func resourceAwsServiceCatalogProvisionedProductUpdate(d *schema.ResourceData, m input.ProvisioningParameters = expandServiceCatalogUpdateProvisioningParameters(v.([]interface{})) } - if v, ok := d.GetOk("provisioning_preferences"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + if v, ok := d.GetOk("stack_set_provisioning_preferences"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.ProvisioningPreferences = expandServiceCatalogUpdateProvisioningPreferences(v.([]interface{})[0].(map[string]interface{})) } From 7e939458577e6e2bd7e0f91937e62608ed7e9453 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 14:24:55 -0400 Subject: [PATCH 0879/1208] docs/r/servicecat_prov_prod: Rename argument --- .../docs/r/servicecatalog_provisioned_product.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/servicecatalog_provisioned_product.html.markdown b/website/docs/r/servicecatalog_provisioned_product.html.markdown index 7ed6d59567fd..ba6325f01805 100644 --- a/website/docs/r/servicecatalog_provisioned_product.html.markdown +++ b/website/docs/r/servicecatalog_provisioned_product.html.markdown @@ -56,8 +56,8 @@ The following arguments are optional: * `provisioning_artifact_id` - (Optional) Identifier of the provisioning artifact. For example, `pa-4abcdjnxjj6ne`. You must provide the `provisioning_artifact_id` or `provisioning_artifact_name`, but not both. * `provisioning_artifact_name` - (Optional) Name of the provisioning artifact. You must provide the `provisioning_artifact_id` or `provisioning_artifact_name`, but not both. * `provisioning_parameters` - (Optional) Configuration block with parameters specified by the administrator that are required for provisioning the product. See details below. -* `provisioning_preferences` - (Optional) Configuration block with information about the provisioning preferences for a stack set. See details below. * `retain_physical_resources` - (Optional) _Only applies to deleting._ Whether to delete the Service Catalog provisioned product but leave the CloudFormation stack, stack set, or the underlying resources of the deleted provisioned product. The default value is `false`. +* `stack_set_provisioning_preferences` - (Optional) Configuration block with information about the provisioning preferences for a stack set. See details below. * `tags` - (Optional) Tags to apply to the provisioned product. 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. ### provisioning_parameters @@ -68,9 +68,9 @@ The following arguments are supported: * `use_previous_value` - (Optional) Whether to ignore `value` and keep the previous parameter value. Ignored when initially provisioning a product. * `value` - (Optional) Parameter value. -### provisioning_preferences +### stack_set_provisioning_preferences -All of the `provisioning_preferences` are only applicable to a `CFN_STACKSET` provisioned product type. +All of the `stack_set_provisioning_preferences` are only applicable to a `CFN_STACKSET` provisioned product type. The following arguments are supported: From 1b30ee6ae59cc86b480c993626702153518b0dfa Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 30 Jun 2021 15:15:24 -0400 Subject: [PATCH 0880/1208] tests/r/servicecat_prov_prod: Rework dependencies --- aws/resource_aws_servicecatalog_provisioned_product_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_servicecatalog_provisioned_product_test.go b/aws/resource_aws_servicecatalog_provisioned_product_test.go index 03c8ed001c48..7ec399859d26 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product_test.go +++ b/aws/resource_aws_servicecatalog_provisioned_product_test.go @@ -296,7 +296,7 @@ resource "aws_servicecatalog_constraint" "test" { } resource "aws_servicecatalog_product_portfolio_association" "test" { - portfolio_id = aws_servicecatalog_portfolio.test.id + portfolio_id = aws_servicecatalog_principal_portfolio_association.test.portfolio_id # avoid depends_on product_id = aws_servicecatalog_product.test.id } @@ -312,9 +312,7 @@ resource "aws_servicecatalog_principal_portfolio_association" "test" { } data "aws_servicecatalog_launch_paths" "test" { - product_id = aws_servicecatalog_product_portfolio_association.test.product_id # less depends_on - - depends_on = [aws_servicecatalog_principal_portfolio_association.test] + product_id = aws_servicecatalog_product_portfolio_association.test.product_id # avoid depends_on } `, rName) } From 95df4cbea07904ae369600b989b4b4a360a7eb75 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 30 Jun 2021 15:15:52 -0400 Subject: [PATCH 0881/1208] r/servicecat_prov_prod: Add retry to avoid not found error --- aws/resource_aws_servicecatalog_provisioned_product.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/resource_aws_servicecatalog_provisioned_product.go b/aws/resource_aws_servicecatalog_provisioned_product.go index b6d9cda7c248..b43ea4b46367 100644 --- a/aws/resource_aws_servicecatalog_provisioned_product.go +++ b/aws/resource_aws_servicecatalog_provisioned_product.go @@ -291,6 +291,10 @@ func resourceAwsServiceCatalogProvisionedProductCreate(d *schema.ResourceData, m return resource.RetryableError(err) } + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return resource.RetryableError(err) + } + if err != nil { return resource.NonRetryableError(err) } From ee0a8315a4948f316a6c914ab943c88904be6a6f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 30 Jun 2021 15:45:21 -0400 Subject: [PATCH 0882/1208] i/servicecat: Make state changes more stable --- .../service/servicecatalog/waiter/waiter.go | 90 ++++++++++++------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index 28558273fd39..e7d3e14c53d6 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -59,10 +59,13 @@ const ( func ProductReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID string) (*servicecatalog.DescribeProductAsAdminOutput, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{servicecatalog.StatusCreating, StatusNotFound, StatusUnavailable}, - Target: []string{servicecatalog.StatusAvailable, StatusCreated}, - Refresh: ProductStatus(conn, acceptLanguage, productID), - Timeout: ProductReadyTimeout, + Pending: []string{servicecatalog.StatusCreating, StatusNotFound, StatusUnavailable}, + Target: []string{servicecatalog.StatusAvailable, StatusCreated}, + Refresh: ProductStatus(conn, acceptLanguage, productID), + Timeout: ProductReadyTimeout, + ContinuousTargetOccurence: 2, + NotFoundChecks: 10, + MinTimeout: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -228,10 +231,13 @@ func OrganizationsAccessStable(conn *servicecatalog.ServiceCatalog) (string, err func ConstraintReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, id string) (*servicecatalog.DescribeConstraintOutput, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{StatusNotFound, servicecatalog.StatusCreating, StatusUnavailable}, - Target: []string{servicecatalog.StatusAvailable}, - Refresh: ConstraintStatus(conn, acceptLanguage, id), - Timeout: ConstraintReadyTimeout, + Pending: []string{StatusNotFound, servicecatalog.StatusCreating, StatusUnavailable}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: ConstraintStatus(conn, acceptLanguage, id), + Timeout: ConstraintReadyTimeout, + ContinuousTargetOccurence: 2, + NotFoundChecks: 10, + MinTimeout: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -258,10 +264,13 @@ func ConstraintDeleted(conn *servicecatalog.ServiceCatalog, acceptLanguage, id s func ProductPortfolioAssociationReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, portfolioID, productID string) (*servicecatalog.PortfolioDetail, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{StatusNotFound, StatusUnavailable}, - Target: []string{servicecatalog.StatusAvailable}, - Refresh: ProductPortfolioAssociationStatus(conn, acceptLanguage, portfolioID, productID), - Timeout: ProductPortfolioAssociationReadyTimeout, + Pending: []string{StatusNotFound, StatusUnavailable}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: ProductPortfolioAssociationStatus(conn, acceptLanguage, portfolioID, productID), + Timeout: ProductPortfolioAssociationReadyTimeout, + ContinuousTargetOccurence: 2, + NotFoundChecks: 10, + MinTimeout: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -382,10 +391,13 @@ func TagOptionResourceAssociationDeleted(conn *servicecatalog.ServiceCatalog, ta func ProvisioningArtifactReady(conn *servicecatalog.ServiceCatalog, id, productID string) (*servicecatalog.DescribeProvisioningArtifactOutput, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{servicecatalog.StatusCreating, StatusNotFound, StatusUnavailable}, - Target: []string{servicecatalog.StatusAvailable, StatusCreated}, - Refresh: ProvisioningArtifactStatus(conn, id, productID), - Timeout: ProvisioningArtifactReadyTimeout, + Pending: []string{servicecatalog.StatusCreating, StatusNotFound, StatusUnavailable}, + Target: []string{servicecatalog.StatusAvailable, StatusCreated}, + Refresh: ProvisioningArtifactStatus(conn, id, productID), + Timeout: ProvisioningArtifactReadyTimeout, + ContinuousTargetOccurence: 2, + NotFoundChecks: 10, + MinTimeout: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -420,12 +432,13 @@ func ProvisioningArtifactDeleted(conn *servicecatalog.ServiceCatalog, id, produc func PrincipalPortfolioAssociationReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, principalARN, portfolioID string) (*servicecatalog.Principal, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{StatusNotFound, StatusUnavailable}, - Target: []string{servicecatalog.StatusAvailable}, - Refresh: PrincipalPortfolioAssociationStatus(conn, acceptLanguage, principalARN, portfolioID), - Timeout: PrincipalPortfolioAssociationReadyTimeout, - NotFoundChecks: 5, - MinTimeout: 10 * time.Second, + Pending: []string{StatusNotFound, StatusUnavailable}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: PrincipalPortfolioAssociationStatus(conn, acceptLanguage, principalARN, portfolioID), + Timeout: PrincipalPortfolioAssociationReadyTimeout, + ContinuousTargetOccurence: 2, + NotFoundChecks: 10, + MinTimeout: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -453,10 +466,13 @@ func PrincipalPortfolioAssociationDeleted(conn *servicecatalog.ServiceCatalog, a func LaunchPathsReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID string) ([]*servicecatalog.LaunchPathSummary, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{StatusNotFound}, - Target: []string{servicecatalog.StatusAvailable}, - Refresh: LaunchPathsStatus(conn, acceptLanguage, productID), - Timeout: LaunchPathsReadyTimeout, + Pending: []string{StatusNotFound}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: LaunchPathsStatus(conn, acceptLanguage, productID), + Timeout: LaunchPathsReadyTimeout, + ContinuousTargetOccurence: 2, + NotFoundChecks: 10, + MinTimeout: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -470,10 +486,13 @@ func LaunchPathsReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, produ func ProvisionedProductReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, id, name string) (*servicecatalog.DescribeProvisionedProductOutput, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{StatusNotFound, StatusUnavailable, servicecatalog.ProvisionedProductStatusUnderChange, servicecatalog.ProvisionedProductStatusPlanInProgress}, - Target: []string{servicecatalog.StatusAvailable}, - Refresh: ProvisionedProductStatus(conn, acceptLanguage, id, name), - Timeout: ProvisionedProductReadyTimeout, + Pending: []string{StatusNotFound, StatusUnavailable, servicecatalog.ProvisionedProductStatusUnderChange, servicecatalog.ProvisionedProductStatusPlanInProgress}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: ProvisionedProductStatus(conn, acceptLanguage, id, name), + Timeout: ProvisionedProductReadyTimeout, + ContinuousTargetOccurence: 2, + NotFoundChecks: 10, + MinTimeout: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() @@ -500,10 +519,13 @@ func ProvisionedProductTerminated(conn *servicecatalog.ServiceCatalog, acceptLan func RecordReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, id string) (*servicecatalog.DescribeRecordOutput, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{StatusNotFound, StatusUnavailable, servicecatalog.ProvisionedProductStatusUnderChange, servicecatalog.ProvisionedProductStatusPlanInProgress}, - Target: []string{servicecatalog.RecordStatusSucceeded, servicecatalog.StatusAvailable}, - Refresh: RecordStatus(conn, acceptLanguage, id), - Timeout: RecordReadyTimeout, + Pending: []string{StatusNotFound, StatusUnavailable, servicecatalog.ProvisionedProductStatusUnderChange, servicecatalog.ProvisionedProductStatusPlanInProgress}, + Target: []string{servicecatalog.RecordStatusSucceeded, servicecatalog.StatusAvailable}, + Refresh: RecordStatus(conn, acceptLanguage, id), + Timeout: RecordReadyTimeout, + ContinuousTargetOccurence: 2, + NotFoundChecks: 10, + MinTimeout: 10 * time.Second, } outputRaw, err := stateConf.WaitForState() From c410a9d3365967d4b7c2b2f79e47ca701775bff3 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Wed, 30 Jun 2021 15:59:48 -0400 Subject: [PATCH 0883/1208] i/servicecat: Use consts for state change arguments --- .../service/servicecatalog/waiter/waiter.go | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index e7d3e14c53d6..ea2cc78fd436 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -48,6 +48,10 @@ const ( RecordReadyTimeout = 3 * time.Minute + MinTimeout = 2 * time.Second + NotFoundChecks = 5 + ContinuousTargetOccurrence = 2 + StatusNotFound = "NOT_FOUND" StatusUnavailable = "UNAVAILABLE" @@ -63,9 +67,9 @@ func ProductReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, productID Target: []string{servicecatalog.StatusAvailable, StatusCreated}, Refresh: ProductStatus(conn, acceptLanguage, productID), Timeout: ProductReadyTimeout, - ContinuousTargetOccurence: 2, - NotFoundChecks: 10, - MinTimeout: 10 * time.Second, + ContinuousTargetOccurence: ContinuousTargetOccurrence, + NotFoundChecks: NotFoundChecks, + MinTimeout: MinTimeout, } outputRaw, err := stateConf.WaitForState() @@ -235,9 +239,9 @@ func ConstraintReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, id str Target: []string{servicecatalog.StatusAvailable}, Refresh: ConstraintStatus(conn, acceptLanguage, id), Timeout: ConstraintReadyTimeout, - ContinuousTargetOccurence: 2, - NotFoundChecks: 10, - MinTimeout: 10 * time.Second, + ContinuousTargetOccurence: ContinuousTargetOccurrence, + NotFoundChecks: NotFoundChecks, + MinTimeout: MinTimeout, } outputRaw, err := stateConf.WaitForState() @@ -268,9 +272,9 @@ func ProductPortfolioAssociationReady(conn *servicecatalog.ServiceCatalog, accep Target: []string{servicecatalog.StatusAvailable}, Refresh: ProductPortfolioAssociationStatus(conn, acceptLanguage, portfolioID, productID), Timeout: ProductPortfolioAssociationReadyTimeout, - ContinuousTargetOccurence: 2, - NotFoundChecks: 10, - MinTimeout: 10 * time.Second, + ContinuousTargetOccurence: ContinuousTargetOccurrence, + NotFoundChecks: NotFoundChecks, + MinTimeout: MinTimeout, } outputRaw, err := stateConf.WaitForState() @@ -395,9 +399,9 @@ func ProvisioningArtifactReady(conn *servicecatalog.ServiceCatalog, id, productI Target: []string{servicecatalog.StatusAvailable, StatusCreated}, Refresh: ProvisioningArtifactStatus(conn, id, productID), Timeout: ProvisioningArtifactReadyTimeout, - ContinuousTargetOccurence: 2, - NotFoundChecks: 10, - MinTimeout: 10 * time.Second, + ContinuousTargetOccurence: ContinuousTargetOccurrence, + NotFoundChecks: NotFoundChecks, + MinTimeout: MinTimeout, } outputRaw, err := stateConf.WaitForState() @@ -436,9 +440,9 @@ func PrincipalPortfolioAssociationReady(conn *servicecatalog.ServiceCatalog, acc Target: []string{servicecatalog.StatusAvailable}, Refresh: PrincipalPortfolioAssociationStatus(conn, acceptLanguage, principalARN, portfolioID), Timeout: PrincipalPortfolioAssociationReadyTimeout, - ContinuousTargetOccurence: 2, - NotFoundChecks: 10, - MinTimeout: 10 * time.Second, + ContinuousTargetOccurence: ContinuousTargetOccurrence, + NotFoundChecks: NotFoundChecks, + MinTimeout: MinTimeout, } outputRaw, err := stateConf.WaitForState() @@ -470,9 +474,9 @@ func LaunchPathsReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, produ Target: []string{servicecatalog.StatusAvailable}, Refresh: LaunchPathsStatus(conn, acceptLanguage, productID), Timeout: LaunchPathsReadyTimeout, - ContinuousTargetOccurence: 2, - NotFoundChecks: 10, - MinTimeout: 10 * time.Second, + ContinuousTargetOccurence: ContinuousTargetOccurrence, + NotFoundChecks: NotFoundChecks, + MinTimeout: MinTimeout, } outputRaw, err := stateConf.WaitForState() @@ -490,9 +494,9 @@ func ProvisionedProductReady(conn *servicecatalog.ServiceCatalog, acceptLanguage Target: []string{servicecatalog.StatusAvailable}, Refresh: ProvisionedProductStatus(conn, acceptLanguage, id, name), Timeout: ProvisionedProductReadyTimeout, - ContinuousTargetOccurence: 2, - NotFoundChecks: 10, - MinTimeout: 10 * time.Second, + ContinuousTargetOccurence: ContinuousTargetOccurrence, + NotFoundChecks: NotFoundChecks, + MinTimeout: MinTimeout, } outputRaw, err := stateConf.WaitForState() @@ -523,9 +527,9 @@ func RecordReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, id string) Target: []string{servicecatalog.RecordStatusSucceeded, servicecatalog.StatusAvailable}, Refresh: RecordStatus(conn, acceptLanguage, id), Timeout: RecordReadyTimeout, - ContinuousTargetOccurence: 2, - NotFoundChecks: 10, - MinTimeout: 10 * time.Second, + ContinuousTargetOccurence: ContinuousTargetOccurrence, + NotFoundChecks: NotFoundChecks, + MinTimeout: MinTimeout, } outputRaw, err := stateConf.WaitForState() From 41048b94230402c79f71b5e0abe785dd2755f15f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 30 Jun 2021 16:36:14 -0400 Subject: [PATCH 0884/1208] Prevent 'severity:warning rule:aws-sdk-go-multiple-service-imports: Resources should not implement multiple AWS service functionality'. --- .semgrep.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.semgrep.yml b/.semgrep.yml index c9a41d64c4a4..575fc5949d21 100644 --- a/.semgrep.yml +++ b/.semgrep.yml @@ -22,6 +22,7 @@ rules: - aws/validators.go - aws/*wafregional*.go - aws/resource_aws_serverlessapplicationrepository_cloudformation_stack.go + - aws/resource_aws_transfer_server.go - aws/*_test.go - aws/internal/keyvaluetags/ - aws/internal/service/wafregional/ From 2e21d6032472493afb579aae0a8268ff6d5187c5 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 30 Jun 2021 20:53:11 +0000 Subject: [PATCH 0885/1208] Update CHANGELOG.md for #19459 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55693ebbb39f..2323c353d39c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ FEATURES: * **New Data Source:** `aws_iam_session_context` ([#19957](https://github.com/hashicorp/terraform-provider-aws/issues/19957)) +* **New Resource:** `aws_servicecatalog_provisioned_product` ([#19459](https://github.com/hashicorp/terraform-provider-aws/issues/19459)) ENHANCEMENTS: From bc692d06426f3c55b08d4401975246e793711cdb Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 13:54:40 -0400 Subject: [PATCH 0886/1208] i/servicecat: Add statuser --- aws/internal/service/servicecatalog/id.go | 4 ++ .../service/servicecatalog/waiter/status.go | 44 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/aws/internal/service/servicecatalog/id.go b/aws/internal/service/servicecatalog/id.go index 3eb0a6f8a418..a15f1a759a24 100644 --- a/aws/internal/service/servicecatalog/id.go +++ b/aws/internal/service/servicecatalog/id.go @@ -87,3 +87,7 @@ func PrincipalPortfolioAssociationParseID(id string) (string, string, string, er func PrincipalPortfolioAssociationID(acceptLanguage, principalARN, portfolioID string) string { return strings.Join([]string{acceptLanguage, principalARN, portfolioID}, ",") } + +func PortfolioConstraintsID(acceptLanguage, portfolioID, productID string) string { + return strings.Join([]string{acceptLanguage, portfolioID, productID}, ":") +} diff --git a/aws/internal/service/servicecatalog/waiter/status.go b/aws/internal/service/servicecatalog/waiter/status.go index d1f39a9489af..7f4dfe872419 100644 --- a/aws/internal/service/servicecatalog/waiter/status.go +++ b/aws/internal/service/servicecatalog/waiter/status.go @@ -417,3 +417,47 @@ func RecordStatus(conn *servicecatalog.ServiceCatalog, acceptLanguage, id string return output, aws.StringValue(output.RecordDetail.Status), err } } + +func PortfolioConstraintsStatus(conn *servicecatalog.ServiceCatalog, acceptLanguage, portfolioID, productID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &servicecatalog.ListConstraintsForPortfolioInput{ + PortfolioId: aws.String(portfolioID), + } + + if acceptLanguage != "" { + input.AcceptLanguage = aws.String(acceptLanguage) + } + + if productID != "" { + input.ProductId = aws.String(productID) + } + + var output []*servicecatalog.ConstraintDetail + + err := conn.ListConstraintsForPortfolioPages(input, func(page *servicecatalog.ListConstraintsForPortfolioOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, deet := range page.ConstraintDetails { + if deet == nil { + continue + } + + output = append(output, deet) + } + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, servicecatalog.ErrCodeResourceNotFoundException) { + return nil, StatusNotFound, nil + } + + if err != nil { + return nil, servicecatalog.StatusFailed, err + } + + return output, servicecatalog.StatusAvailable, err + } +} From 819e2900dfa5ac049dec3d6374c97316ac4a2fce Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 13:55:09 -0400 Subject: [PATCH 0887/1208] i/servicecat: Add waiter --- .../service/servicecatalog/waiter/waiter.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/aws/internal/service/servicecatalog/waiter/waiter.go b/aws/internal/service/servicecatalog/waiter/waiter.go index ea2cc78fd436..0e878168594d 100644 --- a/aws/internal/service/servicecatalog/waiter/waiter.go +++ b/aws/internal/service/servicecatalog/waiter/waiter.go @@ -48,6 +48,8 @@ const ( RecordReadyTimeout = 3 * time.Minute + PortfolioConstraintsReadyTimeout = 3 * time.Minute + MinTimeout = 2 * time.Second NotFoundChecks = 5 ContinuousTargetOccurrence = 2 @@ -540,3 +542,20 @@ func RecordReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, id string) return nil, err } + +func PortfolioConstraintsReady(conn *servicecatalog.ServiceCatalog, acceptLanguage, portfolioID, productID string) ([]*servicecatalog.ConstraintDetail, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{StatusNotFound}, + Target: []string{servicecatalog.StatusAvailable}, + Refresh: PortfolioConstraintsStatus(conn, acceptLanguage, portfolioID, productID), + Timeout: PortfolioConstraintsReadyTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.([]*servicecatalog.ConstraintDetail); ok { + return output, err + } + + return nil, err +} From 220dd5424eab1478dd36104698742aa2604fe909 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 13:55:33 -0400 Subject: [PATCH 0888/1208] provider: Add new data source --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index e71d04dfcf18..f8c6a4179edc 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -393,6 +393,7 @@ func Provider() *schema.Provider { "aws_secretsmanager_secret_version": dataSourceAwsSecretsManagerSecretVersion(), "aws_servicecatalog_constraint": dataSourceAwsServiceCatalogConstraint(), "aws_servicecatalog_launch_paths": dataSourceAwsServiceCatalogLaunchPaths(), + "aws_servicecatalog_portfolio_constraints": dataSourceAwsServiceCatalogPortfolioConstraints(), "aws_servicecatalog_portfolio": dataSourceAwsServiceCatalogPortfolio(), "aws_servicecatalog_product": dataSourceAwsServiceCatalogProduct(), "aws_servicequotas_service": dataSourceAwsServiceQuotasService(), From 12d2b98f82ee4f05e3026831d1079ee9af57f930 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 13:56:21 -0400 Subject: [PATCH 0889/1208] docs/d/servicecat_port_contraints: New data source --- ...atalog_portfolio_constraints.html.markdown | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 website/docs/d/servicecatalog_portfolio_constraints.html.markdown diff --git a/website/docs/d/servicecatalog_portfolio_constraints.html.markdown b/website/docs/d/servicecatalog_portfolio_constraints.html.markdown new file mode 100644 index 000000000000..611a6e148c5e --- /dev/null +++ b/website/docs/d/servicecatalog_portfolio_constraints.html.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "Service Catalog" +layout: "aws" +page_title: "AWS: aws_servicecatalog_portfolio_constraints" +description: |- + Provides information on Service Catalog Portfolio Constraints +--- + +# Data source: aws_servicecatalog_portfolio_constraints + +Provides information on Service Catalog Portfolio Constraints. + +## Example Usage + +### Basic Usage + +```terraform +data "aws_servicecatalog_portfolio_constraints" "example" { + portfolio_id = "port-3lli3b3an" +} +``` + +## Argument Reference + +The following arguments are required: + +* `portfolio_id` - Portfolio identifier. + +The following arguments are optional: + +* `accept_language` - (Optional) Language code. Valid values: `en` (English), `jp` (Japanese), `zh` (Chinese). Default value is `en`. +* `product_id` - (Optional) Product identifier. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `details` - List of information about the constraints. See details below. + +### details + +* `constraint_id` - Identifier of the constraint. +* `description` - Description of the constraint. +* `product_id` - Identifier of the product the constraint applies to. A constraint applies to a specific instance of a product within a certain portfolio. +* `type` - Type of constraint. Valid values are `LAUNCH`, `NOTIFICATION`, `STACKSET`, and `TEMPLATE`. From c6d4a185ba26626245f25f8f63abe9ae2d8f83c8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 13:56:59 -0400 Subject: [PATCH 0890/1208] d/servicecat_port_contraints: New data source --- ...ws_servicecatalog_portfolio_constraints.go | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 aws/data_source_aws_servicecatalog_portfolio_constraints.go diff --git a/aws/data_source_aws_servicecatalog_portfolio_constraints.go b/aws/data_source_aws_servicecatalog_portfolio_constraints.go new file mode 100644 index 000000000000..4e5e31e7debf --- /dev/null +++ b/aws/data_source_aws_servicecatalog_portfolio_constraints.go @@ -0,0 +1,137 @@ +package aws + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + tfservicecatalog "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicecatalog/waiter" +) + +func dataSourceAwsServiceCatalogPortfolioConstraints() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsServiceCatalogPortfolioConstraintsRead, + + Schema: map[string]*schema.Schema{ + "accept_language": { + Type: schema.TypeString, + Optional: true, + Default: "en", + ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), + }, + "details": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "constraint_id": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "owner": { + Type: schema.TypeString, + Computed: true, + }, + "product_id": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "portfolio_id": { + Type: schema.TypeString, + Required: true, + }, + "product_id": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + +func dataSourceAwsServiceCatalogPortfolioConstraintsRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).scconn + + output, err := waiter.PortfolioConstraintsReady(conn, d.Get("accept_language").(string), d.Get("portfolio_id").(string), d.Get("product_id").(string)) + + if err != nil { + return fmt.Errorf("error describing Service Catalog Portfolio Constraints: %w", err) + } + + if len(output) == 0 { + return fmt.Errorf("error getting Service Catalog Portfolio Constraints: no results, change your input") + } + + d.Set("accept_language", d.Get("accept_language").(string)) + d.Set("portfolio_id", d.Get("portfolio_id").(string)) + d.Set("product_id", d.Get("product_id").(string)) + + if err := d.Set("details", flattenServiceCatalogConstraintDetails(output)); err != nil { + return fmt.Errorf("error setting details: %w", err) + } + + d.SetId(tfservicecatalog.PortfolioConstraintsID(d.Get("accept_language").(string), d.Get("portfolio_id").(string), d.Get("product_id").(string))) + + return nil +} + +func flattenServiceCatalogConstraintDetail(apiObject *servicecatalog.ConstraintDetail) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.ConstraintId; v != nil { + tfMap["constraint_id"] = aws.StringValue(v) + } + + if v := apiObject.Description; v != nil { + tfMap["description"] = aws.StringValue(v) + } + + if v := apiObject.Owner; v != nil { + tfMap["owner"] = aws.StringValue(v) + } + + if v := apiObject.ProductId; v != nil { + tfMap["product_id"] = aws.StringValue(v) + } + + if v := apiObject.Type; v != nil { + tfMap["type"] = aws.StringValue(v) + } + + return tfMap +} + +func flattenServiceCatalogConstraintDetails(apiObjects []*servicecatalog.ConstraintDetail) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var tfList []interface{} + + for _, apiObject := range apiObjects { + if apiObject == nil { + continue + } + + tfList = append(tfList, flattenServiceCatalogConstraintDetail(apiObject)) + } + + return tfList +} From 64cbda168fd922830b167c0ceaa40e6943dbe33f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 13:57:15 -0400 Subject: [PATCH 0891/1208] tests/d/servicecat_port_contraints: New data source --- ...rvicecatalog_portfolio_constraints_test.go | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 aws/data_source_aws_servicecatalog_portfolio_constraints_test.go diff --git a/aws/data_source_aws_servicecatalog_portfolio_constraints_test.go b/aws/data_source_aws_servicecatalog_portfolio_constraints_test.go new file mode 100644 index 000000000000..07ae7b5a0140 --- /dev/null +++ b/aws/data_source_aws_servicecatalog_portfolio_constraints_test.go @@ -0,0 +1,44 @@ +package aws + +import ( + "testing" + + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccAWSServiceCatalogPortfolioConstraintDataSource_basic(t *testing.T) { + resourceName := "aws_servicecatalog_portfolio_constraint.test" + dataSourceName := "data.aws_servicecatalog_portfolio_constraint.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, servicecatalog.EndpointsID), + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSServiceCatalogPortfolioConstraintDataSourceConfig_basic(rName, rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "accept_language", dataSourceName, "accept_language"), + resource.TestCheckResourceAttrPair(resourceName, "description", dataSourceName, "description"), + resource.TestCheckResourceAttrPair(resourceName, "owner", dataSourceName, "owner"), + resource.TestCheckResourceAttrPair(resourceName, "parameters", dataSourceName, "parameters"), + resource.TestCheckResourceAttrPair(resourceName, "portfolio_id", dataSourceName, "portfolio_id"), + resource.TestCheckResourceAttrPair(resourceName, "product_id", dataSourceName, "product_id"), + resource.TestCheckResourceAttrPair(resourceName, "status", dataSourceName, "status"), + resource.TestCheckResourceAttrPair(resourceName, "type", dataSourceName, "type"), + ), + }, + }, + }) +} + +func testAccAWSServiceCatalogPortfolioConstraintDataSourceConfig_basic(rName, description string) string { + return composeConfig(testAccAWSServiceCatalogPortfolioConstraintConfig_basic(rName, description), ` +data "aws_servicecatalog_portfolio_constraints" "test" { + id = aws_servicecatalog_portfolio_constraint.test.id +} +`) +} From ee8ae7dfcff2c41c23557b64f71a674844e72352 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 15 Jun 2021 14:00:13 -0400 Subject: [PATCH 0892/1208] d/servicecat_port_contraints: Add changelog --- .changelog/19813.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19813.txt diff --git a/.changelog/19813.txt b/.changelog/19813.txt new file mode 100644 index 000000000000..af1420e8b70d --- /dev/null +++ b/.changelog/19813.txt @@ -0,0 +1,3 @@ +```release-notes:new-data-source +aws_servicecatalog_portfolio_constraints +``` \ No newline at end of file From b05dd884ea5e4ffb9ee9ed81f5042c5d84b52d06 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 19:15:02 -0400 Subject: [PATCH 0893/1208] r/servicecat_constraint: Add check to avoid panic --- aws/resource_aws_servicecatalog_constraint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_servicecatalog_constraint.go b/aws/resource_aws_servicecatalog_constraint.go index 730a57020da4..8a9f3d467639 100644 --- a/aws/resource_aws_servicecatalog_constraint.go +++ b/aws/resource_aws_servicecatalog_constraint.go @@ -144,7 +144,7 @@ func resourceAwsServiceCatalogConstraintRead(d *schema.ResourceData, meta interf return fmt.Errorf("error describing Service Catalog Constraint (%s): %w", d.Id(), err) } - if output == nil { + if output == nil || output.ConstraintDetail == nil { return fmt.Errorf("error getting Service Catalog Constraint (%s): empty response", d.Id()) } From d73ddf5b1231ab55ecdb76a8655da4fc4899bbdd Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 19:16:09 -0400 Subject: [PATCH 0894/1208] d/servicecat_port_constraints: Minor fixes --- ...aws_servicecatalog_portfolio_constraints.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/aws/data_source_aws_servicecatalog_portfolio_constraints.go b/aws/data_source_aws_servicecatalog_portfolio_constraints.go index 4e5e31e7debf..0b89f5068518 100644 --- a/aws/data_source_aws_servicecatalog_portfolio_constraints.go +++ b/aws/data_source_aws_servicecatalog_portfolio_constraints.go @@ -19,7 +19,7 @@ func dataSourceAwsServiceCatalogPortfolioConstraints() *schema.Resource { "accept_language": { Type: schema.TypeString, Optional: true, - Default: "en", + Default: tfservicecatalog.AcceptLanguageEnglish, ValidateFunc: validation.StringInSlice(tfservicecatalog.AcceptLanguage_Values(), false), }, "details": { @@ -39,6 +39,10 @@ func dataSourceAwsServiceCatalogPortfolioConstraints() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "portfolio_id": { + Type: schema.TypeString, + Computed: true, + }, "product_id": { Type: schema.TypeString, Computed: true, @@ -75,7 +79,13 @@ func dataSourceAwsServiceCatalogPortfolioConstraintsRead(d *schema.ResourceData, return fmt.Errorf("error getting Service Catalog Portfolio Constraints: no results, change your input") } - d.Set("accept_language", d.Get("accept_language").(string)) + acceptLanguage := d.Get("accept_language").(string) + + if acceptLanguage == "" { + acceptLanguage = tfservicecatalog.AcceptLanguageEnglish + } + + d.Set("accept_language", acceptLanguage) d.Set("portfolio_id", d.Get("portfolio_id").(string)) d.Set("product_id", d.Get("product_id").(string)) @@ -107,6 +117,10 @@ func flattenServiceCatalogConstraintDetail(apiObject *servicecatalog.ConstraintD tfMap["owner"] = aws.StringValue(v) } + if v := apiObject.PortfolioId; v != nil { + tfMap["portfolio_id"] = aws.StringValue(v) + } + if v := apiObject.ProductId; v != nil { tfMap["product_id"] = aws.StringValue(v) } From 50f23a92556438342535015bd9679c5a46979cc6 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 19:18:51 -0400 Subject: [PATCH 0895/1208] docs/d/servicecat_port_constraints: Add new attribute --- .../docs/d/servicecatalog_portfolio_constraints.html.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/d/servicecatalog_portfolio_constraints.html.markdown b/website/docs/d/servicecatalog_portfolio_constraints.html.markdown index 611a6e148c5e..176fdfcf01b3 100644 --- a/website/docs/d/servicecatalog_portfolio_constraints.html.markdown +++ b/website/docs/d/servicecatalog_portfolio_constraints.html.markdown @@ -24,7 +24,7 @@ data "aws_servicecatalog_portfolio_constraints" "example" { The following arguments are required: -* `portfolio_id` - Portfolio identifier. +* `portfolio_id` - (Required) Portfolio identifier. The following arguments are optional: @@ -41,5 +41,6 @@ In addition to all arguments above, the following attributes are exported: * `constraint_id` - Identifier of the constraint. * `description` - Description of the constraint. +* `portfolio_id` - Identifier of the portfolio the product resides in. The constraint applies only to the instance of the product that lives within this portfolio. * `product_id` - Identifier of the product the constraint applies to. A constraint applies to a specific instance of a product within a certain portfolio. * `type` - Type of constraint. Valid values are `LAUNCH`, `NOTIFICATION`, `STACKSET`, and `TEMPLATE`. From d8dc758e419ff6d63539b42ac1f83093f3e99b79 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 19:19:46 -0400 Subject: [PATCH 0896/1208] tests/d/servicecat_port_constraints: Rework test --- ...rvicecatalog_portfolio_constraints_test.go | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/aws/data_source_aws_servicecatalog_portfolio_constraints_test.go b/aws/data_source_aws_servicecatalog_portfolio_constraints_test.go index 07ae7b5a0140..c63eda588518 100644 --- a/aws/data_source_aws_servicecatalog_portfolio_constraints_test.go +++ b/aws/data_source_aws_servicecatalog_portfolio_constraints_test.go @@ -9,8 +9,8 @@ import ( ) func TestAccAWSServiceCatalogPortfolioConstraintDataSource_basic(t *testing.T) { - resourceName := "aws_servicecatalog_portfolio_constraint.test" - dataSourceName := "data.aws_servicecatalog_portfolio_constraint.test" + resourceName := "aws_servicecatalog_constraint.test" + dataSourceName := "data.aws_servicecatalog_portfolio_constraints.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ @@ -21,14 +21,15 @@ func TestAccAWSServiceCatalogPortfolioConstraintDataSource_basic(t *testing.T) { { Config: testAccAWSServiceCatalogPortfolioConstraintDataSourceConfig_basic(rName, rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrPair(resourceName, "accept_language", dataSourceName, "accept_language"), - resource.TestCheckResourceAttrPair(resourceName, "description", dataSourceName, "description"), - resource.TestCheckResourceAttrPair(resourceName, "owner", dataSourceName, "owner"), - resource.TestCheckResourceAttrPair(resourceName, "parameters", dataSourceName, "parameters"), - resource.TestCheckResourceAttrPair(resourceName, "portfolio_id", dataSourceName, "portfolio_id"), - resource.TestCheckResourceAttrPair(resourceName, "product_id", dataSourceName, "product_id"), - resource.TestCheckResourceAttrPair(resourceName, "status", dataSourceName, "status"), - resource.TestCheckResourceAttrPair(resourceName, "type", dataSourceName, "type"), + resource.TestCheckResourceAttrPair(dataSourceName, "accept_language", resourceName, "accept_language"), + resource.TestCheckResourceAttr(dataSourceName, "details.#", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "details.0.constraint_id", resourceName, "id"), + resource.TestCheckResourceAttrPair(dataSourceName, "details.0.description", resourceName, "description"), + resource.TestCheckResourceAttrPair(dataSourceName, "details.0.owner", resourceName, "owner"), + resource.TestCheckResourceAttrPair(dataSourceName, "details.0.portfolio_id", resourceName, "portfolio_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "details.0.product_id", resourceName, "product_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "details.0.type", resourceName, "type"), + resource.TestCheckResourceAttrPair(dataSourceName, "portfolio_id", resourceName, "portfolio_id"), ), }, }, @@ -36,9 +37,9 @@ func TestAccAWSServiceCatalogPortfolioConstraintDataSource_basic(t *testing.T) { } func testAccAWSServiceCatalogPortfolioConstraintDataSourceConfig_basic(rName, description string) string { - return composeConfig(testAccAWSServiceCatalogPortfolioConstraintConfig_basic(rName, description), ` + return composeConfig(testAccAWSServiceCatalogConstraintConfig_basic(rName, description), ` data "aws_servicecatalog_portfolio_constraints" "test" { - id = aws_servicecatalog_portfolio_constraint.test.id + portfolio_id = aws_servicecatalog_constraint.test.portfolio_id } `) } From 058b8ca82ece594fd15eebc519e2a4b3e4ef996d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 29 Jun 2021 19:20:22 -0400 Subject: [PATCH 0897/1208] d/servicecat_constraint: Align data source with resource --- aws/data_source_aws_servicecatalog_constraint.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/aws/data_source_aws_servicecatalog_constraint.go b/aws/data_source_aws_servicecatalog_constraint.go index a8b29de52c5e..4277b4c17714 100644 --- a/aws/data_source_aws_servicecatalog_constraint.go +++ b/aws/data_source_aws_servicecatalog_constraint.go @@ -71,7 +71,13 @@ func dataSourceAwsServiceCatalogConstraintRead(d *schema.ResourceData, meta inte return fmt.Errorf("error getting Service Catalog Constraint: empty response") } - d.Set("accept_language", d.Get("accept_language").(string)) + acceptLanguage := d.Get("accept_language").(string) + + if acceptLanguage == "" { + acceptLanguage = tfservicecatalog.AcceptLanguageEnglish + } + + d.Set("accept_language", acceptLanguage) d.Set("parameters", output.ConstraintParameters) d.Set("status", output.Status) From d2d0ce509a3f0d097b5fb76893631fd90d6efd92 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 30 Jun 2021 17:01:01 -0400 Subject: [PATCH 0898/1208] Fix 'terrafmt' errors. --- aws/resource_aws_transfer_server_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index c1226b6f0bca..6400e56f1ab1 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -1424,7 +1424,7 @@ resource "aws_transfer_server" "test" { endpoint_details { address_allocation_ids = [aws_eip.test[0].id] - security_group_ids = [aws_security_group.test.id] + security_group_ids = [aws_security_group.test.id] subnet_ids = [aws_subnet.test.id] vpc_id = aws_vpc.test.id } @@ -1460,7 +1460,7 @@ resource "aws_transfer_server" "test" { endpoint_details { address_allocation_ids = [aws_eip.test[1].id] - security_group_ids = [aws_security_group.test2.id] + security_group_ids = [aws_security_group.test2.id] subnet_ids = [aws_subnet.test.id] vpc_id = aws_vpc.test.id } From 7a35a4e2078cefea1418b698842e5bca36abecaa Mon Sep 17 00:00:00 2001 From: shuheiktgw Date: Sun, 14 Mar 2021 20:41:22 +0900 Subject: [PATCH 0899/1208] Add aws_cloudfront_monitoring_subscription resource --- .../service/cloudfront/finder/finder.go | 19 ++ aws/provider.go | 1 + ..._aws_cloudfront_monitoring_subscription.go | 165 ++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 aws/resource_aws_cloudfront_monitoring_subscription.go diff --git a/aws/internal/service/cloudfront/finder/finder.go b/aws/internal/service/cloudfront/finder/finder.go index 3741c1640bbc..3f6a532602ea 100644 --- a/aws/internal/service/cloudfront/finder/finder.go +++ b/aws/internal/service/cloudfront/finder/finder.go @@ -54,3 +54,22 @@ func RealtimeLogConfigByARN(conn *cloudfront.CloudFront, arn string) (*cloudfron return output.RealtimeLogConfig, nil } + +// MonitoringSubscriptionByDistributionId returns the monitoring subscription corresponding to the specified distribution id. +// Returns nil if no subscription is found. +func MonitoringSubscriptionByDistributionId(conn *cloudfront.CloudFront, id string) (*cloudfront.MonitoringSubscription, error) { + input := &cloudfront.GetMonitoringSubscriptionInput{ + DistributionId: aws.String(id), + } + + output, err := conn.GetMonitoringSubscription(input) + if err != nil { + return nil, err + } + + if output == nil { + return nil, nil + } + + return output.MonitoringSubscription, nil +} diff --git a/aws/provider.go b/aws/provider.go index bb29044942d4..001ea6ce0ed8 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -547,6 +547,7 @@ func Provider() *schema.Provider { "aws_cloudfront_distribution": resourceAwsCloudFrontDistribution(), "aws_cloudfront_function": resourceAwsCloudFrontFunction(), "aws_cloudfront_key_group": resourceAwsCloudFrontKeyGroup(), + "aws_cloudfront_monitoring_subscription": resourceAwsCloudFrontMonitoringSubscription(), "aws_cloudfront_origin_access_identity": resourceAwsCloudFrontOriginAccessIdentity(), "aws_cloudfront_origin_request_policy": resourceAwsCloudFrontOriginRequestPolicy(), "aws_cloudfront_public_key": resourceAwsCloudFrontPublicKey(), diff --git a/aws/resource_aws_cloudfront_monitoring_subscription.go b/aws/resource_aws_cloudfront_monitoring_subscription.go new file mode 100644 index 000000000000..71664e4c3a52 --- /dev/null +++ b/aws/resource_aws_cloudfront_monitoring_subscription.go @@ -0,0 +1,165 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudfront" + "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/service/cloudfront/finder" +) + +func resourceAwsCloudFrontMonitoringSubscription() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsCloudFrontMonitoringSubscriptionCreate, + Read: resourceAwsCloudFrontMonitoringSubscriptionRead, + Delete: resourceAwsCloudFrontMonitoringSubscriptionDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "distribution_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "monitoring_subscription": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "realtime_metrics_subscription_config": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "realtime_metrics_subscription_status": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(cloudfront.RealtimeMetricsSubscriptionStatus_Values(), false), + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func resourceAwsCloudFrontMonitoringSubscriptionCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + + id := d.Get("distribution_id").(string) + input := &cloudfront.CreateMonitoringSubscriptionInput{ + DistributionId: aws.String(id), + MonitoringSubscription: expandCloudFrontMonitoringSubscription(d.Get("monitoring_subscription").([]interface{})), + } + + log.Printf("[DEBUG] Creating CloudFront Monitoring Subscription: %s", input) + _, err := conn.CreateMonitoringSubscription(input) + + if err != nil { + return fmt.Errorf("error creating CloudFront Monitoring Subscription (%s): %w", id, err) + } + + d.SetId(id) + + return resourceAwsCloudFrontMonitoringSubscriptionRead(d, meta) +} + +func resourceAwsCloudFrontMonitoringSubscriptionRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + + subscription, err := finder.MonitoringSubscriptionByDistributionId(conn, d.Id()) + + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { + log.Printf("[WARN] CloudFront Distribution (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading CloudFront Monitoring Subscription (%s): %w", d.Id(), err) + } + + if subscription == nil { + if d.IsNewResource() { + return fmt.Errorf("error reading CloudFront Monitoring Subscription (%s): not found", d.Id()) + } + log.Printf("[WARN] CloudFront Monitoring Subscription (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + d.Set("distribution_id", d.Id()) + if err := d.Set("monitoring_subscription", flattenCloudFrontMonitoringSubscription(subscription)); err != nil { + return fmt.Errorf("error setting monitoring_subscription: %w", err) + } + + return nil +} + +func resourceAwsCloudFrontMonitoringSubscriptionDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).cloudfrontconn + + log.Printf("[DEBUG] Deleting CloudFront Monitoring Subscription (%s)", d.Id()) + _, err := conn.DeleteMonitoringSubscription(&cloudfront.DeleteMonitoringSubscriptionInput{ + DistributionId: aws.String(d.Id()), + }) + + if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting CloudFront Monitoring Subscription (%s): %w", d.Id(), err) + } + + return nil +} + +func expandCloudFrontMonitoringSubscription(vSubscription []interface{}) *cloudfront.MonitoringSubscription { + if len(vSubscription) == 0 || vSubscription[0] == nil { + return nil + } + + mSubscription := vSubscription[0].(map[string]interface{}) + + return &cloudfront.MonitoringSubscription{ + RealtimeMetricsSubscriptionConfig: expandCloudFrontRealtimeMetricsSubscriptionConfig(mSubscription["realtime_metrics_subscription_config"].([]interface{})), + } +} + +func expandCloudFrontRealtimeMetricsSubscriptionConfig(vConfig []interface{}) *cloudfront.RealtimeMetricsSubscriptionConfig { + if len(vConfig) == 0 || vConfig[0] == nil { + return nil + } + + mConfig := vConfig[0].(map[string]interface{}) + + return &cloudfront.RealtimeMetricsSubscriptionConfig{ + RealtimeMetricsSubscriptionStatus: aws.String(mConfig["realtime_metrics_subscription_status"].(string)), + } +} + +func flattenCloudFrontMonitoringSubscription(subscription *cloudfront.MonitoringSubscription) []interface{} { + return []interface{}{map[string]interface{}{"realtime_metrics_subscription_config": flattenCloudFrontRealtimeMetricsSubscriptionConfig(subscription.RealtimeMetricsSubscriptionConfig)}} +} + +func flattenCloudFrontRealtimeMetricsSubscriptionConfig(config *cloudfront.RealtimeMetricsSubscriptionConfig) []interface{} { + return []interface{}{map[string]interface{}{"realtime_metrics_subscription_status": config.RealtimeMetricsSubscriptionStatus}} +} From d99391f006848c38a67204fe4ac9f51a882f80a8 Mon Sep 17 00:00:00 2001 From: shuheiktgw Date: Sun, 14 Mar 2021 20:41:50 +0900 Subject: [PATCH 0900/1208] Add tests for aws_cloudfront_monitoring_subscription resource --- ...cloudfront_monitoring_subscription_test.go | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 aws/resource_aws_cloudfront_monitoring_subscription_test.go diff --git a/aws/resource_aws_cloudfront_monitoring_subscription_test.go b/aws/resource_aws_cloudfront_monitoring_subscription_test.go new file mode 100644 index 000000000000..4397e9b7c487 --- /dev/null +++ b/aws/resource_aws_cloudfront_monitoring_subscription_test.go @@ -0,0 +1,282 @@ +package aws + +import ( + "fmt" + "log" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudfront" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/cloudfront/finder" +) + +func init() { + resource.AddTestSweepers("aws_cloudfront_monitoring_subscription", &resource.Sweeper{ + Name: "aws_cloudfront_monitoring_subscription", + F: testSweepCloudFrontMonitoringSubscriptions, + }) +} + +func testSweepCloudFrontMonitoringSubscriptions(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).cloudfrontconn + var sweeperErrs *multierror.Error + + distributionSummaries := make([]*cloudfront.DistributionSummary, 0) + + input := &cloudfront.ListDistributionsInput{} + err = conn.ListDistributionsPages(input, func(page *cloudfront.ListDistributionsOutput, lastPage bool) bool { + distributionSummaries = append(distributionSummaries, page.DistributionList.Items...) + return !lastPage + }) + if err != nil { + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping CloudFront Monitoring Subscriptions sweep for %s: %s", region, err) + return nil + } + return fmt.Errorf("error listing CloudFront Distributions: %s", err) + } + + if len(distributionSummaries) == 0 { + log.Print("[DEBUG] No CloudFront Distributions found") + return nil + } + + for _, distributionSummary := range distributionSummaries { + + _, err := conn.GetMonitoringSubscription(&cloudfront.GetMonitoringSubscriptionInput{ + DistributionId: distributionSummary.Id, + }) + if err != nil { + return fmt.Errorf("error reading CloudFront Monitoring Subscription %s: %s", aws.StringValue(distributionSummary.Id), err) + } + + _, err = conn.DeleteMonitoringSubscription(&cloudfront.DeleteMonitoringSubscriptionInput{ + DistributionId: distributionSummary.Id, + }) + if err != nil { + return fmt.Errorf("error deleting CloudFront Monitoring Subscription %s: %s", aws.StringValue(distributionSummary.Id), err) + } + } + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSCloudFrontMonitoringSubscription_basic(t *testing.T) { + var v cloudfront.MonitoringSubscription + resourceName := "aws_cloudfront_monitoring_subscription.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(cloudfront.EndpointsID, t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontMonitoringSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudFrontMonitoringSubscriptionConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontMonitoringSubscriptionExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "distribution_id"), + resource.TestCheckResourceAttr(resourceName, "monitoring_subscription.#", "1"), + resource.TestCheckResourceAttr(resourceName, "monitoring_subscription.0.realtime_metrics_subscription_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "monitoring_subscription.0.realtime_metrics_subscription_config.0.realtime_metrics_subscription_status", "Enabled"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSCloudFrontMonitoringSubscription_disappears(t *testing.T) { + var v cloudfront.MonitoringSubscription + resourceName := "aws_cloudfront_monitoring_subscription.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(cloudfront.EndpointsID, t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontMonitoringSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudFrontMonitoringSubscriptionConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontMonitoringSubscriptionExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudFrontMonitoringSubscription(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSCloudFrontMonitoringSubscription_RealtimeMetricsSubscriptionConfig(t *testing.T) { + var v cloudfront.MonitoringSubscription + resourceName := "aws_cloudfront_monitoring_subscription.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(cloudfront.EndpointsID, t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFrontMonitoringSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCloudFrontMonitoringSubscriptionRealtimeMetricsSubscriptionConfigConfig("Enabled"), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontMonitoringSubscriptionExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "distribution_id"), + resource.TestCheckResourceAttr(resourceName, "monitoring_subscription.#", "1"), + resource.TestCheckResourceAttr(resourceName, "monitoring_subscription.0.realtime_metrics_subscription_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "monitoring_subscription.0.realtime_metrics_subscription_config.0.realtime_metrics_subscription_status", "Enabled"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCloudFrontMonitoringSubscriptionRealtimeMetricsSubscriptionConfigConfig("Disabled"), + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFrontMonitoringSubscriptionExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "distribution_id"), + resource.TestCheckResourceAttr(resourceName, "monitoring_subscription.#", "1"), + resource.TestCheckResourceAttr(resourceName, "monitoring_subscription.0.realtime_metrics_subscription_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "monitoring_subscription.0.realtime_metrics_subscription_config.0.realtime_metrics_subscription_status", "Disabled"), + ), + }, + }, + }) +} + +func testAccCheckCloudFrontMonitoringSubscriptionDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).cloudfrontconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_cloudfront_monitoring_subscription" { + continue + } + + s, err := finder.MonitoringSubscriptionByDistributionId(conn, rs.Primary.ID) + + if isAWSErr(err, cloudfront.ErrCodeNoSuchDistribution, "") { + continue + } + if err != nil { + return err + } + if s != nil { + continue + } + return fmt.Errorf("CloudFront Monitoring Subscription still exists: %s", rs.Primary.ID) + } + + return nil +} + +func testAccCheckCloudFrontMonitoringSubscriptionExists(n string, v *cloudfront.MonitoringSubscription) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No CloudFront Monitoring Subscription ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).cloudfrontconn + out, err := finder.MonitoringSubscriptionByDistributionId(conn, rs.Primary.ID) + if err != nil { + return err + } + + *v = *out + + return nil + } +} + +func testAccAWSCloudFrontMonitoringSubscriptionConfigBase() string { + return ` +resource "aws_cloudfront_distribution" "test" { + enabled = true + retain_on_delete = false + + default_cache_behavior { + allowed_methods = ["GET", "HEAD"] + cached_methods = ["GET", "HEAD"] + target_origin_id = "test" + viewer_protocol_policy = "allow-all" + + forwarded_values { + query_string = false + + cookies { + forward = "all" + } + } + } + + origin { + domain_name = "www.example.com" + origin_id = "test" + + custom_origin_config { + http_port = 80 + https_port = 443 + origin_protocol_policy = "https-only" + origin_ssl_protocols = ["TLSv1.2"] + } + } + + restrictions { + geo_restriction { + restriction_type = "none" + } + } + + viewer_certificate { + cloudfront_default_certificate = true + } +} +` +} + +func testAccAWSCloudFrontMonitoringSubscriptionConfig() string { + return composeConfig( + testAccAWSCloudFrontMonitoringSubscriptionConfigBase(), + ` +resource "aws_cloudfront_monitoring_subscription" "test" { + distribution_id = aws_cloudfront_distribution.test.id + + monitoring_subscription { + realtime_metrics_subscription_config { + realtime_metrics_subscription_status = "Enabled" + } + } +} +`) +} + +func testAccAWSCloudFrontMonitoringSubscriptionRealtimeMetricsSubscriptionConfigConfig(status string) string { + return composeConfig( + testAccAWSCloudFrontMonitoringSubscriptionConfigBase(), + fmt.Sprintf(` +resource "aws_cloudfront_monitoring_subscription" "test" { + distribution_id = aws_cloudfront_distribution.test.id + + monitoring_subscription { + realtime_metrics_subscription_config { + realtime_metrics_subscription_status = %q + } + } +} +`, status)) +} From 4ef8063987c27badad5d9d42d9f93b5f88d9099a Mon Sep 17 00:00:00 2001 From: shuheiktgw Date: Mon, 15 Mar 2021 08:35:16 +0900 Subject: [PATCH 0901/1208] Add a document for aws_cloudfront_monitoring_subscription resource --- ...ront_monitoring_subscription.html.markdown | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 website/docs/r/cloudfront_monitoring_subscription.html.markdown diff --git a/website/docs/r/cloudfront_monitoring_subscription.html.markdown b/website/docs/r/cloudfront_monitoring_subscription.html.markdown new file mode 100644 index 000000000000..636762587459 --- /dev/null +++ b/website/docs/r/cloudfront_monitoring_subscription.html.markdown @@ -0,0 +1,54 @@ +--- +subcategory: "CloudFront" +layout: "aws" +page_title: "AWS: aws_cloudfront_monitoring_subscription" +description: |- + Provides a CloudFront monitoring subscription resource. +--- + +# Resource: aws_cloudfront_monitoring_subscription + +Provides a CloudFront real-time log configuration resource. + +## Example Usage + +```hcl +resource "aws_cloudfront_monitoring_subscription" "example" { + distribution_id = aws_cloudfront_distribution.example.id + + monitoring_subscription { + realtime_metrics_subscription_config { + realtime_metrics_subscription_status = "Enabled" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `distribution_id` - (Required) The ID of the distribution that you are enabling metrics for. +* `monitoring_subscription` - (Required) A monitoring subscription. This structure contains information about whether additional CloudWatch metrics are enabled for a given CloudFront distribution. + +The `monitoring_subscription` object supports the following argument: + +* `realtime_metrics_subscription_config` - (Required) A subscription configuration for additional CloudWatch metrics. + +The `realtime_metrics_subscription_config` object supports the following argument: + +* `realtime_metrics_subscription_status` - (Required) A flag that indicates whether additional CloudWatch metrics are enabled for a given CloudFront distribution. Valid values are `Enabled` and `Disabled`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the CloudFront monitoring subscription, which corresponds to the `distribution_id`. + +## Import + +CloudFront monitoring subscription can be imported using the id, e.g. + +``` +$ terraform import aws_cloudfront_monitoring_subscription.example E3QYSUHO4VYRGB +``` From c38fe522539561b41a221ca781c0959aa0ee3db0 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Wed, 30 Jun 2021 14:29:13 -0700 Subject: [PATCH 0902/1208] Add CHANGELOG entry --- .changelog/18083.txt | 3 ++ ..._aws_cloudfront_monitoring_subscription.go | 14 +++++---- ...cloudfront_monitoring_subscription_test.go | 30 +++++-------------- ...ront_monitoring_subscription.html.markdown | 8 ++--- 4 files changed, 22 insertions(+), 33 deletions(-) create mode 100644 .changelog/18083.txt diff --git a/.changelog/18083.txt b/.changelog/18083.txt new file mode 100644 index 000000000000..7aff48adf89d --- /dev/null +++ b/.changelog/18083.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_cloudfront_monitoring_subscription +``` diff --git a/aws/resource_aws_cloudfront_monitoring_subscription.go b/aws/resource_aws_cloudfront_monitoring_subscription.go index 71664e4c3a52..8cba547f5960 100644 --- a/aws/resource_aws_cloudfront_monitoring_subscription.go +++ b/aws/resource_aws_cloudfront_monitoring_subscription.go @@ -16,9 +16,10 @@ func resourceAwsCloudFrontMonitoringSubscription() *schema.Resource { return &schema.Resource{ Create: resourceAwsCloudFrontMonitoringSubscriptionCreate, Read: resourceAwsCloudFrontMonitoringSubscriptionRead, + Update: resourceAwsCloudFrontMonitoringSubscriptionCreate, Delete: resourceAwsCloudFrontMonitoringSubscriptionDelete, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: resourceAwsCloudFrontMonitoringSubscriptionImport, }, Schema: map[string]*schema.Schema{ @@ -31,7 +32,6 @@ func resourceAwsCloudFrontMonitoringSubscription() *schema.Resource { "monitoring_subscription": { Type: schema.TypeList, Required: true, - ForceNew: true, MinItems: 1, MaxItems: 1, Elem: &schema.Resource{ @@ -39,7 +39,6 @@ func resourceAwsCloudFrontMonitoringSubscription() *schema.Resource { "realtime_metrics_subscription_config": { Type: schema.TypeList, Required: true, - ForceNew: true, MinItems: 1, MaxItems: 1, Elem: &schema.Resource{ @@ -47,7 +46,6 @@ func resourceAwsCloudFrontMonitoringSubscription() *schema.Resource { "realtime_metrics_subscription_status": { Type: schema.TypeString, Required: true, - ForceNew: true, ValidateFunc: validation.StringInSlice(cloudfront.RealtimeMetricsSubscriptionStatus_Values(), false), }, }, @@ -86,7 +84,7 @@ func resourceAwsCloudFrontMonitoringSubscriptionRead(d *schema.ResourceData, met subscription, err := finder.MonitoringSubscriptionByDistributionId(conn, d.Id()) - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { + if tfawserr.ErrCodeEquals(err, cloudfront.ErrCodeNoSuchDistribution) { log.Printf("[WARN] CloudFront Distribution (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -105,7 +103,6 @@ func resourceAwsCloudFrontMonitoringSubscriptionRead(d *schema.ResourceData, met return nil } - d.Set("distribution_id", d.Id()) if err := d.Set("monitoring_subscription", flattenCloudFrontMonitoringSubscription(subscription)); err != nil { return fmt.Errorf("error setting monitoring_subscription: %w", err) } @@ -163,3 +160,8 @@ func flattenCloudFrontMonitoringSubscription(subscription *cloudfront.Monitoring func flattenCloudFrontRealtimeMetricsSubscriptionConfig(config *cloudfront.RealtimeMetricsSubscriptionConfig) []interface{} { return []interface{}{map[string]interface{}{"realtime_metrics_subscription_status": config.RealtimeMetricsSubscriptionStatus}} } + +func resourceAwsCloudFrontMonitoringSubscriptionImport(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + d.Set("distribution_id", d.Id()) + return []*schema.ResourceData{d}, nil +} diff --git a/aws/resource_aws_cloudfront_monitoring_subscription_test.go b/aws/resource_aws_cloudfront_monitoring_subscription_test.go index 4397e9b7c487..31dbb18e8c8c 100644 --- a/aws/resource_aws_cloudfront_monitoring_subscription_test.go +++ b/aws/resource_aws_cloudfront_monitoring_subscription_test.go @@ -78,7 +78,7 @@ func TestAccAWSCloudFrontMonitoringSubscription_basic(t *testing.T) { CheckDestroy: testAccCheckCloudFrontMonitoringSubscriptionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFrontMonitoringSubscriptionConfig(), + Config: testAccAWSCloudFrontMonitoringSubscriptionConfig("Enabled"), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFrontMonitoringSubscriptionExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "distribution_id"), @@ -106,7 +106,7 @@ func TestAccAWSCloudFrontMonitoringSubscription_disappears(t *testing.T) { CheckDestroy: testAccCheckCloudFrontMonitoringSubscriptionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFrontMonitoringSubscriptionConfig(), + Config: testAccAWSCloudFrontMonitoringSubscriptionConfig("Enabled"), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFrontMonitoringSubscriptionExists(resourceName, &v), testAccCheckResourceDisappears(testAccProvider, resourceAwsCloudFrontMonitoringSubscription(), resourceName), @@ -117,7 +117,7 @@ func TestAccAWSCloudFrontMonitoringSubscription_disappears(t *testing.T) { }) } -func TestAccAWSCloudFrontMonitoringSubscription_RealtimeMetricsSubscriptionConfig(t *testing.T) { +func TestAccAWSCloudFrontMonitoringSubscription_update(t *testing.T) { var v cloudfront.MonitoringSubscription resourceName := "aws_cloudfront_monitoring_subscription.test" @@ -127,7 +127,7 @@ func TestAccAWSCloudFrontMonitoringSubscription_RealtimeMetricsSubscriptionConfi CheckDestroy: testAccCheckCloudFrontMonitoringSubscriptionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCloudFrontMonitoringSubscriptionRealtimeMetricsSubscriptionConfigConfig("Enabled"), + Config: testAccAWSCloudFrontMonitoringSubscriptionConfig("Enabled"), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFrontMonitoringSubscriptionExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "distribution_id"), @@ -142,7 +142,7 @@ func TestAccAWSCloudFrontMonitoringSubscription_RealtimeMetricsSubscriptionConfi ImportStateVerify: true, }, { - Config: testAccAWSCloudFrontMonitoringSubscriptionRealtimeMetricsSubscriptionConfigConfig("Disabled"), + Config: testAccAWSCloudFrontMonitoringSubscriptionConfig("Disabled"), Check: resource.ComposeTestCheckFunc( testAccCheckCloudFrontMonitoringSubscriptionExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "distribution_id"), @@ -249,23 +249,7 @@ resource "aws_cloudfront_distribution" "test" { ` } -func testAccAWSCloudFrontMonitoringSubscriptionConfig() string { - return composeConfig( - testAccAWSCloudFrontMonitoringSubscriptionConfigBase(), - ` -resource "aws_cloudfront_monitoring_subscription" "test" { - distribution_id = aws_cloudfront_distribution.test.id - - monitoring_subscription { - realtime_metrics_subscription_config { - realtime_metrics_subscription_status = "Enabled" - } - } -} -`) -} - -func testAccAWSCloudFrontMonitoringSubscriptionRealtimeMetricsSubscriptionConfigConfig(status string) string { +func testAccAWSCloudFrontMonitoringSubscriptionConfig(status string) string { return composeConfig( testAccAWSCloudFrontMonitoringSubscriptionConfigBase(), fmt.Sprintf(` @@ -274,7 +258,7 @@ resource "aws_cloudfront_monitoring_subscription" "test" { monitoring_subscription { realtime_metrics_subscription_config { - realtime_metrics_subscription_status = %q + realtime_metrics_subscription_status = %[1]q } } } diff --git a/website/docs/r/cloudfront_monitoring_subscription.html.markdown b/website/docs/r/cloudfront_monitoring_subscription.html.markdown index 636762587459..53655a9e6bc3 100644 --- a/website/docs/r/cloudfront_monitoring_subscription.html.markdown +++ b/website/docs/r/cloudfront_monitoring_subscription.html.markdown @@ -31,13 +31,13 @@ The following arguments are supported: * `distribution_id` - (Required) The ID of the distribution that you are enabling metrics for. * `monitoring_subscription` - (Required) A monitoring subscription. This structure contains information about whether additional CloudWatch metrics are enabled for a given CloudFront distribution. -The `monitoring_subscription` object supports the following argument: +### monitoring_subscription -* `realtime_metrics_subscription_config` - (Required) A subscription configuration for additional CloudWatch metrics. +* `realtime_metrics_subscription_config` - (Required) A subscription configuration for additional CloudWatch metrics. See below. -The `realtime_metrics_subscription_config` object supports the following argument: +### realtime_metrics_subscription_config -* `realtime_metrics_subscription_status` - (Required) A flag that indicates whether additional CloudWatch metrics are enabled for a given CloudFront distribution. Valid values are `Enabled` and `Disabled`. +* `realtime_metrics_subscription_status` - (Required) A flag that indicates whether additional CloudWatch metrics are enabled for a given CloudFront distribution. Valid values are `Enabled` and `Disabled`. See below. ## Attributes Reference From b8d1828673262c3cc0e9733f022d8a38c8ece4ac Mon Sep 17 00:00:00 2001 From: bill-rich Date: Wed, 30 Jun 2021 14:50:24 -0700 Subject: [PATCH 0903/1208] Add ErrorCheck --- aws/resource_aws_cloudfront_monitoring_subscription_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aws/resource_aws_cloudfront_monitoring_subscription_test.go b/aws/resource_aws_cloudfront_monitoring_subscription_test.go index 31dbb18e8c8c..d5ebde409f9e 100644 --- a/aws/resource_aws_cloudfront_monitoring_subscription_test.go +++ b/aws/resource_aws_cloudfront_monitoring_subscription_test.go @@ -76,6 +76,7 @@ func TestAccAWSCloudFrontMonitoringSubscription_basic(t *testing.T) { PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(cloudfront.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckCloudFrontMonitoringSubscriptionDestroy, + ErrorCheck: testAccErrorCheck(t, cloudfront.EndpointsID), Steps: []resource.TestStep{ { Config: testAccAWSCloudFrontMonitoringSubscriptionConfig("Enabled"), @@ -104,6 +105,7 @@ func TestAccAWSCloudFrontMonitoringSubscription_disappears(t *testing.T) { PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(cloudfront.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckCloudFrontMonitoringSubscriptionDestroy, + ErrorCheck: testAccErrorCheck(t, cloudfront.EndpointsID), Steps: []resource.TestStep{ { Config: testAccAWSCloudFrontMonitoringSubscriptionConfig("Enabled"), @@ -125,6 +127,7 @@ func TestAccAWSCloudFrontMonitoringSubscription_update(t *testing.T) { PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(cloudfront.EndpointsID, t) }, Providers: testAccProviders, CheckDestroy: testAccCheckCloudFrontMonitoringSubscriptionDestroy, + ErrorCheck: testAccErrorCheck(t, cloudfront.EndpointsID), Steps: []resource.TestStep{ { Config: testAccAWSCloudFrontMonitoringSubscriptionConfig("Enabled"), From 26a7810da31381b84f4031e6855fbec0d02feeb8 Mon Sep 17 00:00:00 2001 From: bill-rich Date: Wed, 30 Jun 2021 14:52:20 -0700 Subject: [PATCH 0904/1208] Fix example code language --- website/docs/r/cloudfront_monitoring_subscription.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cloudfront_monitoring_subscription.html.markdown b/website/docs/r/cloudfront_monitoring_subscription.html.markdown index 53655a9e6bc3..ce4de36850f0 100644 --- a/website/docs/r/cloudfront_monitoring_subscription.html.markdown +++ b/website/docs/r/cloudfront_monitoring_subscription.html.markdown @@ -12,7 +12,7 @@ Provides a CloudFront real-time log configuration resource. ## Example Usage -```hcl +```terraform resource "aws_cloudfront_monitoring_subscription" "example" { distribution_id = aws_cloudfront_distribution.example.id From 0109e755da77a12dbd62ddb9676a0200231bb7a6 Mon Sep 17 00:00:00 2001 From: Jack Casey Date: Wed, 30 Jun 2021 21:04:13 -0700 Subject: [PATCH 0905/1208] Add detail on mapping for restricted option --- website/docs/r/transfer_user.html.markdown | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/website/docs/r/transfer_user.html.markdown b/website/docs/r/transfer_user.html.markdown index f011274e4ab7..c739d26281f8 100644 --- a/website/docs/r/transfer_user.html.markdown +++ b/website/docs/r/transfer_user.html.markdown @@ -94,6 +94,15 @@ The following arguments are supported: * `entry` - (Required) Represents an entry and a target. * `target` - (Required) Represents the map target. +The `Restricted` option is achieved using the following mapping: + +``` +home_directory_mappings { + entry = "/" + target = "/${aws_s3_bucket.foo.id}/$${Transfer:UserName}" +} +``` + ### Posix Profile * `gid` - (Required) The POSIX group ID used for all EFS operations by this user. From f22226de4cf529673e8e12cc17603d2de0bd53da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 06:06:00 +0000 Subject: [PATCH 0906/1208] build(deps): bump integrations/github in /infrastructure/repository Bumps [integrations/github](https://github.com/integrations/terraform-provider-github) from 4.12.0 to 4.12.1. - [Release notes](https://github.com/integrations/terraform-provider-github/releases) - [Changelog](https://github.com/integrations/terraform-provider-github/blob/master/CHANGELOG.md) - [Commits](https://github.com/integrations/terraform-provider-github/compare/v4.12.0...v4.12.1) --- updated-dependencies: - dependency-name: integrations/github dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- infrastructure/repository/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/repository/main.tf b/infrastructure/repository/main.tf index fa2688e230bf..d10b66d74711 100644 --- a/infrastructure/repository/main.tf +++ b/infrastructure/repository/main.tf @@ -10,7 +10,7 @@ terraform { required_providers { github = { source = "integrations/github" - version = "4.12.0" + version = "4.12.1" } } From 1c41f1270052d99bb5b48ab30458b8d1a23c535e Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 1 Jul 2021 10:26:50 +0300 Subject: [PATCH 0907/1208] add revoke and retry --- aws/resource_aws_cognito_user_pool_client.go | 21 +++++-- ...ource_aws_cognito_user_pool_client_test.go | 61 +++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool_client.go b/aws/resource_aws_cognito_user_pool_client.go index 1a6bda9f6363..45a45b3bd388 100644 --- a/aws/resource_aws_cognito_user_pool_client.go +++ b/aws/resource_aws_cognito_user_pool_client.go @@ -116,11 +116,16 @@ func resourceAwsCognitoUserPoolClient() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 1024), + validation.StringLenBetween(0, 1024), validation.StringMatch(regexp.MustCompile(`[\p{L}\p{M}\p{S}\p{N}\p{P}]+`), "must satisfy regular expression pattern: [\\p{L}\\p{M}\\p{S}\\p{N}\\p{P}]+`"), ), }, + "enable_token_revocation": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, "explicit_auth_flows": { Type: schema.TypeSet, Optional: true, @@ -311,6 +316,10 @@ func resourceAwsCognitoUserPoolClientCreate(d *schema.ResourceData, meta interfa params.PreventUserExistenceErrors = aws.String(v.(string)) } + if v, ok := d.GetOk("enable_token_revocation"); ok { + params.EnableTokenRevocation = aws.Bool(v.(bool)) + } + log.Printf("[DEBUG] Creating Cognito User Pool Client: %s", params) resp, err := conn.CreateUserPoolClient(params) @@ -363,6 +372,7 @@ func resourceAwsCognitoUserPoolClientRead(d *schema.ResourceData, meta interface d.Set("logout_urls", flattenStringSet(userPoolClient.LogoutURLs)) d.Set("prevent_user_existence_errors", userPoolClient.PreventUserExistenceErrors) d.Set("supported_identity_providers", flattenStringSet(userPoolClient.SupportedIdentityProviders)) + d.Set("enable_token_revocation", userPoolClient.EnableTokenRevocation) if err := d.Set("analytics_configuration", flattenAwsCognitoUserPoolClientAnalyticsConfig(userPoolClient.AnalyticsConfiguration)); err != nil { return fmt.Errorf("error setting analytics_configuration: %w", err) @@ -379,8 +389,9 @@ func resourceAwsCognitoUserPoolClientUpdate(d *schema.ResourceData, meta interfa conn := meta.(*AWSClient).cognitoidpconn params := &cognitoidentityprovider.UpdateUserPoolClientInput{ - ClientId: aws.String(d.Id()), - UserPoolId: aws.String(d.Get("user_pool_id").(string)), + ClientId: aws.String(d.Id()), + UserPoolId: aws.String(d.Get("user_pool_id").(string)), + EnableTokenRevocation: aws.Bool(d.Get("enable_token_revocation").(bool)), } if v, ok := d.GetOk("name"); ok { @@ -453,7 +464,9 @@ func resourceAwsCognitoUserPoolClientUpdate(d *schema.ResourceData, meta interfa log.Printf("[DEBUG] Updating Cognito User Pool Client: %s", params) - _, err := conn.UpdateUserPoolClient(params) + _, err := retryOnAwsCode(cognitoidentityprovider.ErrCodeConcurrentModificationException, func() (interface{}, error) { + return conn.UpdateUserPoolClient(params) + }) if err != nil { return fmt.Errorf("error updating Cognito User Pool Client (%s): %w", d.Id(), err) } diff --git a/aws/resource_aws_cognito_user_pool_client_test.go b/aws/resource_aws_cognito_user_pool_client_test.go index d9d0c54319f7..b5631516d349 100644 --- a/aws/resource_aws_cognito_user_pool_client_test.go +++ b/aws/resource_aws_cognito_user_pool_client_test.go @@ -45,6 +45,52 @@ func TestAccAWSCognitoUserPoolClient_basic(t *testing.T) { }) } +func TestAccAWSCognitoUserPoolClient_enableRevokation(t *testing.T) { + var client cognitoidentityprovider.UserPoolClientType + userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) + clientName := acctest.RandString(10) + resourceName := "aws_cognito_user_pool_client.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, + ErrorCheck: testAccErrorCheck(t, cognitoidentityprovider.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSCognitoUserPoolClientRevokationConfig(userPoolName, clientName, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "name", clientName), + resource.TestCheckResourceAttr(resourceName, "enable_token_revocation", "true"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAWSCognitoUserPoolClientImportStateIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSCognitoUserPoolClientRevokationConfig(userPoolName, clientName, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "name", clientName), + resource.TestCheckResourceAttr(resourceName, "enable_token_revocation", "false"), + ), + }, + { + Config: testAccAWSCognitoUserPoolClientRevokationConfig(userPoolName, clientName, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), + resource.TestCheckResourceAttr(resourceName, "name", clientName), + resource.TestCheckResourceAttr(resourceName, "enable_token_revocation", "true"), + ), + }, + }, + }) +} + func TestAccAWSCognitoUserPoolClient_refreshTokenValidity(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType rName := acctest.RandomWithPrefix("tf-acc-test") @@ -623,6 +669,21 @@ resource "aws_cognito_user_pool_client" "test" { `, userPoolName, clientName) } +func testAccAWSCognitoUserPoolClientRevokationConfig(userPoolName, clientName string, revoke bool) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "test" { + name = %[1]q +} + +resource "aws_cognito_user_pool_client" "test" { + name = %[2]q + user_pool_id = aws_cognito_user_pool.test.id + explicit_auth_flows = ["ADMIN_NO_SRP_AUTH"] + enable_token_revocation = %[3]t +} +`, userPoolName, clientName, revoke) +} + func testAccAWSCognitoUserPoolClientConfig_RefreshTokenValidity(rName string, refreshTokenValidity int) string { return fmt.Sprintf(` resource "aws_cognito_user_pool" "test" { From 5c61440c4c37d62c6cd14f8129adb14a80584c43 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 1 Jul 2021 10:40:21 +0300 Subject: [PATCH 0908/1208] rename --- aws/resource_aws_cognito_user_pool_client_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool_client_test.go b/aws/resource_aws_cognito_user_pool_client_test.go index b5631516d349..c8d87dfc3c45 100644 --- a/aws/resource_aws_cognito_user_pool_client_test.go +++ b/aws/resource_aws_cognito_user_pool_client_test.go @@ -45,7 +45,7 @@ func TestAccAWSCognitoUserPoolClient_basic(t *testing.T) { }) } -func TestAccAWSCognitoUserPoolClient_enableRevokation(t *testing.T) { +func TestAccAWSCognitoUserPoolClient_enableRevocation(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) clientName := acctest.RandString(10) @@ -58,7 +58,7 @@ func TestAccAWSCognitoUserPoolClient_enableRevokation(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolClientRevokationConfig(userPoolName, clientName, true), + Config: testAccAWSCognitoUserPoolClientRevocationConfig(userPoolName, clientName, true), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), resource.TestCheckResourceAttr(resourceName, "name", clientName), @@ -72,7 +72,7 @@ func TestAccAWSCognitoUserPoolClient_enableRevokation(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCognitoUserPoolClientRevokationConfig(userPoolName, clientName, false), + Config: testAccAWSCognitoUserPoolClientRevocationConfig(userPoolName, clientName, false), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), resource.TestCheckResourceAttr(resourceName, "name", clientName), @@ -80,7 +80,7 @@ func TestAccAWSCognitoUserPoolClient_enableRevokation(t *testing.T) { ), }, { - Config: testAccAWSCognitoUserPoolClientRevokationConfig(userPoolName, clientName, true), + Config: testAccAWSCognitoUserPoolClientRevocationConfig(userPoolName, clientName, true), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), resource.TestCheckResourceAttr(resourceName, "name", clientName), @@ -669,7 +669,7 @@ resource "aws_cognito_user_pool_client" "test" { `, userPoolName, clientName) } -func testAccAWSCognitoUserPoolClientRevokationConfig(userPoolName, clientName string, revoke bool) string { +func testAccAWSCognitoUserPoolClientRevocationConfig(userPoolName, clientName string, revoke bool) string { return fmt.Sprintf(` resource "aws_cognito_user_pool" "test" { name = %[1]q From 6e24253a793be6f499ca1347581606afdf583580 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 1 Jul 2021 12:16:08 +0300 Subject: [PATCH 0909/1208] refactor tests --- ...ource_aws_cognito_user_pool_client_test.go | 199 +++++++----------- 1 file changed, 80 insertions(+), 119 deletions(-) diff --git a/aws/resource_aws_cognito_user_pool_client_test.go b/aws/resource_aws_cognito_user_pool_client_test.go index c8d87dfc3c45..d6f0bfb681c7 100644 --- a/aws/resource_aws_cognito_user_pool_client_test.go +++ b/aws/resource_aws_cognito_user_pool_client_test.go @@ -14,8 +14,7 @@ import ( func TestAccAWSCognitoUserPoolClient_basic(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType - userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) - clientName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool_client.test" resource.ParallelTest(t, resource.TestCase{ @@ -25,10 +24,10 @@ func TestAccAWSCognitoUserPoolClient_basic(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolClientConfig_basic(userPoolName, clientName), + Config: testAccAWSCognitoUserPoolClientConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), - resource.TestCheckResourceAttr(resourceName, "name", clientName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "explicit_auth_flows.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName, "explicit_auth_flows.*", "ADMIN_NO_SRP_AUTH"), resource.TestCheckResourceAttr(resourceName, "token_validity_units.#", "0"), @@ -47,8 +46,8 @@ func TestAccAWSCognitoUserPoolClient_basic(t *testing.T) { func TestAccAWSCognitoUserPoolClient_enableRevocation(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType - userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) - clientName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_cognito_user_pool_client.test" resource.ParallelTest(t, resource.TestCase{ @@ -58,10 +57,10 @@ func TestAccAWSCognitoUserPoolClient_enableRevocation(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolClientRevocationConfig(userPoolName, clientName, true), + Config: testAccAWSCognitoUserPoolClientRevocationConfig(rName, true), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), - resource.TestCheckResourceAttr(resourceName, "name", clientName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "enable_token_revocation", "true"), ), }, @@ -72,18 +71,18 @@ func TestAccAWSCognitoUserPoolClient_enableRevocation(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCognitoUserPoolClientRevocationConfig(userPoolName, clientName, false), + Config: testAccAWSCognitoUserPoolClientRevocationConfig(rName, false), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), - resource.TestCheckResourceAttr(resourceName, "name", clientName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "enable_token_revocation", "false"), ), }, { - Config: testAccAWSCognitoUserPoolClientRevocationConfig(userPoolName, clientName, true), + Config: testAccAWSCognitoUserPoolClientRevocationConfig(rName, true), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), - resource.TestCheckResourceAttr(resourceName, "name", clientName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "enable_token_revocation", "true"), ), }, @@ -317,8 +316,7 @@ func TestAccAWSCognitoUserPoolClient_Name(t *testing.T) { func TestAccAWSCognitoUserPoolClient_allFields(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType - userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) - clientName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool_client.test" resource.ParallelTest(t, resource.TestCase{ @@ -328,10 +326,10 @@ func TestAccAWSCognitoUserPoolClient_allFields(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolClientConfig_allFields(userPoolName, clientName, 300), + Config: testAccAWSCognitoUserPoolClientConfig_allFields(rName, 300), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), - resource.TestCheckResourceAttr(resourceName, "name", clientName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "explicit_auth_flows.#", "3"), resource.TestCheckTypeSetElemAttr(resourceName, "explicit_auth_flows.*", "CUSTOM_AUTH_FLOW_ONLY"), resource.TestCheckTypeSetElemAttr(resourceName, "explicit_auth_flows.*", "USER_PASSWORD_AUTH"), @@ -374,8 +372,7 @@ func TestAccAWSCognitoUserPoolClient_allFields(t *testing.T) { func TestAccAWSCognitoUserPoolClient_allFieldsUpdatingOneField(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType - userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) - clientName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool_client.test" resource.ParallelTest(t, resource.TestCase{ @@ -385,13 +382,13 @@ func TestAccAWSCognitoUserPoolClient_allFieldsUpdatingOneField(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolClientConfig_allFields(userPoolName, clientName, 300), + Config: testAccAWSCognitoUserPoolClientConfig_allFields(rName, 300), }, { - Config: testAccAWSCognitoUserPoolClientConfig_allFields(userPoolName, clientName, 299), + Config: testAccAWSCognitoUserPoolClientConfig_allFields(rName, 299), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), - resource.TestCheckResourceAttr(resourceName, "name", clientName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "explicit_auth_flows.#", "3"), resource.TestCheckTypeSetElemAttr(resourceName, "explicit_auth_flows.*", "CUSTOM_AUTH_FLOW_ONLY"), resource.TestCheckTypeSetElemAttr(resourceName, "explicit_auth_flows.*", "USER_PASSWORD_AUTH"), @@ -434,8 +431,7 @@ func TestAccAWSCognitoUserPoolClient_allFieldsUpdatingOneField(t *testing.T) { func TestAccAWSCognitoUserPoolClient_analyticsConfig(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType - userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) - clientName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool_client.test" pinpointResourceName := "aws_pinpoint_app.test" @@ -450,12 +446,12 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfig(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolClientConfigAnalyticsConfig(userPoolName, clientName), + Config: testAccAWSCognitoUserPoolClientConfigAnalyticsConfig(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "analytics_configuration.0.application_id", pinpointResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "analytics_configuration.0.external_id", clientName), + resource.TestCheckResourceAttr(resourceName, "analytics_configuration.0.external_id", rName), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.0.user_data_shared", "false"), ), }, @@ -466,19 +462,19 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfig(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSCognitoUserPoolClientConfig_basic(userPoolName, clientName), + Config: testAccAWSCognitoUserPoolClientConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.#", "0"), ), }, { - Config: testAccAWSCognitoUserPoolClientConfigAnalyticsConfigShareUserData(userPoolName, clientName), + Config: testAccAWSCognitoUserPoolClientConfigAnalyticsConfigShareUserData(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "analytics_configuration.0.application_id", pinpointResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "analytics_configuration.0.external_id", clientName), + resource.TestCheckResourceAttr(resourceName, "analytics_configuration.0.external_id", rName), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.0.user_data_shared", "true"), ), }, @@ -488,8 +484,7 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfig(t *testing.T) { func TestAccAWSCognitoUserPoolClient_analyticsConfigWithArn(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType - userPoolName := acctest.RandString(10) - clientName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool_client.test" resource.ParallelTest(t, resource.TestCase{ @@ -503,7 +498,7 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfigWithArn(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolClientConfigAnalyticsWithArnConfig(userPoolName, clientName), + Config: testAccAWSCognitoUserPoolClientConfigAnalyticsWithArnConfig(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), resource.TestCheckResourceAttr(resourceName, "analytics_configuration.#", "1"), @@ -524,8 +519,7 @@ func TestAccAWSCognitoUserPoolClient_analyticsConfigWithArn(t *testing.T) { func TestAccAWSCognitoUserPoolClient_disappears(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType - userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) - clientName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool_client.test" resource.ParallelTest(t, resource.TestCase{ @@ -535,7 +529,7 @@ func TestAccAWSCognitoUserPoolClient_disappears(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolClientConfig_basic(userPoolName, clientName), + Config: testAccAWSCognitoUserPoolClientConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), testAccCheckResourceDisappears(testAccProvider, resourceAwsCognitoUserPoolClient(), resourceName), @@ -548,8 +542,7 @@ func TestAccAWSCognitoUserPoolClient_disappears(t *testing.T) { func TestAccAWSCognitoUserPoolClient_disappears_userPool(t *testing.T) { var client cognitoidentityprovider.UserPoolClientType - userPoolName := fmt.Sprintf("tf-acc-cognito-user-pool-%s", acctest.RandString(7)) - clientName := acctest.RandString(10) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_cognito_user_pool_client.test" resource.ParallelTest(t, resource.TestCase{ @@ -559,7 +552,7 @@ func TestAccAWSCognitoUserPoolClient_disappears_userPool(t *testing.T) { CheckDestroy: testAccCheckAWSCognitoUserPoolClientDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolClientConfig_basic(userPoolName, clientName), + Config: testAccAWSCognitoUserPoolClientConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSCognitoUserPoolClientExists(resourceName, &client), testAccCheckResourceDisappears(testAccProvider, resourceAwsCognitoUserPool(), "aws_cognito_user_pool.test"), @@ -655,83 +648,67 @@ func testAccCheckAWSCognitoUserPoolClientExists(name string, client *cognitoiden } } -func testAccAWSCognitoUserPoolClientConfig_basic(userPoolName, clientName string) string { +func testAccAWSCognitoUserPoolClientConfigBase(rName string) string { return fmt.Sprintf(` resource "aws_cognito_user_pool" "test" { - name = "%s" + name = %[1]q +} +`, rName) } +func testAccAWSCognitoUserPoolClientConfig_basic(rName string) string { + return testAccAWSCognitoUserPoolClientConfigBase(rName) + fmt.Sprintf(` resource "aws_cognito_user_pool_client" "test" { - name = "%s" + name = %[1]q user_pool_id = aws_cognito_user_pool.test.id explicit_auth_flows = ["ADMIN_NO_SRP_AUTH"] } -`, userPoolName, clientName) -} - -func testAccAWSCognitoUserPoolClientRevocationConfig(userPoolName, clientName string, revoke bool) string { - return fmt.Sprintf(` -resource "aws_cognito_user_pool" "test" { - name = %[1]q +`, rName) } +func testAccAWSCognitoUserPoolClientRevocationConfig(rName string, revoke bool) string { + return testAccAWSCognitoUserPoolClientConfigBase(rName) + fmt.Sprintf(` resource "aws_cognito_user_pool_client" "test" { - name = %[2]q + name = %[1]q user_pool_id = aws_cognito_user_pool.test.id explicit_auth_flows = ["ADMIN_NO_SRP_AUTH"] - enable_token_revocation = %[3]t + enable_token_revocation = %[2]t } -`, userPoolName, clientName, revoke) +`, rName, revoke) } func testAccAWSCognitoUserPoolClientConfig_RefreshTokenValidity(rName string, refreshTokenValidity int) string { - return fmt.Sprintf(` -resource "aws_cognito_user_pool" "test" { - name = "%s" -} - + return testAccAWSCognitoUserPoolClientConfigBase(rName) + fmt.Sprintf(` resource "aws_cognito_user_pool_client" "test" { - name = "%s" - refresh_token_validity = %d + name = %[1]q + refresh_token_validity = %[2]d user_pool_id = aws_cognito_user_pool.test.id } -`, rName, rName, refreshTokenValidity) +`, rName, refreshTokenValidity) } func testAccAWSCognitoUserPoolClientConfigAccessTokenValidity(rName string, validity int) string { - return fmt.Sprintf(` -resource "aws_cognito_user_pool" "test" { - name = "%s" -} - + return testAccAWSCognitoUserPoolClientConfigBase(rName) + fmt.Sprintf(` resource "aws_cognito_user_pool_client" "test" { - name = "%s" - access_token_validity = %d + name = %[1]q + access_token_validity = %[2]d user_pool_id = aws_cognito_user_pool.test.id } -`, rName, rName, validity) +`, rName, validity) } func testAccAWSCognitoUserPoolClientConfigIDTokenValidity(rName string, validity int) string { - return fmt.Sprintf(` -resource "aws_cognito_user_pool" "test" { - name = "%s" -} - + return testAccAWSCognitoUserPoolClientConfigBase(rName) + fmt.Sprintf(` resource "aws_cognito_user_pool_client" "test" { - name = "%s" - id_token_validity = %d + name = %[1]q + id_token_validity = %[2]d user_pool_id = aws_cognito_user_pool.test.id } -`, rName, rName, validity) +`, rName, validity) } func testAccAWSCognitoUserPoolClientConfigTokenValidityUnits(rName, units string) string { - return fmt.Sprintf(` -resource "aws_cognito_user_pool" "test" { - name = %[1]q -} - + return testAccAWSCognitoUserPoolClientConfigBase(rName) + fmt.Sprintf(` resource "aws_cognito_user_pool_client" "test" { name = %[1]q user_pool_id = aws_cognito_user_pool.test.id @@ -746,11 +723,7 @@ resource "aws_cognito_user_pool_client" "test" { } func testAccAWSCognitoUserPoolClientConfigTokenValidityUnitsWithTokenValidity(rName, units string) string { - return fmt.Sprintf(` -resource "aws_cognito_user_pool" "test" { - name = %[1]q -} - + return testAccAWSCognitoUserPoolClientConfigBase(rName) + fmt.Sprintf(` resource "aws_cognito_user_pool_client" "test" { name = %[1]q user_pool_id = aws_cognito_user_pool.test.id @@ -766,26 +739,18 @@ resource "aws_cognito_user_pool_client" "test" { } func testAccAWSCognitoUserPoolClientConfig_Name(rName, name string) string { - return fmt.Sprintf(` -resource "aws_cognito_user_pool" "test" { - name = %[1]q -} - + return testAccAWSCognitoUserPoolClientConfigBase(rName) + fmt.Sprintf(` resource "aws_cognito_user_pool_client" "test" { - name = %[2]q + name = %[1]q user_pool_id = aws_cognito_user_pool.test.id } -`, rName, name) -} - -func testAccAWSCognitoUserPoolClientConfig_allFields(userPoolName, clientName string, refreshTokenValidity int) string { - return fmt.Sprintf(` -resource "aws_cognito_user_pool" "test" { - name = "%s" +`, name) } +func testAccAWSCognitoUserPoolClientConfig_allFields(rName string, refreshTokenValidity int) string { + return testAccAWSCognitoUserPoolClientConfigBase(rName) + fmt.Sprintf(` resource "aws_cognito_user_pool_client" "test" { - name = "%s" + name = %[1]q user_pool_id = aws_cognito_user_pool.test.id explicit_auth_flows = ["ADMIN_NO_SRP_AUTH", "CUSTOM_AUTH_FLOW_ONLY", "USER_PASSWORD_AUTH"] @@ -795,7 +760,7 @@ resource "aws_cognito_user_pool_client" "test" { read_attributes = ["email"] write_attributes = ["email"] - refresh_token_validity = %d + refresh_token_validity = %[2]d prevent_user_existence_errors = "LEGACY" allowed_oauth_flows = ["code", "implicit"] @@ -806,25 +771,21 @@ resource "aws_cognito_user_pool_client" "test" { default_redirect_uri = "https://www.example.com/redirect" logout_urls = ["https://www.example.com/login"] } -`, userPoolName, clientName, refreshTokenValidity) +`, rName, refreshTokenValidity) } -func testAccAWSCognitoUserPoolClientConfigAnalyticsConfigBase(userPoolName, clientName string) string { - return fmt.Sprintf(` +func testAccAWSCognitoUserPoolClientConfigAnalyticsConfigBase(rName string) string { + return testAccAWSCognitoUserPoolClientConfigBase(rName) + fmt.Sprintf(` data "aws_caller_identity" "current" {} data "aws_partition" "current" {} -resource "aws_cognito_user_pool" "test" { - name = %[1]q -} - resource "aws_pinpoint_app" "test" { - name = %[2]q + name = %[1]q } resource "aws_iam_role" "test" { - name = %[2]q + name = %[1]q assume_role_policy = < Date: Thu, 1 Jul 2021 08:56:11 -0400 Subject: [PATCH 0910/1208] r/aws_transfer_server: Add tests to set no VPC subnet IDs or security group IDs. --- aws/resource_aws_transfer_server.go | 21 +++++++++--- aws/resource_aws_transfer_server_test.go | 43 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index fc06e68e4624..162533614f9e 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -376,7 +376,7 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e conn := meta.(*AWSClient).transferconn if d.HasChangesExcept("tags", "tags_all") { - //TODO var addressAllocationIDs []*string + var addressAllocationIDs []*string var offlineUpdate bool input := &transfer.UpdateServerInput{ @@ -404,10 +404,9 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e } if newEndpointTypeVpc && !oldEndpointTypeVpc { - // TODO ???? // Prevent the following error: InvalidRequestException: Cannot specify AddressAllocationids when updating server to EndpointType: VPC - // addressAllocationIDs = input.EndpointDetails.AddressAllocationIds - // input.EndpointDetails.AddressAllocationIds = nil + addressAllocationIDs = input.EndpointDetails.AddressAllocationIds + input.EndpointDetails.AddressAllocationIds = nil // Prevent the following error: InvalidRequestException: VPC Endpoint ID unsupported for EndpointType: VPC input.EndpointDetails.VpcEndpointId = nil @@ -505,6 +504,20 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e return err } + // Set any AddressAllocationIds if the server has updated endpoint type to VPC. + if len(addressAllocationIDs) > 0 { + input := &transfer.UpdateServerInput{ + ServerId: aws.String(d.Id()), + EndpointDetails: &transfer.EndpointDetails{ + AddressAllocationIds: addressAllocationIDs, + }, + } + + if err := updateTransferServer(conn, input); err != nil { + return err + } + } + if offlineUpdate { if err := startTransferServer(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { return err diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index 6400e56f1ab1..be2668959b38 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -275,6 +275,20 @@ func testAccAWSTransferServer_vpc(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, + { + Config: testAccAWSTransferServerVpcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, }, }) } @@ -333,6 +347,20 @@ func testAccAWSTransferServer_vpcAddressAllocationIds(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, + { + Config: testAccAWSTransferServerVpcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, }, }) } @@ -342,6 +370,7 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { resourceName := "aws_transfer_server.test" securityGroup1ResourceName := "aws_security_group.test" securityGroup2ResourceName := "aws_security_group.test2" + defaultSecurityGroupResourceName := "aws_default_security_group.test" vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -385,6 +414,20 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, + { + Config: testAccAWSTransferServerVpcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferServerExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), + resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + ), + }, }, }) } From d635b87ee9b04e94637eabd955ed2f9cce40eed4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Jul 2021 10:05:18 -0400 Subject: [PATCH 0911/1208] r/aws_vpc_endpoint: Ignore errors such as Error: error deleting EC2 VPC Endpoint (vpce-09a9ae6b78f2b0571): 1 error occurred: * vpce-09a9ae6b78f2b0571: InvalidVpcEndpoint.NotFound: The Vpc Endpoint Id 'vpce-09a9ae6b78f2b0571' does not exist --- aws/internal/service/ec2/errors.go | 4 +- aws/internal/service/ec2/errors_test.go | 133 ++++++++++++++++++++++++ aws/resource_aws_vpc_endpoint.go | 14 +-- 3 files changed, 141 insertions(+), 10 deletions(-) create mode 100644 aws/internal/service/ec2/errors_test.go diff --git a/aws/internal/service/ec2/errors.go b/aws/internal/service/ec2/errors.go index cbcac12e0975..e4c94a554084 100644 --- a/aws/internal/service/ec2/errors.go +++ b/aws/internal/service/ec2/errors.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" multierror "github.com/hashicorp/go-multierror" ) @@ -69,6 +70,7 @@ const ( const ( ErrCodeInvalidVpcEndpointIdNotFound = "InvalidVpcEndpointId.NotFound" + ErrCodeInvalidVpcEndpointNotFound = "InvalidVpcEndpoint.NotFound" ErrCodeInvalidVpcEndpointServiceIdNotFound = "InvalidVpcEndpointServiceId.NotFound" ) @@ -86,7 +88,7 @@ func UnsuccessfulItemError(apiObject *ec2.UnsuccessfulItemError) error { return nil } - return fmt.Errorf("%s: %s", aws.StringValue(apiObject.Code), aws.StringValue(apiObject.Message)) + return awserr.New(aws.StringValue(apiObject.Code), aws.StringValue(apiObject.Message), nil) } func UnsuccessfulItemsError(apiObjects []*ec2.UnsuccessfulItem) error { diff --git a/aws/internal/service/ec2/errors_test.go b/aws/internal/service/ec2/errors_test.go new file mode 100644 index 000000000000..7bdc90fa31b5 --- /dev/null +++ b/aws/internal/service/ec2/errors_test.go @@ -0,0 +1,133 @@ +package ec2_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" +) + +func TestUnsuccessfulItemError(t *testing.T) { + unsuccessfulItemError := &ec2.UnsuccessfulItemError{ + Code: aws.String("test code"), + Message: aws.String("test message"), + } + + err := tfec2.UnsuccessfulItemError(unsuccessfulItemError) + + if !tfawserr.ErrCodeEquals(err, "test code") { + t.Errorf("tfawserr.ErrCodeEquals failed: %s", err) + } + + if !tfawserr.ErrMessageContains(err, "test code", "est mess") { + t.Errorf("tfawserr.ErrMessageContains failed: %s", err) + } +} + +func TestUnsuccessfulItemsError(t *testing.T) { + testCases := []struct { + Name string + Items []*ec2.UnsuccessfulItem + Expected bool + }{ + { + Name: "no items", + }, + { + Name: "one item no error", + Items: []*ec2.UnsuccessfulItem{ + { + ResourceId: aws.String("test resource"), + }, + }, + }, + { + Name: "one item", + Items: []*ec2.UnsuccessfulItem{ + { + Error: &ec2.UnsuccessfulItemError{ + Code: aws.String("test code"), + Message: aws.String("test message"), + }, + ResourceId: aws.String("test resource"), + }, + }, + Expected: true, + }, + { + Name: "two items, first no error", + Items: []*ec2.UnsuccessfulItem{ + { + ResourceId: aws.String("test resource 1"), + }, + { + Error: &ec2.UnsuccessfulItemError{ + Code: aws.String("test code"), + Message: aws.String("test message"), + }, + ResourceId: aws.String("test resource 2"), + }, + }, + Expected: true, + }, + { + Name: "two items, first not as expected", + Items: []*ec2.UnsuccessfulItem{ + { + Error: &ec2.UnsuccessfulItemError{ + Code: aws.String("not what is required"), + Message: aws.String("not what is wanted"), + }, + ResourceId: aws.String("test resource 1"), + }, + { + Error: &ec2.UnsuccessfulItemError{ + Code: aws.String("test code"), + Message: aws.String("test message"), + }, + ResourceId: aws.String("test resource 2"), + }, + }, + }, + { + Name: "two items, first as expected", + Items: []*ec2.UnsuccessfulItem{ + { + Error: &ec2.UnsuccessfulItemError{ + Code: aws.String("test code"), + Message: aws.String("test message"), + }, + ResourceId: aws.String("test resource 1"), + }, + { + Error: &ec2.UnsuccessfulItemError{ + Code: aws.String("not what is required"), + Message: aws.String("not what is wanted"), + }, + ResourceId: aws.String("test resource 2"), + }, + }, + Expected: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.Name, func(t *testing.T) { + err := tfec2.UnsuccessfulItemsError(testCase.Items) + + got := tfawserr.ErrCodeEquals(err, "test code") + + if got != testCase.Expected { + t.Errorf("ErrCodeEquals got %t, expected %t", got, testCase.Expected) + } + + got = tfawserr.ErrMessageContains(err, "test code", "est mess") + + if got != testCase.Expected { + t.Errorf("ErrMessageContains got %t, expected %t", got, testCase.Expected) + } + }) + } +} diff --git a/aws/resource_aws_vpc_endpoint.go b/aws/resource_aws_vpc_endpoint.go index 0f372c3acf0f..8520c36a88ab 100644 --- a/aws/resource_aws_vpc_endpoint.go +++ b/aws/resource_aws_vpc_endpoint.go @@ -377,7 +377,11 @@ func resourceAwsVpcEndpointDelete(d *schema.ResourceData, meta interface{}) erro output, err := conn.DeleteVpcEndpoints(input) - if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidVpcEndpointIdNotFound) { + if err == nil && output != nil { + err = tfec2.UnsuccessfulItemsError(output.Unsuccessful) + } + + if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidVpcEndpointNotFound) { return nil } @@ -385,14 +389,6 @@ func resourceAwsVpcEndpointDelete(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("error deleting EC2 VPC Endpoint (%s): %w", d.Id(), err) } - if output != nil && len(output.Unsuccessful) > 0 { - err := tfec2.UnsuccessfulItemsError(output.Unsuccessful) - - if err != nil { - return fmt.Errorf("error deleting EC2 VPC Endpoint (%s): %w", d.Id(), err) - } - } - _, err = waiter.VpcEndpointDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) if err != nil { From e597a095a2d89780b42e107e8aac18ad96a8aa69 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Jul 2021 10:17:41 -0400 Subject: [PATCH 0912/1208] Triple tick for changelog entry. --- .changelog/17754.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/17754.txt b/.changelog/17754.txt index eaff8273ffc9..e204d94078fe 100644 --- a/.changelog/17754.txt +++ b/.changelog/17754.txt @@ -1,3 +1,3 @@ -``release-note:bug +```release-note:bug resource/aws_cloudwatch_event_archive: Fix retention_days type conversion on creation ``` From 163c41745c837c26d74bff0d2771db3bd7d727bf Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 1 Jul 2021 17:25:46 +0300 Subject: [PATCH 0913/1208] docs --- website/docs/r/cognito_user_pool_client.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/cognito_user_pool_client.markdown b/website/docs/r/cognito_user_pool_client.markdown index a4fed4fc222c..a3e6d6920634 100644 --- a/website/docs/r/cognito_user_pool_client.markdown +++ b/website/docs/r/cognito_user_pool_client.markdown @@ -126,6 +126,7 @@ The following arguments are optional: * `analytics_configuration` - (Optional) Configuration block for Amazon Pinpoint analytics for collecting metrics for this user pool. [Detailed below](#analytics_configuration). * `callback_urls` - (Optional) List of allowed callback URLs for the identity providers. * `default_redirect_uri` - (Optional) Default redirect URI. Must be in the list of callback URLs. +* `enable_token_revocation` - (Optional) Enables or disables token revocation. * `explicit_auth_flows` - (Optional) List of authentication flows (ADMIN_NO_SRP_AUTH, CUSTOM_AUTH_FLOW_ONLY, USER_PASSWORD_AUTH, ALLOW_ADMIN_USER_PASSWORD_AUTH, ALLOW_CUSTOM_AUTH, ALLOW_USER_PASSWORD_AUTH, ALLOW_USER_SRP_AUTH, ALLOW_REFRESH_TOKEN_AUTH). * `generate_secret` - (Optional) Should an application secret be generated. * `id_token_validity` - (Optional) Time limit, between 5 minutes and 1 day, after which the ID token is no longer valid and cannot be used. This value will be overridden if you have entered a value in `token_validity_units`. From 3bb599ad77265433aaeedb528e0db65431544648 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Jul 2021 10:26:02 -0400 Subject: [PATCH 0914/1208] 'release-notes' -> 'release-note' for changelog entry. --- .changelog/16850.txt | 4 ++-- .changelog/16908.txt | 4 ++-- .changelog/16916.txt | 4 ++-- .changelog/16961.txt | 2 +- .changelog/16963.txt | 2 +- .changelog/16979.txt | 6 +++--- .changelog/17001.txt | 4 ++-- .changelog/17295.txt | 2 +- .changelog/17319.txt | 6 +++--- .changelog/17347.txt | 2 +- .changelog/17655.txt | 2 +- .changelog/18932.txt | 2 +- .changelog/19168.txt | 6 +++--- .changelog/19391.txt | 4 ++-- .changelog/19415.txt | 8 ++++---- .changelog/19423.txt | 2 +- .changelog/19425.txt | 10 +++++----- .changelog/19499.txt | 4 ++-- .changelog/19503.txt | 4 ++-- .changelog/19572.txt | 4 ++-- .changelog/19813.txt | 4 ++-- 21 files changed, 43 insertions(+), 43 deletions(-) diff --git a/.changelog/16850.txt b/.changelog/16850.txt index 62b0494c3bae..1976b664a307 100644 --- a/.changelog/16850.txt +++ b/.changelog/16850.txt @@ -1,3 +1,3 @@ -```release-notes:enhancement +```release-note:enhancement resource/aws_batch_job_definition: Add `platform_capabilities` attribute -``` \ No newline at end of file +``` diff --git a/.changelog/16908.txt b/.changelog/16908.txt index 0ae07b54cb64..5e161a9ee9e4 100644 --- a/.changelog/16908.txt +++ b/.changelog/16908.txt @@ -1,3 +1,3 @@ -```release-notes:enhancement +```release-note:enhancement resource/aws_instance: Add `capacity_reservation_specification` argument -``` \ No newline at end of file +``` diff --git a/.changelog/16916.txt b/.changelog/16916.txt index 0e2f404319f2..2a56750ba77d 100644 --- a/.changelog/16916.txt +++ b/.changelog/16916.txt @@ -1,3 +1,3 @@ -```release-notes:enhancement +```release-note:enhancement resource/aws_lakeformation_permissions: Allow `principal` to be an AWS account ID or an IAM group, ou, or organization -``` \ No newline at end of file +``` diff --git a/.changelog/16961.txt b/.changelog/16961.txt index 0d8a128b9214..79b018a06168 100644 --- a/.changelog/16961.txt +++ b/.changelog/16961.txt @@ -1,3 +1,3 @@ -```release-notes:enhancement +```release-note:enhancement resource/aws_route: Add `carrier_gateway_id` attribute ``` diff --git a/.changelog/16963.txt b/.changelog/16963.txt index fe1bfd80372d..b29a53dc5200 100644 --- a/.changelog/16963.txt +++ b/.changelog/16963.txt @@ -1,3 +1,3 @@ -```release-notes:enhancement +```release-note:enhancement data-source/aws_route: Add `carrier_gateway_id` attribute ``` diff --git a/.changelog/16979.txt b/.changelog/16979.txt index 0c1a7fc785f9..ef3f5337416d 100644 --- a/.changelog/16979.txt +++ b/.changelog/16979.txt @@ -1,11 +1,11 @@ -```release-notes:enhancement +```release-note:enhancement resource/aws_default_route_table: Add `arn` attribute ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_route_table: Add `arn` attribute ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_route_table: Add `carrier_gateway_id` attribute to `route` configuration block ``` diff --git a/.changelog/17001.txt b/.changelog/17001.txt index 31e76d12e7d6..6c752c43368c 100644 --- a/.changelog/17001.txt +++ b/.changelog/17001.txt @@ -1,7 +1,7 @@ -```release-notes:enhancement +```release-note:enhancement data-source/aws_route_table: Add `arn` attribute ``` -```release-notes:enhancement +```release-note:enhancement data-source/aws_route_table: Add `carrier_gateway_id` attribute to `routes` list ``` diff --git a/.changelog/17295.txt b/.changelog/17295.txt index 1aa7f7f378dc..eb45eadef04e 100644 --- a/.changelog/17295.txt +++ b/.changelog/17295.txt @@ -1,3 +1,3 @@ -```release-notes:enhancement +```release-note:enhancement data-source/aws_route: Add `destination_prefix_list_id` attribute ``` diff --git a/.changelog/17319.txt b/.changelog/17319.txt index 01a6b8f59b9c..73a72331214c 100644 --- a/.changelog/17319.txt +++ b/.changelog/17319.txt @@ -1,8 +1,8 @@ -```release-notes:enhancement +```release-note:enhancement resource/aws_default_route_table: Add `destination_prefix_list_id` attribute ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_route_table: Add `destination_prefix_list_id` attribute ``` @@ -16,4 +16,4 @@ resource/aws_route_table: Improve eventual consistency handling and handling of ```release-note:bug resource/aws_route_table_association: Improve eventual consistency handling and handling of out-of-band resource removal -``` \ No newline at end of file +``` diff --git a/.changelog/17347.txt b/.changelog/17347.txt index 796e74a274c9..341f4ddda9ae 100644 --- a/.changelog/17347.txt +++ b/.changelog/17347.txt @@ -1,3 +1,3 @@ -```release-notes:enhancement +```release-note:enhancement data-source/aws_route_table: Add `destination_prefix_list_id` attribute ``` diff --git a/.changelog/17655.txt b/.changelog/17655.txt index f7b060ce23dd..f8532bdd8a48 100644 --- a/.changelog/17655.txt +++ b/.changelog/17655.txt @@ -1,3 +1,3 @@ -```release-notes:note +```release-note:note provider: The default development, testing and building of the Terraform AWS Provider is now done with Go 1.16. This version of Go adds support for `darwin/arm64` (Apple Silicon) but deprecates support for macOS 10.12 (Sierra). ``` diff --git a/.changelog/18932.txt b/.changelog/18932.txt index 7c81aae95ce9..b97353b452bb 100644 --- a/.changelog/18932.txt +++ b/.changelog/18932.txt @@ -1,3 +1,3 @@ -```release-notes:enhancement +```release-note:enhancement resource/aws_datasync_task: Add `options` `log_level` attribute ``` diff --git a/.changelog/19168.txt b/.changelog/19168.txt index 2c0a0b1f44ce..51c89c04c98c 100644 --- a/.changelog/19168.txt +++ b/.changelog/19168.txt @@ -2,10 +2,10 @@ resource/aws_shield_protection: Add `tags` argument ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_shield_protection: Add `arn` attribute ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_shield_protection: Missing resources are now detected and recreated -``` \ No newline at end of file +``` diff --git a/.changelog/19391.txt b/.changelog/19391.txt index 113f81bf3fc2..d9484020e8ae 100644 --- a/.changelog/19391.txt +++ b/.changelog/19391.txt @@ -1,3 +1,3 @@ -```release-notes:new-data-source +```release-note:new-data-source aws_default_tags -``` \ No newline at end of file +``` diff --git a/.changelog/19415.txt b/.changelog/19415.txt index 6ff2032e1a39..03052da1f90a 100644 --- a/.changelog/19415.txt +++ b/.changelog/19415.txt @@ -1,15 +1,15 @@ -```release-notes:enhancement +```release-note:enhancement resource/aws_wafv2_web_acl: Add `custom_request_handling` to `allow` and `count` default action and rule actions. ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_wafv2_web_acl: Add `custom_response` to `block` default action and rule actions. ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_wafv2_rule_group: Add `custom_request_handling` to `allow` and `count` rule actions. ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_wafv2_rule_group: Add `custom_response` to `block` rule actions. ``` diff --git a/.changelog/19423.txt b/.changelog/19423.txt index 668fb42ddbd9..0731a70f0acf 100644 --- a/.changelog/19423.txt +++ b/.changelog/19423.txt @@ -1,3 +1,3 @@ -```release-notes:note +```release-note:note resource/aws_appmesh_virtual_node: Number of default backends per virtual node increased up to 50 ``` diff --git a/.changelog/19425.txt b/.changelog/19425.txt index 270d361e8a9c..7133279ad1f4 100644 --- a/.changelog/19425.txt +++ b/.changelog/19425.txt @@ -1,15 +1,15 @@ -```release-notes:enhancement +```release-note:enhancement resource/aws_lambda_event_source_mapping: Add `self_managed_event_source` and `source_access_configuration` arguments to support self-managed Apache Kafka event sources ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_lambda_event_source_mapping: Add `tumbling_window_in_seconds` argument to support AWS Lambda streaming analytics calculations ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_lambda_event_source_mapping: Add `function_response_types` argument to support AWS Lambda checkpointing ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_lambda_event_source_mapping: Add `queues` argument to support Amazon MQ for Apache ActiveMQ event sources -``` \ No newline at end of file +``` diff --git a/.changelog/19499.txt b/.changelog/19499.txt index 92a274598bbc..db1e6936e0ab 100644 --- a/.changelog/19499.txt +++ b/.changelog/19499.txt @@ -1,3 +1,3 @@ -```release-notes:new-data-source +```release-note:new-data-source aws_servicecatalog_constraint -``` \ No newline at end of file +``` diff --git a/.changelog/19503.txt b/.changelog/19503.txt index 88b7b14cb403..184824e42dec 100644 --- a/.changelog/19503.txt +++ b/.changelog/19503.txt @@ -1,3 +1,3 @@ -```release-notes:new-data-source +```release-note:new-data-source aws_servicecatalog_product - ``` \ No newline at end of file + ``` diff --git a/.changelog/19572.txt b/.changelog/19572.txt index 2c13789f2181..9a3b532f9318 100644 --- a/.changelog/19572.txt +++ b/.changelog/19572.txt @@ -1,3 +1,3 @@ -```release-notes:new-data-source +```release-note:new-data-source aws_servicecatalog_launch_paths -``` \ No newline at end of file +``` diff --git a/.changelog/19813.txt b/.changelog/19813.txt index af1420e8b70d..7d1458ae4830 100644 --- a/.changelog/19813.txt +++ b/.changelog/19813.txt @@ -1,3 +1,3 @@ -```release-notes:new-data-source +```release-note:new-data-source aws_servicecatalog_portfolio_constraints -``` \ No newline at end of file +``` From 92f626a8c401d89c1fbc334f064373684c26e281 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 1 Jul 2021 14:31:59 +0000 Subject: [PATCH 0915/1208] Update CHANGELOG.md for #20041 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2323c353d39c..118c5dcc0d60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ FEATURES: * **New Data Source:** `aws_iam_session_context` ([#19957](https://github.com/hashicorp/terraform-provider-aws/issues/19957)) +* **New Data Source:** `aws_servicecatalog_launch_paths` ([#19572](https://github.com/hashicorp/terraform-provider-aws/issues/19572)) +* **New Data Source:** `aws_servicecatalog_portfolio_constraints` ([#19813](https://github.com/hashicorp/terraform-provider-aws/issues/19813)) +* **New Resource:** `aws_cloudfront_monitoring_subscription` ([#18083](https://github.com/hashicorp/terraform-provider-aws/issues/18083)) * **New Resource:** `aws_servicecatalog_provisioned_product` ([#19459](https://github.com/hashicorp/terraform-provider-aws/issues/19459)) ENHANCEMENTS: From e6c3deaa516092a474ab8d510762be242e9ec94d Mon Sep 17 00:00:00 2001 From: Deku-shrub Date: Thu, 1 Jul 2021 15:37:35 +0100 Subject: [PATCH 0916/1208] correct value --- aws/data_source_aws_wafv2_regex_pattern_set_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/data_source_aws_wafv2_regex_pattern_set_test.go b/aws/data_source_aws_wafv2_regex_pattern_set_test.go index 0d2fb68921d5..a1a4c9621247 100644 --- a/aws/data_source_aws_wafv2_regex_pattern_set_test.go +++ b/aws/data_source_aws_wafv2_regex_pattern_set_test.go @@ -32,7 +32,7 @@ func TestAccDataSourceAwsWafv2RegexPatternSet_basic(t *testing.T) { resource.TestCheckResourceAttrPair(datasourceName, "description", resourceName, "description"), resource.TestCheckResourceAttrPair(datasourceName, "id", resourceName, "id"), resource.TestCheckResourceAttrPair(datasourceName, "name", resourceName, "name"), - resource.TestCheckResourceAttrPair(datasourceName, "regular_expression_list", resourceName, "regular_expression_list"), + resource.TestCheckResourceAttrPair(datasourceName, "regular_expression", resourceName, "regular_expression"), resource.TestCheckResourceAttrPair(datasourceName, "scope", resourceName, "scope"), ), }, From dc51a726fdafcd5624979a16007520cfff1eec5a Mon Sep 17 00:00:00 2001 From: Deku-shrub Date: Thu, 1 Jul 2021 15:38:57 +0100 Subject: [PATCH 0917/1208] correct value --- website/docs/r/wafv2_rule_group.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/wafv2_rule_group.html.markdown b/website/docs/r/wafv2_rule_group.html.markdown index a8432218bf11..276bcb306d88 100644 --- a/website/docs/r/wafv2_rule_group.html.markdown +++ b/website/docs/r/wafv2_rule_group.html.markdown @@ -64,7 +64,7 @@ resource "aws_wafv2_regex_pattern_set" "test" { name = "test" scope = "REGIONAL" - regular_expression_list { + regular_expression { regex_string = "one" } } From 62593d79cb062f7e09244442f8f248e1b5a6eddb Mon Sep 17 00:00:00 2001 From: Jeremy Ciak Date: Wed, 9 Dec 2020 22:37:15 -0500 Subject: [PATCH 0918/1208] Adding support for aliases with FSx for Windows --- aws/resource_aws_fsx_windows_file_system.go | 105 ++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/aws/resource_aws_fsx_windows_file_system.go b/aws/resource_aws_fsx_windows_file_system.go index 1dbf1f7dae05..8f1f11ca8a7d 100644 --- a/aws/resource_aws_fsx_windows_file_system.go +++ b/aws/resource_aws_fsx_windows_file_system.go @@ -43,6 +43,18 @@ func resourceAwsFsxWindowsFileSystem() *schema.Resource { ForceNew: true, ConflictsWith: []string{"self_managed_active_directory"}, }, + "aliases": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 50, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.All( + validation.StringLenBetween(4, 253), + validation.StringMatch(regexp.MustCompile(`^[A-Za-z0-9]([.][A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])+$`), "must be in the fqdn format hostname.domain"), + ), + }, + }, "arn": { Type: schema.TypeString, Computed: true, @@ -265,6 +277,10 @@ func resourceAwsFsxWindowsFileSystemCreate(d *schema.ResourceData, meta interfac input.WindowsConfiguration.ActiveDirectoryId = aws.String(v.(string)) } + if v, ok := d.GetOk("aliases"); ok { + input.WindowsConfiguration.Aliases = expandStringSet(v.(*schema.Set)) + } + if v, ok := d.GetOk("deployment_type"); ok { input.WindowsConfiguration.DeploymentType = aws.String(v.(string)) } @@ -339,6 +355,14 @@ func resourceAwsFsxWindowsFileSystemUpdate(d *schema.ResourceData, meta interfac WindowsConfiguration: &fsx.UpdateFileSystemWindowsConfiguration{}, } + if d.HasChange("aliases") { + o, n := d.GetChange("aliases") + + if err := updateFsxAliases(conn, d.Get("arn").(string), o.([]*fsx.Alias), n.([]*fsx.Alias)); err != nil { + return fmt.Errorf("error updating FSx Windows File System (%s) aliases: %s", d.Get("arn").(string), err) + } + } + if d.HasChange("automatic_backup_retention_days") { input.WindowsConfiguration.AutomaticBackupRetentionDays = aws.Int64(int64(d.Get("automatic_backup_retention_days").(int))) } @@ -425,6 +449,10 @@ func resourceAwsFsxWindowsFileSystemRead(d *schema.ResourceData, meta interface{ d.Set("kms_key_id", filesystem.KmsKeyId) d.Set("storage_type", filesystem.StorageType) + if err := d.Set("aliases", aws.StringValueSlice(expandFsxAliasValues(filesystem.WindowsConfiguration.Aliases))); err != nil { + return fmt.Errorf("error setting aliases: %s", err) + } + if err := d.Set("network_interface_ids", aws.StringValueSlice(filesystem.NetworkInterfaceIds)); err != nil { return fmt.Errorf("error setting network_interface_ids: %w", err) } @@ -493,6 +521,83 @@ func resourceAwsFsxWindowsFileSystemDelete(d *schema.ResourceData, meta interfac return nil } +func expandFsxAliasValues(aliases []*fsx.Alias) []*string { + var alternateDNSNames []*string + + for i := 0; i < len(aliases); i++ { + alternateDNSNames[i] = aliases[i].Name + } + + return alternateDNSNames +} + +func updateFsxAliases(conn *fsx.FSx, identifier string, oldAliases []*fsx.Alias, newAliases []*fsx.Alias) error { + oldAliasValues := expandFsxAliasValues(oldAliases) + newAliasValues := expandFsxAliasValues(newAliases) + + var removedAliases []*string + + for _, oldAliasValue := range oldAliasValues { + exists := false + + for _, newAliasValue := range newAliasValues { + if newAliasValue == oldAliasValue { + exists = true + break + } + } + + if !exists { + removedAliases = append(removedAliases, oldAliasValue) + } + } + + if len(removedAliases) > 0 { + input := &fsx.DisassociateFileSystemAliasesInput{ + FileSystemId: aws.String(identifier), + Aliases: removedAliases, + } + + _, err := conn.DisassociateFileSystemAliases(input) + + if err != nil { + return fmt.Errorf("error disassociating aliases from FSx file system (%s): %w", identifier, err) + } + } + + var addedAliases []*string + + for _, newAliasValue := range newAliasValues { + exists := false + + for _, oldAliasValue := range oldAliasValues { + if oldAliasValue == newAliasValue { + exists = true + break + } + } + + if !exists { + addedAliases = append(addedAliases, newAliasValue) + } + } + + if len(addedAliases) > 0 { + input := &fsx.AssociateFileSystemAliasesInput{ + FileSystemId: aws.String(identifier), + Aliases: addedAliases, + } + + _, err := conn.AssociateFileSystemAliases(input) + + if err != nil { + return fmt.Errorf("error associating aliases to FSx file system (%s): %w", identifier, err) + } + } + + return nil +} + func expandFsxSelfManagedActiveDirectoryConfigurationCreate(l []interface{}) *fsx.SelfManagedActiveDirectoryConfiguration { if len(l) == 0 || l[0] == nil { return nil From d9b8d0715718f461a94d692881dce673ec36c9d7 Mon Sep 17 00:00:00 2001 From: Jeremy Ciak Date: Wed, 9 Dec 2020 22:37:29 -0500 Subject: [PATCH 0919/1208] Adding tests to account for the new support for aliases --- ...source_aws_fsx_windows_file_system_test.go | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/aws/resource_aws_fsx_windows_file_system_test.go b/aws/resource_aws_fsx_windows_file_system_test.go index 20b4b679c8eb..9feae003698f 100644 --- a/aws/resource_aws_fsx_windows_file_system_test.go +++ b/aws/resource_aws_fsx_windows_file_system_test.go @@ -85,6 +85,7 @@ func TestAccAWSFsxWindowsFileSystem_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "fsx", regexp.MustCompile(`file-system/fs-.+`)), + resource.TestCheckResourceAttr(resourceName, "aliases.#", "0"), resource.TestCheckResourceAttr(resourceName, "automatic_backup_retention_days", "7"), resource.TestCheckResourceAttr(resourceName, "copy_tags_to_backups", "false"), resource.TestMatchResourceAttr(resourceName, "daily_automatic_backup_start_time", regexp.MustCompile(`^\d\d:\d\d$`)), @@ -140,6 +141,7 @@ func TestAccAWSFsxWindowsFileSystem_singleAz2(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "fsx", regexp.MustCompile(`file-system/fs-.+`)), + resource.TestCheckResourceAttr(resourceName, "aliases.#", "0"), resource.TestCheckResourceAttr(resourceName, "automatic_backup_retention_days", "7"), resource.TestCheckResourceAttr(resourceName, "copy_tags_to_backups", "false"), resource.TestMatchResourceAttr(resourceName, "daily_automatic_backup_start_time", regexp.MustCompile(`^\d\d:\d\d$`)), @@ -219,6 +221,7 @@ func TestAccAWSFsxWindowsFileSystem_multiAz(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "fsx", regexp.MustCompile(`file-system/fs-.+`)), + resource.TestCheckResourceAttr(resourceName, "aliases.#", "0"), resource.TestCheckResourceAttr(resourceName, "automatic_backup_retention_days", "7"), resource.TestCheckResourceAttr(resourceName, "copy_tags_to_backups", "false"), resource.TestMatchResourceAttr(resourceName, "daily_automatic_backup_start_time", regexp.MustCompile(`^\d\d:\d\d$`)), @@ -273,6 +276,55 @@ func TestAccAWSFsxWindowsFileSystem_disappears(t *testing.T) { }) } +func TestAccAWSFsxWindowsFileSystem_Aliases(t *testing.T) { + var filesystem1, filesystem2, filesystem3 fsx.FileSystem + resourceName := "aws_fsx_windows_file_system.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(fsx.EndpointsID, t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckFsxWindowsFileSystemDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsFsxWindowsFileSystemConfigAliases1("filesystem1.domain.name.com"), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem1), + resource.TestCheckResourceAttr(resourceName, "aliases.#", "1"), + resource.TestCheckResourceAttr(resourceName, "aliases.0", "filesystem1.domain.name.com"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "security_group_ids", + "skip_final_backup", + }, + }, + { + Config: testAccAwsFsxWindowsFileSystemConfigAliases2("filesystem1.domain.name.com", "filesystem2.domain.name.com"), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem2), + testAccCheckFsxWindowsFileSystemNotRecreated(&filesystem1, &filesystem2), + resource.TestCheckResourceAttr(resourceName, "aliases.#", "2"), + resource.TestCheckResourceAttr(resourceName, "aliases.0", "filesystem1.domain.name.com"), + resource.TestCheckResourceAttr(resourceName, "aliases.1", "filesystem2.domain.name.com"), + ), + }, + { + Config: testAccAwsFsxWindowsFileSystemConfigAliases1("filesystem2.domain.name.com"), + Check: resource.ComposeTestCheckFunc( + testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem3), + testAccCheckFsxWindowsFileSystemNotRecreated(&filesystem2, &filesystem3), + resource.TestCheckResourceAttr(resourceName, "aliases.#", "1"), + resource.TestCheckResourceAttr(resourceName, "aliases.0", "filesystem2.domain.name.com"), + ), + }, + }, + }) +} + func TestAccAWSFsxWindowsFileSystem_AutomaticBackupRetentionDays(t *testing.T) { var filesystem1, filesystem2, filesystem3 fsx.FileSystem resourceName := "aws_fsx_windows_file_system.test" @@ -861,6 +913,39 @@ resource "aws_directory_service_directory" "test" { ` } +func testAccAwsFsxWindowsFileSystemConfigAliases1(alias1 string) string { + return testAccAwsFsxWindowsFileSystemConfigBase() + fmt.Sprintf(` +resource "aws_fsx_windows_file_system" "test" { + active_directory_id = aws_directory_service_directory.test.id + skip_final_backup = true + storage_capacity = 32 + subnet_ids = [aws_subnet.test1.id] + throughput_capacity = 8 + + aliases = [ + %[1]q + ] +} +`, alias1) +} + +func testAccAwsFsxWindowsFileSystemConfigAliases2(alias1, alias2 string) string { + return testAccAwsFsxWindowsFileSystemConfigBase() + fmt.Sprintf(` +resource "aws_fsx_windows_file_system" "test" { + active_directory_id = aws_directory_service_directory.test.id + skip_final_backup = true + storage_capacity = 32 + subnet_ids = [aws_subnet.test1.id] + throughput_capacity = 8 + + aliases = [ + %[1]q + %[2]q + ] +} +`, alias1, alias2) +} + func testAccAwsFsxWindowsFileSystemConfigAutomaticBackupRetentionDays(automaticBackupRetentionDays int) string { return testAccAwsFsxWindowsFileSystemConfigBase() + fmt.Sprintf(` resource "aws_fsx_windows_file_system" "test" { From 43d31c78ff1fa962d5f08c878af2efe511d60086 Mon Sep 17 00:00:00 2001 From: Jeremy Ciak Date: Wed, 9 Dec 2020 22:37:45 -0500 Subject: [PATCH 0920/1208] Updating tools --- tools/go.mod | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/go.mod b/tools/go.mod index 02ed3cf722ac..f6e63fbb44f7 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -5,12 +5,19 @@ go 1.15 require ( github.com/bflad/tfproviderdocs v0.9.1 github.com/client9/misspell v0.3.4 +<<<<<<< HEAD github.com/golangci/golangci-lint v1.39.0 github.com/hashicorp/go-changelog v0.0.0-20201005170154-56335215ce3a github.com/hashicorp/go-getter v1.5.2 // indirect github.com/katbyte/terrafmt v0.3.0 github.com/pavius/impi v0.0.3 github.com/terraform-linters/tflint v0.28.1 +======= + github.com/golangci/golangci-lint v1.33.0 + github.com/katbyte/terrafmt v0.2.1-0.20200913185704-5ff4421407b4 + github.com/pavius/impi v0.0.3 // indirect + github.com/terraform-linters/tflint v0.20.3 +>>>>>>> 9c419a56f (Updating tools) ) replace github.com/katbyte/terrafmt => github.com/gdavison/terrafmt v0.3.1-0.20210204054728-84242796be99 From 3394f1479e61dbf2074126078058fba2678f6db0 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Thu, 1 Jul 2021 20:58:52 +0300 Subject: [PATCH 0921/1208] revert --- tools/go.mod | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tools/go.mod b/tools/go.mod index f6e63fbb44f7..02ed3cf722ac 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -5,19 +5,12 @@ go 1.15 require ( github.com/bflad/tfproviderdocs v0.9.1 github.com/client9/misspell v0.3.4 -<<<<<<< HEAD github.com/golangci/golangci-lint v1.39.0 github.com/hashicorp/go-changelog v0.0.0-20201005170154-56335215ce3a github.com/hashicorp/go-getter v1.5.2 // indirect github.com/katbyte/terrafmt v0.3.0 github.com/pavius/impi v0.0.3 github.com/terraform-linters/tflint v0.28.1 -======= - github.com/golangci/golangci-lint v1.33.0 - github.com/katbyte/terrafmt v0.2.1-0.20200913185704-5ff4421407b4 - github.com/pavius/impi v0.0.3 // indirect - github.com/terraform-linters/tflint v0.20.3 ->>>>>>> 9c419a56f (Updating tools) ) replace github.com/katbyte/terrafmt => github.com/gdavison/terrafmt v0.3.1-0.20210204054728-84242796be99 From 8fd8ce797e6c2c76fce26f2390cea326e149dde1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Jul 2021 06:11:49 +0000 Subject: [PATCH 0922/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.68 to 1.38.71. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.68...v1.38.71) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../github.com/aws/aws-sdk-go/aws/endpoints/defaults.go | 3 +++ .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index e5c3fcf0a8ec..a1f0079246c0 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.68 + github.com/aws/aws-sdk-go v1.38.71 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 744b783008c1..54c82c3d98e1 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -70,8 +70,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.68 h1:aOG8geU4SohNp659eKBHRBgbqSrZ6jNZlfimIuJAwL8= -github.com/aws/aws-sdk-go v1.38.68/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.71 h1:aWhtgoOiDhBCfaAj9XbxzcyvjEAKovbtv7d5mCVBZXw= +github.com/aws/aws-sdk-go v1.38.71/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index 887c21dcb1ca..27797a72e982 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -982,6 +982,7 @@ var awsPartition = partition{ "ap-east-1": endpoint{}, "ap-northeast-1": endpoint{}, "ap-northeast-2": endpoint{}, + "ap-northeast-3": endpoint{}, "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, @@ -3047,6 +3048,7 @@ var awsPartition = partition{ "ap-east-1": endpoint{}, "ap-northeast-1": endpoint{}, "ap-northeast-2": endpoint{}, + "ap-northeast-3": endpoint{}, "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, @@ -6737,6 +6739,7 @@ var awsPartition = partition{ "ap-east-1": endpoint{}, "ap-northeast-1": endpoint{}, "ap-northeast-2": endpoint{}, + "ap-northeast-3": endpoint{}, "ap-south-1": endpoint{}, "ap-southeast-1": endpoint{}, "ap-southeast-2": endpoint{}, diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index db6522049807..95a41a03b2b6 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.68" +const SDKVersion = "1.38.71" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 656e13681f31..76a11a4180fc 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.68 +# github.com/aws/aws-sdk-go v1.38.71 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From b86fb6ce10dd8fcf52672fb5ef56b2a7c3a64a5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Jul 2021 06:12:46 +0000 Subject: [PATCH 0923/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.68 to 1.38.71 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.68 to 1.38.71. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.68...v1.38.71) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0a0a95874679..5a3199e20f34 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect - github.com/aws/aws-sdk-go v1.38.68 + github.com/aws/aws-sdk-go v1.38.71 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index e9f95cdd37d9..64815f1736ec 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.68 h1:aOG8geU4SohNp659eKBHRBgbqSrZ6jNZlfimIuJAwL8= -github.com/aws/aws-sdk-go v1.38.68/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.38.71 h1:aWhtgoOiDhBCfaAj9XbxzcyvjEAKovbtv7d5mCVBZXw= +github.com/aws/aws-sdk-go v1.38.71/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From c6345fab946f2d0cfa957dc1ec30080f51e59124 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 2 Jul 2021 13:40:24 +0300 Subject: [PATCH 0924/1208] refactor PR --- aws/fsx.go | 72 ++++++++++ aws/resource_aws_fsx_windows_file_system.go | 130 ++++++++++-------- ...source_aws_fsx_windows_file_system_test.go | 30 ++-- 3 files changed, 161 insertions(+), 71 deletions(-) diff --git a/aws/fsx.go b/aws/fsx.go index 73afe902a41d..faf6dcce2e8f 100644 --- a/aws/fsx.go +++ b/aws/fsx.go @@ -8,6 +8,11 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) +const ( + fsxWindowsFileSystemAliasAvailable = 10 * time.Minute + fsxWindowsFileSystemAliasDeleted = 10 * time.Minute +) + func describeFsxFileSystem(conn *fsx.FSx, id string) (*fsx.FileSystem, error) { input := &fsx.DescribeFileSystemsInput{ FileSystemIds: []*string{aws.String(id)}, @@ -48,6 +53,45 @@ func refreshFsxFileSystemLifecycle(conn *fsx.FSx, id string) resource.StateRefre } } +func refreshFsxWindowsFileSystemAliasLifecycle(conn *fsx.FSx, id, aliasName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + filesystem, err := describeFsxFileSystem(conn, id) + + if isAWSErr(err, fsx.ErrCodeFileSystemNotFound, "") { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + if filesystem == nil { + return nil, "", nil + } + + if filesystem.WindowsConfiguration == nil { + return nil, "", nil + } + + aliases := filesystem.WindowsConfiguration.Aliases + if aliases == nil { + return nil, "", nil + } + + for _, alias := range aliases { + if alias == nil { + continue + } + + if aws.StringValue(alias.Name) == aliasName { + return filesystem, aws.StringValue(alias.Lifecycle), nil + } + } + + return filesystem, "", nil + } +} + func refreshFsxFileSystemAdministrativeActionsStatusFileSystemUpdate(conn *fsx.FSx, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { filesystem, err := describeFsxFileSystem(conn, id) @@ -78,6 +122,34 @@ func refreshFsxFileSystemAdministrativeActionsStatusFileSystemUpdate(conn *fsx.F } } +func waitForFsxWindowsFileSystemAliasAvailable(conn *fsx.FSx, id, alias string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{fsx.AliasLifecycleCreating}, + Target: []string{fsx.AliasLifecycleAvailable}, + Refresh: refreshFsxWindowsFileSystemAliasLifecycle(conn, id, alias), + Timeout: fsxWindowsFileSystemAliasAvailable, + Delay: 30 * time.Second, + } + + _, err := stateConf.WaitForState() + + return err +} + +func waitForFsxWindowsFileSystemAliasDeleted(conn *fsx.FSx, id, alias string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{fsx.AliasLifecycleAvailable, fsx.AliasLifecycleDeleting}, + Target: []string{""}, + Refresh: refreshFsxWindowsFileSystemAliasLifecycle(conn, id, alias), + Timeout: fsxWindowsFileSystemAliasDeleted, + Delay: 30 * time.Second, + } + + _, err := stateConf.WaitForState() + + return err +} + func waitForFsxFileSystemCreation(conn *fsx.FSx, id string, timeout time.Duration) error { stateConf := &resource.StateChangeConf{ Pending: []string{fsx.FileSystemLifecycleCreating}, diff --git a/aws/resource_aws_fsx_windows_file_system.go b/aws/resource_aws_fsx_windows_file_system.go index 8f1f11ca8a7d..ced17dc4c90f 100644 --- a/aws/resource_aws_fsx_windows_file_system.go +++ b/aws/resource_aws_fsx_windows_file_system.go @@ -51,7 +51,7 @@ func resourceAwsFsxWindowsFileSystem() *schema.Resource { Type: schema.TypeString, ValidateFunc: validation.All( validation.StringLenBetween(4, 253), - validation.StringMatch(regexp.MustCompile(`^[A-Za-z0-9]([.][A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])+$`), "must be in the fqdn format hostname.domain"), + // validation.StringMatch(regexp.MustCompile(`^[A-Za-z0-9]([.][A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])+$`), "must be in the fqdn format hostname.domain"), ), }, }, @@ -348,21 +348,21 @@ func resourceAwsFsxWindowsFileSystemUpdate(d *schema.ResourceData, meta interfac } } - if d.HasChangeExcept("tags_all") { + if d.HasChange("aliases") { + o, n := d.GetChange("aliases") + + if err := updateFsxAliases(conn, d.Id(), o.(*schema.Set), n.(*schema.Set)); err != nil { + return fmt.Errorf("error updating FSx Windows File System (%s) aliases: %w", d.Id(), err) + } + } + + if d.HasChangesExcept("tags_all", "aliases") { input := &fsx.UpdateFileSystemInput{ ClientRequestToken: aws.String(resource.UniqueId()), FileSystemId: aws.String(d.Id()), WindowsConfiguration: &fsx.UpdateFileSystemWindowsConfiguration{}, } - if d.HasChange("aliases") { - o, n := d.GetChange("aliases") - - if err := updateFsxAliases(conn, d.Get("arn").(string), o.([]*fsx.Alias), n.([]*fsx.Alias)); err != nil { - return fmt.Errorf("error updating FSx Windows File System (%s) aliases: %s", d.Get("arn").(string), err) - } - } - if d.HasChange("automatic_backup_retention_days") { input.WindowsConfiguration.AutomaticBackupRetentionDays = aws.Int64(int64(d.Get("automatic_backup_retention_days").(int))) } @@ -524,76 +524,94 @@ func resourceAwsFsxWindowsFileSystemDelete(d *schema.ResourceData, meta interfac func expandFsxAliasValues(aliases []*fsx.Alias) []*string { var alternateDNSNames []*string - for i := 0; i < len(aliases); i++ { - alternateDNSNames[i] = aliases[i].Name + for _, alias := range aliases { + aName := alias.Name + alternateDNSNames = append(alternateDNSNames, aName) } return alternateDNSNames } -func updateFsxAliases(conn *fsx.FSx, identifier string, oldAliases []*fsx.Alias, newAliases []*fsx.Alias) error { - oldAliasValues := expandFsxAliasValues(oldAliases) - newAliasValues := expandFsxAliasValues(newAliases) +func updateFsxAliases(conn *fsx.FSx, identifier string, newSet *schema.Set, oldSet *schema.Set) error { + // oldAliasValues := expandFsxAliasValues(oldAliases) + // newAliasValues := expandFsxAliasValues(newAliases) - var removedAliases []*string + // var removedAliases []*string - for _, oldAliasValue := range oldAliasValues { - exists := false + // for _, oldAliasValue := range oldAliasValues { + // exists := false - for _, newAliasValue := range newAliasValues { - if newAliasValue == oldAliasValue { - exists = true - break - } - } + // for _, newAliasValue := range newAliasValues { + // if newAliasValue == oldAliasValue { + // exists = true + // break + // } + // } - if !exists { - removedAliases = append(removedAliases, oldAliasValue) - } - } + // if !exists { + // removedAliases = append(removedAliases, oldAliasValue) + // } + // } - if len(removedAliases) > 0 { - input := &fsx.DisassociateFileSystemAliasesInput{ - FileSystemId: aws.String(identifier), - Aliases: removedAliases, - } + if newSet.Len() > 0 { + if newAliases := newSet.Difference(oldSet); newAliases.Len() > 0 { - _, err := conn.DisassociateFileSystemAliases(input) + input := &fsx.AssociateFileSystemAliasesInput{ + FileSystemId: aws.String(identifier), + Aliases: expandStringSet(newAliases), + } - if err != nil { - return fmt.Errorf("error disassociating aliases from FSx file system (%s): %w", identifier, err) + _, err := conn.AssociateFileSystemAliases(input) + + if err != nil { + return fmt.Errorf("error associating aliases to FSx file system (%s): %w", identifier, err) + } + + for _, alias := range newAliases.List() { + if err := waitForFsxWindowsFileSystemAliasAvailable(conn, identifier, alias.(string)); err != nil { + return fmt.Errorf("Error waiting for FSX Windows filesystem alias (%s) to be available: %w", identifier, err) + } + } } } - var addedAliases []*string + if oldSet.Len() > 0 { + if oldAliases := oldSet.Difference(newSet); oldAliases.Len() > 0 { + input := &fsx.DisassociateFileSystemAliasesInput{ + FileSystemId: aws.String(identifier), + Aliases: expandStringSet(oldAliases), + } - for _, newAliasValue := range newAliasValues { - exists := false + _, err := conn.DisassociateFileSystemAliases(input) - for _, oldAliasValue := range oldAliasValues { - if oldAliasValue == newAliasValue { - exists = true - break + if err != nil { + return fmt.Errorf("error disassociating aliases from FSx file system (%s): %w", identifier, err) } - } - if !exists { - addedAliases = append(addedAliases, newAliasValue) + for _, alias := range oldAliases.List() { + if err := waitForFsxWindowsFileSystemAliasDeleted(conn, identifier, alias.(string)); err != nil { + return fmt.Errorf("Error waiting for FSX Windows filesystem alias (%s) to delete: %w", identifier, err) + } + } } } - if len(addedAliases) > 0 { - input := &fsx.AssociateFileSystemAliasesInput{ - FileSystemId: aws.String(identifier), - Aliases: addedAliases, - } + // var addedAliases []*string - _, err := conn.AssociateFileSystemAliases(input) + // for _, newAliasValue := range newAliasValues { + // exists := false - if err != nil { - return fmt.Errorf("error associating aliases to FSx file system (%s): %w", identifier, err) - } - } + // for _, oldAliasValue := range oldAliasValues { + // if oldAliasValue == newAliasValue { + // exists = true + // break + // } + // } + + // if !exists { + // addedAliases = append(addedAliases, newAliasValue) + // } + // } return nil } diff --git a/aws/resource_aws_fsx_windows_file_system_test.go b/aws/resource_aws_fsx_windows_file_system_test.go index 9feae003698f..44493c61138a 100644 --- a/aws/resource_aws_fsx_windows_file_system_test.go +++ b/aws/resource_aws_fsx_windows_file_system_test.go @@ -276,7 +276,7 @@ func TestAccAWSFsxWindowsFileSystem_disappears(t *testing.T) { }) } -func TestAccAWSFsxWindowsFileSystem_Aliases(t *testing.T) { +func TestAccAWSFsxWindowsFileSystem_aliases(t *testing.T) { var filesystem1, filesystem2, filesystem3 fsx.FileSystem resourceName := "aws_fsx_windows_file_system.test" @@ -286,11 +286,11 @@ func TestAccAWSFsxWindowsFileSystem_Aliases(t *testing.T) { CheckDestroy: testAccCheckFsxWindowsFileSystemDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsFsxWindowsFileSystemConfigAliases1("filesystem1.domain.name.com"), + Config: testAccAwsFsxWindowsFileSystemConfigAliases1("filesystem1.example.com"), Check: resource.ComposeTestCheckFunc( testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem1), resource.TestCheckResourceAttr(resourceName, "aliases.#", "1"), - resource.TestCheckResourceAttr(resourceName, "aliases.0", "filesystem1.domain.name.com"), + resource.TestCheckResourceAttr(resourceName, "aliases.0", "filesystem1.example.com"), ), }, { @@ -303,22 +303,22 @@ func TestAccAWSFsxWindowsFileSystem_Aliases(t *testing.T) { }, }, { - Config: testAccAwsFsxWindowsFileSystemConfigAliases2("filesystem1.domain.name.com", "filesystem2.domain.name.com"), + Config: testAccAwsFsxWindowsFileSystemConfigAliases2("filesystem2.example.com", "filesystem3.example.com"), Check: resource.ComposeTestCheckFunc( testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem2), testAccCheckFsxWindowsFileSystemNotRecreated(&filesystem1, &filesystem2), resource.TestCheckResourceAttr(resourceName, "aliases.#", "2"), - resource.TestCheckResourceAttr(resourceName, "aliases.0", "filesystem1.domain.name.com"), - resource.TestCheckResourceAttr(resourceName, "aliases.1", "filesystem2.domain.name.com"), + resource.TestCheckResourceAttr(resourceName, "aliases.0", "filesystem2.example.com"), + resource.TestCheckResourceAttr(resourceName, "aliases.1", "filesystem3.example.com"), ), }, { - Config: testAccAwsFsxWindowsFileSystemConfigAliases1("filesystem2.domain.name.com"), + Config: testAccAwsFsxWindowsFileSystemConfigAliases1("filesystem3.example.com"), Check: resource.ComposeTestCheckFunc( testAccCheckFsxWindowsFileSystemExists(resourceName, &filesystem3), testAccCheckFsxWindowsFileSystemNotRecreated(&filesystem2, &filesystem3), resource.TestCheckResourceAttr(resourceName, "aliases.#", "1"), - resource.TestCheckResourceAttr(resourceName, "aliases.0", "filesystem2.domain.name.com"), + resource.TestCheckResourceAttr(resourceName, "aliases.0", "filesystem3.example.com"), ), }, }, @@ -914,12 +914,12 @@ resource "aws_directory_service_directory" "test" { } func testAccAwsFsxWindowsFileSystemConfigAliases1(alias1 string) string { - return testAccAwsFsxWindowsFileSystemConfigBase() + fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_fsx_windows_file_system" "test" { - active_directory_id = aws_directory_service_directory.test.id + active_directory_id = "d-92677185a7" skip_final_backup = true storage_capacity = 32 - subnet_ids = [aws_subnet.test1.id] + subnet_ids = ["subnet-060ab259c291fa28c"] throughput_capacity = 8 aliases = [ @@ -930,16 +930,16 @@ resource "aws_fsx_windows_file_system" "test" { } func testAccAwsFsxWindowsFileSystemConfigAliases2(alias1, alias2 string) string { - return testAccAwsFsxWindowsFileSystemConfigBase() + fmt.Sprintf(` + return fmt.Sprintf(` resource "aws_fsx_windows_file_system" "test" { - active_directory_id = aws_directory_service_directory.test.id + active_directory_id = "d-92677185a7" skip_final_backup = true storage_capacity = 32 - subnet_ids = [aws_subnet.test1.id] + subnet_ids = ["subnet-060ab259c291fa28c"] throughput_capacity = 8 aliases = [ - %[1]q + %[1]q, %[2]q ] } From 15fe05ff273c21d5ce4caa8f52c1391c283473f6 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 2 Jul 2021 13:43:30 +0300 Subject: [PATCH 0925/1208] changelog --- .changelog/20054.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/20054.txt diff --git a/.changelog/20054.txt b/.changelog/20054.txt new file mode 100644 index 000000000000..17613fbece00 --- /dev/null +++ b/.changelog/20054.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/fsx_windows_file_system: Add `aliases` argument. +``` From b19fd347424ccb3db1a6a67630e7bc1172f1643e Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 2 Jul 2021 13:46:16 +0300 Subject: [PATCH 0926/1208] docs --- website/docs/r/fsx_windows_file_system.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/fsx_windows_file_system.html.markdown b/website/docs/r/fsx_windows_file_system.html.markdown index 4378b8970412..8498466b8742 100644 --- a/website/docs/r/fsx_windows_file_system.html.markdown +++ b/website/docs/r/fsx_windows_file_system.html.markdown @@ -56,6 +56,7 @@ The following arguments are supported: * `subnet_ids` - (Required) A list of IDs for the subnets that the file system will be accessible from. To specify more than a single subnet set `deployment_type` to `MULTI_AZ_1`. * `throughput_capacity` - (Required) Throughput (megabytes per second) of the file system in power of 2 increments. Minimum of `8` and maximum of `2048`. * `active_directory_id` - (Optional) The ID for an existing Microsoft Active Directory instance that the file system should join when it's created. Cannot be specified with `self_managed_active_directory`. +* `aliases` - (Optional) An array DNS alias names that you want to associate with the Amazon FSx file system. For more information, see [Working with DNS Aliases](https://docs.aws.amazon.com/fsx/latest/WindowsGuide/managing-dns-aliases.html) * `automatic_backup_retention_days` - (Optional) The number of days to retain automatic backups. Minimum of `0` and maximum of `90`. Defaults to `7`. Set to `0` to disable. * `copy_tags_to_backups` - (Optional) A boolean flag indicating whether tags on the file system should be copied to backups. Defaults to `false`. * `daily_automatic_backup_start_time` - (Optional) The preferred time (in `HH:MM` format) to take daily automatic backups, in the UTC time zone. From 321819037b8db314d4dae84e4ee4c5d6b101cd64 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 2 Jul 2021 13:47:56 +0300 Subject: [PATCH 0927/1208] fmt --- aws/resource_aws_fsx_windows_file_system_test.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_fsx_windows_file_system_test.go b/aws/resource_aws_fsx_windows_file_system_test.go index 44493c61138a..87f3b1fac649 100644 --- a/aws/resource_aws_fsx_windows_file_system_test.go +++ b/aws/resource_aws_fsx_windows_file_system_test.go @@ -922,9 +922,7 @@ resource "aws_fsx_windows_file_system" "test" { subnet_ids = ["subnet-060ab259c291fa28c"] throughput_capacity = 8 - aliases = [ - %[1]q - ] + aliases = [%[1]q] } `, alias1) } @@ -938,10 +936,7 @@ resource "aws_fsx_windows_file_system" "test" { subnet_ids = ["subnet-060ab259c291fa28c"] throughput_capacity = 8 - aliases = [ - %[1]q, - %[2]q - ] + aliases = [%[1]q, %[2]q] } `, alias1, alias2) } From d3ecd65b58533856e88f2b222184ffed762af20c Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 2 Jul 2021 14:08:20 +0300 Subject: [PATCH 0928/1208] fix diff --- aws/resource_aws_fsx_windows_file_system.go | 43 ++----------------- ...source_aws_fsx_windows_file_system_test.go | 1 + 2 files changed, 4 insertions(+), 40 deletions(-) diff --git a/aws/resource_aws_fsx_windows_file_system.go b/aws/resource_aws_fsx_windows_file_system.go index ced17dc4c90f..eb7eda3011f5 100644 --- a/aws/resource_aws_fsx_windows_file_system.go +++ b/aws/resource_aws_fsx_windows_file_system.go @@ -532,27 +532,7 @@ func expandFsxAliasValues(aliases []*fsx.Alias) []*string { return alternateDNSNames } -func updateFsxAliases(conn *fsx.FSx, identifier string, newSet *schema.Set, oldSet *schema.Set) error { - // oldAliasValues := expandFsxAliasValues(oldAliases) - // newAliasValues := expandFsxAliasValues(newAliases) - - // var removedAliases []*string - - // for _, oldAliasValue := range oldAliasValues { - // exists := false - - // for _, newAliasValue := range newAliasValues { - // if newAliasValue == oldAliasValue { - // exists = true - // break - // } - // } - - // if !exists { - // removedAliases = append(removedAliases, oldAliasValue) - // } - // } - +func updateFsxAliases(conn *fsx.FSx, identifier string, oldSet *schema.Set, newSet *schema.Set) error { if newSet.Len() > 0 { if newAliases := newSet.Difference(oldSet); newAliases.Len() > 0 { @@ -569,7 +549,7 @@ func updateFsxAliases(conn *fsx.FSx, identifier string, newSet *schema.Set, oldS for _, alias := range newAliases.List() { if err := waitForFsxWindowsFileSystemAliasAvailable(conn, identifier, alias.(string)); err != nil { - return fmt.Errorf("Error waiting for FSX Windows filesystem alias (%s) to be available: %w", identifier, err) + return fmt.Errorf("Error waiting for FSX Windows filesystem (%s) alias (%s) to be available: %w", identifier, alias.(string), err) } } } @@ -590,29 +570,12 @@ func updateFsxAliases(conn *fsx.FSx, identifier string, newSet *schema.Set, oldS for _, alias := range oldAliases.List() { if err := waitForFsxWindowsFileSystemAliasDeleted(conn, identifier, alias.(string)); err != nil { - return fmt.Errorf("Error waiting for FSX Windows filesystem alias (%s) to delete: %w", identifier, err) + return fmt.Errorf("Error waiting for FSX Windows filesystem (%s) alias (%s) to delete: %w", identifier, alias.(string), err) } } } } - // var addedAliases []*string - - // for _, newAliasValue := range newAliasValues { - // exists := false - - // for _, oldAliasValue := range oldAliasValues { - // if oldAliasValue == newAliasValue { - // exists = true - // break - // } - // } - - // if !exists { - // addedAliases = append(addedAliases, newAliasValue) - // } - // } - return nil } diff --git a/aws/resource_aws_fsx_windows_file_system_test.go b/aws/resource_aws_fsx_windows_file_system_test.go index 87f3b1fac649..99e8bbd98636 100644 --- a/aws/resource_aws_fsx_windows_file_system_test.go +++ b/aws/resource_aws_fsx_windows_file_system_test.go @@ -282,6 +282,7 @@ func TestAccAWSFsxWindowsFileSystem_aliases(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(fsx.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, fsx.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckFsxWindowsFileSystemDestroy, Steps: []resource.TestStep{ From 1d20f54c376f026aa7f44661790ec06807ea5d98 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 2 Jul 2021 15:16:34 +0300 Subject: [PATCH 0929/1208] use admin action waiter --- aws/fsx.go | 80 ++------------------- aws/resource_aws_fsx_windows_file_system.go | 18 ++--- 2 files changed, 11 insertions(+), 87 deletions(-) diff --git a/aws/fsx.go b/aws/fsx.go index faf6dcce2e8f..7aa5d9896982 100644 --- a/aws/fsx.go +++ b/aws/fsx.go @@ -8,11 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -const ( - fsxWindowsFileSystemAliasAvailable = 10 * time.Minute - fsxWindowsFileSystemAliasDeleted = 10 * time.Minute -) - func describeFsxFileSystem(conn *fsx.FSx, id string) (*fsx.FileSystem, error) { input := &fsx.DescribeFileSystemsInput{ FileSystemIds: []*string{aws.String(id)}, @@ -53,46 +48,7 @@ func refreshFsxFileSystemLifecycle(conn *fsx.FSx, id string) resource.StateRefre } } -func refreshFsxWindowsFileSystemAliasLifecycle(conn *fsx.FSx, id, aliasName string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - filesystem, err := describeFsxFileSystem(conn, id) - - if isAWSErr(err, fsx.ErrCodeFileSystemNotFound, "") { - return nil, "", nil - } - - if err != nil { - return nil, "", err - } - - if filesystem == nil { - return nil, "", nil - } - - if filesystem.WindowsConfiguration == nil { - return nil, "", nil - } - - aliases := filesystem.WindowsConfiguration.Aliases - if aliases == nil { - return nil, "", nil - } - - for _, alias := range aliases { - if alias == nil { - continue - } - - if aws.StringValue(alias.Name) == aliasName { - return filesystem, aws.StringValue(alias.Lifecycle), nil - } - } - - return filesystem, "", nil - } -} - -func refreshFsxFileSystemAdministrativeActionsStatusFileSystemUpdate(conn *fsx.FSx, id string) resource.StateRefreshFunc { +func refreshFsxFileSystemAdministrativeActionsStatusFileSystemUpdate(conn *fsx.FSx, id, action string) resource.StateRefreshFunc { return func() (interface{}, string, error) { filesystem, err := describeFsxFileSystem(conn, id) @@ -113,7 +69,7 @@ func refreshFsxFileSystemAdministrativeActionsStatusFileSystemUpdate(conn *fsx.F continue } - if aws.StringValue(administrativeAction.AdministrativeActionType) == fsx.AdministrativeActionTypeFileSystemUpdate { + if aws.StringValue(administrativeAction.AdministrativeActionType) == action { return filesystem, aws.StringValue(administrativeAction.Status), nil } } @@ -122,34 +78,6 @@ func refreshFsxFileSystemAdministrativeActionsStatusFileSystemUpdate(conn *fsx.F } } -func waitForFsxWindowsFileSystemAliasAvailable(conn *fsx.FSx, id, alias string) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{fsx.AliasLifecycleCreating}, - Target: []string{fsx.AliasLifecycleAvailable}, - Refresh: refreshFsxWindowsFileSystemAliasLifecycle(conn, id, alias), - Timeout: fsxWindowsFileSystemAliasAvailable, - Delay: 30 * time.Second, - } - - _, err := stateConf.WaitForState() - - return err -} - -func waitForFsxWindowsFileSystemAliasDeleted(conn *fsx.FSx, id, alias string) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{fsx.AliasLifecycleAvailable, fsx.AliasLifecycleDeleting}, - Target: []string{""}, - Refresh: refreshFsxWindowsFileSystemAliasLifecycle(conn, id, alias), - Timeout: fsxWindowsFileSystemAliasDeleted, - Delay: 30 * time.Second, - } - - _, err := stateConf.WaitForState() - - return err -} - func waitForFsxFileSystemCreation(conn *fsx.FSx, id string, timeout time.Duration) error { stateConf := &resource.StateChangeConf{ Pending: []string{fsx.FileSystemLifecycleCreating}, @@ -192,7 +120,7 @@ func waitForFsxFileSystemUpdate(conn *fsx.FSx, id string, timeout time.Duration) return err } -func waitForFsxFileSystemUpdateAdministrativeActionsStatusFileSystemUpdate(conn *fsx.FSx, id string, timeout time.Duration) error { +func waitForFsxFileSystemUpdateAdministrativeActionsStatusFileSystemUpdate(conn *fsx.FSx, id, action string, timeout time.Duration) error { stateConf := &resource.StateChangeConf{ Pending: []string{ fsx.StatusInProgress, @@ -202,7 +130,7 @@ func waitForFsxFileSystemUpdateAdministrativeActionsStatusFileSystemUpdate(conn fsx.StatusCompleted, fsx.StatusUpdatedOptimizing, }, - Refresh: refreshFsxFileSystemAdministrativeActionsStatusFileSystemUpdate(conn, id), + Refresh: refreshFsxFileSystemAdministrativeActionsStatusFileSystemUpdate(conn, id, action), Timeout: timeout, Delay: 30 * time.Second, } diff --git a/aws/resource_aws_fsx_windows_file_system.go b/aws/resource_aws_fsx_windows_file_system.go index eb7eda3011f5..fb9df280df40 100644 --- a/aws/resource_aws_fsx_windows_file_system.go +++ b/aws/resource_aws_fsx_windows_file_system.go @@ -351,7 +351,7 @@ func resourceAwsFsxWindowsFileSystemUpdate(d *schema.ResourceData, meta interfac if d.HasChange("aliases") { o, n := d.GetChange("aliases") - if err := updateFsxAliases(conn, d.Id(), o.(*schema.Set), n.(*schema.Set)); err != nil { + if err := updateFsxAliases(conn, d.Id(), o.(*schema.Set), n.(*schema.Set), d.Timeout(schema.TimeoutUpdate)); err != nil { return fmt.Errorf("error updating FSx Windows File System (%s) aliases: %w", d.Id(), err) } } @@ -397,7 +397,7 @@ func resourceAwsFsxWindowsFileSystemUpdate(d *schema.ResourceData, meta interfac return fmt.Errorf("error updating FSx Windows File System (%s): %w", d.Id(), err) } - if err := waitForFsxFileSystemUpdateAdministrativeActionsStatusFileSystemUpdate(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + if err := waitForFsxFileSystemUpdateAdministrativeActionsStatusFileSystemUpdate(conn, d.Id(), fsx.AdministrativeActionTypeFileSystemUpdate, d.Timeout(schema.TimeoutUpdate)); err != nil { return fmt.Errorf("error waiting for FSx Windows File System (%s) update: %w", d.Id(), err) } } @@ -532,7 +532,7 @@ func expandFsxAliasValues(aliases []*fsx.Alias) []*string { return alternateDNSNames } -func updateFsxAliases(conn *fsx.FSx, identifier string, oldSet *schema.Set, newSet *schema.Set) error { +func updateFsxAliases(conn *fsx.FSx, identifier string, oldSet *schema.Set, newSet *schema.Set, timeout time.Duration) error { if newSet.Len() > 0 { if newAliases := newSet.Difference(oldSet); newAliases.Len() > 0 { @@ -547,10 +547,8 @@ func updateFsxAliases(conn *fsx.FSx, identifier string, oldSet *schema.Set, newS return fmt.Errorf("error associating aliases to FSx file system (%s): %w", identifier, err) } - for _, alias := range newAliases.List() { - if err := waitForFsxWindowsFileSystemAliasAvailable(conn, identifier, alias.(string)); err != nil { - return fmt.Errorf("Error waiting for FSX Windows filesystem (%s) alias (%s) to be available: %w", identifier, alias.(string), err) - } + if err := waitForFsxFileSystemUpdateAdministrativeActionsStatusFileSystemUpdate(conn, identifier, fsx.AdministrativeActionTypeFileSystemAliasAssociation, timeout); err != nil { + return fmt.Errorf("Error waiting for FSX Windows filesystem (%s) alias to be associated: %w", identifier, err) } } } @@ -568,10 +566,8 @@ func updateFsxAliases(conn *fsx.FSx, identifier string, oldSet *schema.Set, newS return fmt.Errorf("error disassociating aliases from FSx file system (%s): %w", identifier, err) } - for _, alias := range oldAliases.List() { - if err := waitForFsxWindowsFileSystemAliasDeleted(conn, identifier, alias.(string)); err != nil { - return fmt.Errorf("Error waiting for FSX Windows filesystem (%s) alias (%s) to delete: %w", identifier, alias.(string), err) - } + if err := waitForFsxFileSystemUpdateAdministrativeActionsStatusFileSystemUpdate(conn, identifier, fsx.AdministrativeActionTypeFileSystemAliasDisassociation, timeout); err != nil { + return fmt.Errorf("Error waiting for FSX Windows filesystem (%s) alias to disassociated: %w", identifier, err) } } } From 8ff6dfe816cf526d722af6668bd825e03a66d1b5 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 2 Jul 2021 15:17:58 +0300 Subject: [PATCH 0930/1208] revert local changes --- aws/resource_aws_fsx_windows_file_system_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_fsx_windows_file_system_test.go b/aws/resource_aws_fsx_windows_file_system_test.go index 99e8bbd98636..a6d83d327a72 100644 --- a/aws/resource_aws_fsx_windows_file_system_test.go +++ b/aws/resource_aws_fsx_windows_file_system_test.go @@ -915,12 +915,12 @@ resource "aws_directory_service_directory" "test" { } func testAccAwsFsxWindowsFileSystemConfigAliases1(alias1 string) string { - return fmt.Sprintf(` + return testAccAwsFsxWindowsFileSystemConfigBase() + fmt.Sprintf(` resource "aws_fsx_windows_file_system" "test" { - active_directory_id = "d-92677185a7" + active_directory_id = aws_directory_service_directory.test.id skip_final_backup = true storage_capacity = 32 - subnet_ids = ["subnet-060ab259c291fa28c"] + subnet_ids = [aws_subnet.test1.id] throughput_capacity = 8 aliases = [%[1]q] @@ -929,12 +929,12 @@ resource "aws_fsx_windows_file_system" "test" { } func testAccAwsFsxWindowsFileSystemConfigAliases2(alias1, alias2 string) string { - return fmt.Sprintf(` + return testAccAwsFsxWindowsFileSystemConfigBase() + fmt.Sprintf(` resource "aws_fsx_windows_file_system" "test" { - active_directory_id = "d-92677185a7" + active_directory_id = aws_directory_service_directory.test.id skip_final_backup = true storage_capacity = 32 - subnet_ids = ["subnet-060ab259c291fa28c"] + subnet_ids = [aws_subnet.test1.id] throughput_capacity = 8 aliases = [%[1]q, %[2]q] From e8dc87fa890058af2adbad3267f3caf25f3eafe1 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 2 Jul 2021 15:25:46 +0300 Subject: [PATCH 0931/1208] fmt --- aws/resource_aws_fsx_windows_file_system_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_fsx_windows_file_system_test.go b/aws/resource_aws_fsx_windows_file_system_test.go index a6d83d327a72..f64f2852c64b 100644 --- a/aws/resource_aws_fsx_windows_file_system_test.go +++ b/aws/resource_aws_fsx_windows_file_system_test.go @@ -917,7 +917,7 @@ resource "aws_directory_service_directory" "test" { func testAccAwsFsxWindowsFileSystemConfigAliases1(alias1 string) string { return testAccAwsFsxWindowsFileSystemConfigBase() + fmt.Sprintf(` resource "aws_fsx_windows_file_system" "test" { - active_directory_id = aws_directory_service_directory.test.id + active_directory_id = aws_directory_service_directory.test.id skip_final_backup = true storage_capacity = 32 subnet_ids = [aws_subnet.test1.id] From 725e40df6a2cbeeaf822f5398057acdc946a105a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Jul 2021 08:53:14 -0400 Subject: [PATCH 0932/1208] r/aws_transfer_server: Correct update to 0 subnet_ids. --- aws/resource_aws_transfer_server.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 162533614f9e..201c2cf3fbb5 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -418,6 +418,11 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e // Prevent the following error: InvalidRequestException: Changing Security Group is not supported input.EndpointDetails.SecurityGroupIds = nil + + // Update to 0 SubnetIds. + if input.EndpointDetails.SubnetIds == nil { + input.EndpointDetails.SubnetIds = []*string{} + } } } From 549d814f47357d45b49f90183b80ce908308a18f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Jul 2021 08:54:00 -0400 Subject: [PATCH 0933/1208] r/aws_transfer_server: Cannot update to 0 security_group_ids (VPC Endpoint always requires at least 1). --- aws/resource_aws_transfer_server_test.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index be2668959b38..1313d31210b4 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -414,20 +414,6 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, - { - Config: testAccAWSTransferServerVpcConfig(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), - resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), - ), - }, }, }) } From fe8cda6d26fd9d73e6d98b7386f4bf708385e316 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Jul 2021 09:40:05 -0400 Subject: [PATCH 0934/1208] r/aws_transfer_server: When updating endpoint_type to VPC, wait for newly provisioned VPC Endpoint to become available. --- aws/resource_aws_transfer_server.go | 41 ++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 201c2cf3fbb5..972412b495ba 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -376,6 +376,18 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e conn := meta.(*AWSClient).transferconn if d.HasChangesExcept("tags", "tags_all") { + var newEndpointTypeVpc bool + var oldEndpointTypeVpc bool + + old, new := d.GetChange("endpoint_type") + + if old, new := old.(string), new.(string); new != old && new == transfer.EndpointTypeVpc { + newEndpointTypeVpc = true + } else if new == old && new == transfer.EndpointTypeVpc { + newEndpointTypeVpc = true + oldEndpointTypeVpc = true + } + var addressAllocationIDs []*string var offlineUpdate bool @@ -388,21 +400,9 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e } if d.HasChange("endpoint_details") { - var newEndpointTypeVpc bool - var oldEndpointTypeVpc bool - if v, ok := d.GetOk("endpoint_details"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.EndpointDetails = expandTransferEndpointDetails(v.([]interface{})[0].(map[string]interface{})) - old, new := d.GetChange("endpoint_type") - - if old, new := old.(string), new.(string); new != old && new == transfer.EndpointTypeVpc { - newEndpointTypeVpc = true - } else if new == old && new == transfer.EndpointTypeVpc { - newEndpointTypeVpc = true - oldEndpointTypeVpc = true - } - if newEndpointTypeVpc && !oldEndpointTypeVpc { // Prevent the following error: InvalidRequestException: Cannot specify AddressAllocationids when updating server to EndpointType: VPC addressAllocationIDs = input.EndpointDetails.AddressAllocationIds @@ -509,6 +509,23 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e return err } + if newEndpointTypeVpc && !oldEndpointTypeVpc { + // Wait for newly provisioned VPC Endpoint to become available. + output, err := finder.ServerByID(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error reading Transfer Server (%s): %w", d.Id(), err) + } + + vpcEndpointID := aws.StringValue(output.EndpointDetails.VpcEndpointId) + + _, err = ec2waiter.VpcEndpointAvailable(meta.(*AWSClient).ec2conn, vpcEndpointID, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("error waiting for Transfer Server (%s) VPC Endpoint (%s) to become available: %w", d.Id(), vpcEndpointID, err) + } + } + // Set any AddressAllocationIds if the server has updated endpoint type to VPC. if len(addressAllocationIDs) > 0 { input := &transfer.UpdateServerInput{ From 7c0c8d049da5ea8b6071bbf53b2be1e1b07ccb08 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Jul 2021 10:12:16 -0400 Subject: [PATCH 0935/1208] Fix rebase merge conflicts. --- .github/workflows/release.yml | 54 ----------------------------------- .goreleaser.yml | 2 +- 2 files changed, 1 insertion(+), 55 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ed1b05a5020..90969c0596bd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,3 @@ -<<<<<<< HEAD name: Post Publish on: release: @@ -53,56 +52,3 @@ jobs: git add CHANGELOG.md git commit -m "Update CHANGELOG.md after ${{ github.event.release.tag_name }}" git push -======= -# This GitHub action can publish assets for release when a tag is created. -# Currently its setup to run on any tag that matches the pattern "v*" (ie. v0.1.0). -# -# This uses an action (paultyng/ghaction-import-gpg) that assumes you set your -# private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `PASSPHRASE` -# secret. If you would rather own your own GPG handling, please fork this action -# or use an alternative one for key handling. -# -# You will need to pass the `--batch` flag to `gpg` in your signing step -# in `goreleaser` to indicate this is being used in a non-interactive mode. -# -name: release -on: - push: - tags: - - 'v*' -jobs: - goreleaser: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Unshallow - run: git fetch --prune --unshallow - - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: 1.14 - - - name: Import GPG key - id: import_gpg - # TODO: move this to HashiCorp namespace or find alternative that is just simple gpg commands - # see https://github.com/hashicorp/terraform-provider-scaffolding/issues/22 - uses: paultyng/ghaction-import-gpg@v2.1.0 - env: - # These secrets will need to be configured for the repository: - GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} - PASSPHRASE: ${{ secrets.PASSPHRASE }} - - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v2 - with: - version: latest - args: release --rm-dist - env: - GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} - # GitHub sets this automatically - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ->>>>>>> 19bf7eb9c (Change) diff --git a/.goreleaser.yml b/.goreleaser.yml index 8d1a78155dd9..fe1eb97fe8c6 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -24,7 +24,7 @@ builds: - goarch: '386' goos: darwin ldflags: - - -s -w -X aws/version.ProviderVersion={{.Version}} + - -s -w -X version.ProviderVersion={{.Version}} mod_timestamp: '{{ .CommitTimestamp }}' changelog: skip: true From baffc397d24e7e132930046350a8b0548da685ae Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Jul 2021 10:19:19 -0400 Subject: [PATCH 0936/1208] Call out use of EC2 DescribeVpcEndpoints/ModifyVpcEndpoint actions. --- website/docs/r/transfer_server.html.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index 257f4703b11c..2b754ab8544e 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -10,6 +10,8 @@ description: |- Provides a AWS Transfer Server resource. +~> **NOTE on AWS IAM permissions:** If the `endpoint_type` is set to `VPC`, the `ec2:DescribeVpcEndpoints` and `ec2:ModifyVpcEndpoint` [actions](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonec2.html#amazonec2-actions-as-permissions) are used. + ## Example Usage ### Basic @@ -124,7 +126,7 @@ In addition to all arguments above, the following attributes are exported: Transfer Servers can be imported using the `server id`, e.g. ``` -$ terraform import aws_transfer_server.bar s-12345678 +$ terraform import aws_transfer_server.example s-12345678 ``` Certain resource arguments, such as `host_key`, cannot be read via the API and imported into Terraform. Terraform will display a difference for these arguments the first run after import if declared in the Terraform configuration for an imported resource. From d6a8e5383b6d376448cba49cbc6bd2faeee750e2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Jul 2021 10:34:07 -0400 Subject: [PATCH 0937/1208] r/aws_transfer_server: Handle 'InvalidRequestException: AddressAllocationIds must be removed before SubnetIds can be modified'. --- aws/resource_aws_transfer_server.go | 37 +++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index 972412b495ba..c04b235b31bf 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -390,6 +390,7 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e var addressAllocationIDs []*string var offlineUpdate bool + var removeAddressAllocationIDs bool input := &transfer.UpdateServerInput{ ServerId: aws.String(d.Id()), @@ -416,6 +417,24 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e offlineUpdate = true } + // Update to 0 AddressAllocationIds. + if input.EndpointDetails.AddressAllocationIds == nil { + input.EndpointDetails.AddressAllocationIds = []*string{} + } + + // Prevent the following error: InvalidRequestException: AddressAllocationIds must be removed before SubnetIds can be modified + if d.HasChange("endpoint_details.0.subnet_ids") { + old, _ := d.GetChange("endpoint_details.0.address_allocation_ids") + + if old := old.(*schema.Set); old.Len() > 0 { + offlineUpdate = true + removeAddressAllocationIDs = true + + addressAllocationIDs = input.EndpointDetails.AddressAllocationIds + input.EndpointDetails.AddressAllocationIds = nil + } + } + // Prevent the following error: InvalidRequestException: Changing Security Group is not supported input.EndpointDetails.SecurityGroupIds = nil @@ -451,7 +470,7 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("error updating Transfer Server (%s) VPC Endpoint (%s): %w", d.Id(), vpcEndpointID, err) } - _, err := ec2waiter.VpcEndpointAvailable(conn, vpcEndpointID, d.Timeout(schema.TimeoutUpdate)) + _, err := ec2waiter.VpcEndpointAvailable(conn, vpcEndpointID, Ec2VpcEndpointCreationTimeout) if err != nil { return fmt.Errorf("error waiting for Transfer Server (%s) VPC Endpoint (%s) to become available: %w", d.Id(), vpcEndpointID, err) @@ -504,6 +523,20 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e } } + if removeAddressAllocationIDs { + input := &transfer.UpdateServerInput{ + ServerId: aws.String(d.Id()), + EndpointDetails: &transfer.EndpointDetails{ + AddressAllocationIds: []*string{}, + }, + } + + log.Printf("[DEBUG] Removing Transfer Server Address Allocation IDs: %s", input) + if err := updateTransferServer(conn, input); err != nil { + return err + } + } + log.Printf("[DEBUG] Updating Transfer Server: %s", input) if err := updateTransferServer(conn, input); err != nil { return err @@ -526,7 +559,6 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e } } - // Set any AddressAllocationIds if the server has updated endpoint type to VPC. if len(addressAllocationIDs) > 0 { input := &transfer.UpdateServerInput{ ServerId: aws.String(d.Id()), @@ -535,6 +567,7 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e }, } + log.Printf("[DEBUG] Adding Transfer Server Address Allocation IDs: %s", input) if err := updateTransferServer(conn, input); err != nil { return err } From f3cf2ce769dbfe49a939730b32d2e9f45abb3dd0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Jul 2021 12:32:56 -0400 Subject: [PATCH 0938/1208] r/aws_transfer_server: Simplify some acceptance tests. --- aws/resource_aws_transfer_server_test.go | 111 ++++------------------- 1 file changed, 18 insertions(+), 93 deletions(-) diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index 1313d31210b4..c1274b96ed90 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -244,7 +244,6 @@ func testAccAWSTransferServer_vpc(t *testing.T) { Config: testAccAWSTransferServerVpcConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), @@ -252,6 +251,7 @@ func testAccAWSTransferServer_vpc(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { @@ -264,7 +264,6 @@ func testAccAWSTransferServer_vpc(t *testing.T) { Config: testAccAWSTransferServerVpcUpdateConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), @@ -273,13 +272,13 @@ func testAccAWSTransferServer_vpc(t *testing.T) { resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { Config: testAccAWSTransferServerVpcConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), @@ -287,6 +286,7 @@ func testAccAWSTransferServer_vpc(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, }, @@ -313,7 +313,6 @@ func testAccAWSTransferServer_vpcAddressAllocationIds(t *testing.T) { Config: testAccAWSTransferServerVpcAddressAllocationIdsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip1ResourceName, "id"), @@ -323,6 +322,7 @@ func testAccAWSTransferServer_vpcAddressAllocationIds(t *testing.T) { resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { @@ -335,7 +335,6 @@ func testAccAWSTransferServer_vpcAddressAllocationIds(t *testing.T) { Config: testAccAWSTransferServerVpcAddressAllocationIdsUpdateConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip2ResourceName, "id"), @@ -345,13 +344,13 @@ func testAccAWSTransferServer_vpcAddressAllocationIds(t *testing.T) { resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { Config: testAccAWSTransferServerVpcConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), @@ -359,6 +358,7 @@ func testAccAWSTransferServer_vpcAddressAllocationIds(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, }, @@ -370,7 +370,6 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { resourceName := "aws_transfer_server.test" securityGroup1ResourceName := "aws_security_group.test" securityGroup2ResourceName := "aws_security_group.test2" - defaultSecurityGroupResourceName := "aws_default_security_group.test" vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -384,7 +383,6 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { Config: testAccAWSTransferServerVpcSecurityGroupIdsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), @@ -392,6 +390,7 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { @@ -404,7 +403,6 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { Config: testAccAWSTransferServerVpcSecurityGroupIdsUpdateConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), @@ -412,6 +410,7 @@ func testAccAWSTransferServer_vpcSecurityGroupIds(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, }, @@ -439,7 +438,6 @@ func testAccAWSTransferServer_vpcAddressAllocationIds_securityGroupIds(t *testin Config: testAccAWSTransferServerVpcAddressAllocationIdsSecurityGroupIdsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip1ResourceName, "id"), @@ -449,6 +447,7 @@ func testAccAWSTransferServer_vpcAddressAllocationIds_securityGroupIds(t *testin resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { @@ -461,7 +460,6 @@ func testAccAWSTransferServer_vpcAddressAllocationIds_securityGroupIds(t *testin Config: testAccAWSTransferServerVpcAddressAllocationIdsSecurityGroupIdsUpdateConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eip2ResourceName, "id"), @@ -471,6 +469,7 @@ func testAccAWSTransferServer_vpcAddressAllocationIds_securityGroupIds(t *testin resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, }, @@ -480,8 +479,6 @@ func testAccAWSTransferServer_vpcAddressAllocationIds_securityGroupIds(t *testin func testAccAWSTransferServer_updateEndpointType_publicToVpc(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" - defaultSecurityGroupResourceName := "aws_default_security_group.test" - vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.Test(t, resource.TestCase{ @@ -502,14 +499,8 @@ func testAccAWSTransferServer_updateEndpointType_publicToVpc(t *testing.T) { Config: testAccAWSTransferServerVpcConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), - resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { @@ -525,10 +516,6 @@ func testAccAWSTransferServer_updateEndpointType_publicToVpc(t *testing.T) { func testAccAWSTransferServer_updateEndpointType_publicToVpc_addressAllocationIds(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" - eipResourceName := "aws_eip.test.0" - defaultSecurityGroupResourceName := "aws_default_security_group.test" - subnetResourceName := "aws_subnet.test" - vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.Test(t, resource.TestCase{ @@ -549,16 +536,8 @@ func testAccAWSTransferServer_updateEndpointType_publicToVpc_addressAllocationId Config: testAccAWSTransferServerVpcAddressAllocationIdsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eipResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), - resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), - resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { @@ -574,9 +553,6 @@ func testAccAWSTransferServer_updateEndpointType_publicToVpc_addressAllocationId func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" - defaultSecurityGroupResourceName := "aws_default_security_group.test" - vpcEndpointResourceName := "aws_vpc_endpoint.test" - vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.Test(t, resource.TestCase{ @@ -589,27 +565,16 @@ func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc(t *testing.T) Config: testAccAWSTransferServerVpcEndpointConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), - resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_endpoint_id", vpcEndpointResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.vpc_id", ""), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), ), }, { Config: testAccAWSTransferServerVpcConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), - resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { @@ -625,11 +590,6 @@ func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc(t *testing.T) func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_addressAllocationIds(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" - eipResourceName := "aws_eip.test.0" - defaultSecurityGroupResourceName := "aws_default_security_group.test" - subnetResourceName := "aws_subnet.test" - vpcEndpointResourceName := "aws_vpc_endpoint.test" - vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.Test(t, resource.TestCase{ @@ -644,11 +604,6 @@ func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_addressAllocat testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), - resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_endpoint_id", vpcEndpointResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.vpc_id", ""), ), }, { @@ -657,14 +612,6 @@ func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_addressAllocat testAccCheckAWSTransferServerExists(resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.address_allocation_ids.*", eipResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.subnet_ids.*", subnetResourceName, "id"), - resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), - resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), ), }, { @@ -680,9 +627,6 @@ func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_addressAllocat func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_securityGroupIds(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" - securityGroupResourceName := "aws_security_group.test" - vpcEndpointResourceName := "aws_vpc_endpoint.test" - vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.Test(t, resource.TestCase{ @@ -695,27 +639,16 @@ func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_securityGroupI Config: testAccAWSTransferServerVpcEndpointConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), - resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_endpoint_id", vpcEndpointResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.vpc_id", ""), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), ), }, { Config: testAccAWSTransferServerVpcSecurityGroupIdsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", securityGroupResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), - resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { @@ -731,8 +664,6 @@ func testAccAWSTransferServer_updateEndpointType_vpcEndpointToVpc_securityGroupI func testAccAWSTransferServer_updateEndpointType_vpcToPublic(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" - defaultSecurityGroupResourceName := "aws_default_security_group.test" - vpcResourceName := "aws_vpc.test" rName := acctest.RandomWithPrefix("tf-acc-test") resource.Test(t, resource.TestCase{ @@ -745,14 +676,8 @@ func testAccAWSTransferServer_updateEndpointType_vpcToPublic(t *testing.T) { Config: testAccAWSTransferServerVpcConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "1"), - resource.TestCheckTypeSetElemAttrPair(resourceName, "endpoint_details.0.security_group_ids.*", defaultSecurityGroupResourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "endpoint_details.0.vpc_endpoint_id"), - resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_id", vpcResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC"), ), }, { @@ -976,13 +901,13 @@ func testAccAWSTransferServer_vpcEndpointId(t *testing.T) { Config: testAccAWSTransferServerVpcEndpointConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferServerExists(resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.#", "1"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.address_allocation_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.security_group_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.subnet_ids.#", "0"), resource.TestCheckResourceAttrPair(resourceName, "endpoint_details.0.vpc_endpoint_id", vpcEndpointResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "endpoint_details.0.vpc_id", ""), + resource.TestCheckResourceAttr(resourceName, "endpoint_type", "VPC_ENDPOINT"), ), }, { From 63f852f1a2b64af4e337b507a9db2af42e0a876e Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Fri, 2 Jul 2021 16:51:35 +0000 Subject: [PATCH 0939/1208] v3.48.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 118c5dcc0d60..53ea0bf22fe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 3.48.0 (Unreleased) +## 3.48.0 (July 02, 2021) FEATURES: From 2b06a38688ce41f72da1bb1c78174ccc27b20e8f Mon Sep 17 00:00:00 2001 From: changelogbot Date: Fri, 2 Jul 2021 17:11:33 +0000 Subject: [PATCH 0940/1208] Update CHANGELOG.md after v3.48.0 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53ea0bf22fe4..4b7731a01b7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## 3.49.0 (Unreleased) ## 3.48.0 (July 02, 2021) FEATURES: From c008160e6c9b51b9fe5fbd7873a5c5bc697f49e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Jul 2021 18:44:30 +0000 Subject: [PATCH 0941/1208] build(deps): bump github.com/bflad/tfproviderlint in /awsproviderlint Bumps [github.com/bflad/tfproviderlint](https://github.com/bflad/tfproviderlint) from 0.26.0 to 0.27.0. - [Release notes](https://github.com/bflad/tfproviderlint/releases) - [Changelog](https://github.com/bflad/tfproviderlint/blob/main/CHANGELOG.md) - [Commits](https://github.com/bflad/tfproviderlint/compare/v0.26.0...v0.27.0) --- updated-dependencies: - dependency-name: github.com/bflad/tfproviderlint dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 +- .../tfproviderlint/helper/astutils/package.go | 4 ++ .../bflad/tfproviderlint/passes/R006/R006.go | 42 +++++++++++++++++-- .../tfproviderlint/passes/R006/README.md | 4 ++ awsproviderlint/vendor/modules.txt | 2 +- 6 files changed, 51 insertions(+), 7 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index a1f0079246c0..8c64df62cb81 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/aws/aws-sdk-go v1.38.71 - github.com/bflad/tfproviderlint v0.26.0 + github.com/bflad/tfproviderlint v0.27.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb ) diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 54c82c3d98e1..26160262f8c2 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -74,8 +74,8 @@ github.com/aws/aws-sdk-go v1.38.71 h1:aWhtgoOiDhBCfaAj9XbxzcyvjEAKovbtv7d5mCVBZX github.com/aws/aws-sdk-go v1.38.71/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= -github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= -github.com/bflad/tfproviderlint v0.26.0/go.mod h1:7Z9Pyl1Z1UWJcPBuyjN89D2NaJGpjReQb5NoaaQCthQ= +github.com/bflad/tfproviderlint v0.27.0 h1:KXF+dYaWJ/OSVyWIrk2NIYgQBMDDSOC4VQB/P+P5nhI= +github.com/bflad/tfproviderlint v0.27.0/go.mod h1:7Z9Pyl1Z1UWJcPBuyjN89D2NaJGpjReQb5NoaaQCthQ= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= diff --git a/awsproviderlint/vendor/github.com/bflad/tfproviderlint/helper/astutils/package.go b/awsproviderlint/vendor/github.com/bflad/tfproviderlint/helper/astutils/package.go index 1ce1d7f2c8d3..91aae9414ee5 100644 --- a/awsproviderlint/vendor/github.com/bflad/tfproviderlint/helper/astutils/package.go +++ b/awsproviderlint/vendor/github.com/bflad/tfproviderlint/helper/astutils/package.go @@ -293,6 +293,10 @@ func IsStdlibPackageType(t types.Type, packagePath string, typeName string) bool func isModulePackagePath(module string, packageSuffix string, path string) bool { // Only check end of path due to vendoring + if packageSuffix == "" { + return strings.HasSuffix(path, module) + } + r := regexp.MustCompile(fmt.Sprintf("%s(/v[1-9][0-9]*)?/%s$", module, packageSuffix)) return r.MatchString(path) } diff --git a/awsproviderlint/vendor/github.com/bflad/tfproviderlint/passes/R006/R006.go b/awsproviderlint/vendor/github.com/bflad/tfproviderlint/passes/R006/R006.go index da27a3e6a25b..b66b59d58d31 100644 --- a/awsproviderlint/vendor/github.com/bflad/tfproviderlint/passes/R006/R006.go +++ b/awsproviderlint/vendor/github.com/bflad/tfproviderlint/passes/R006/R006.go @@ -3,8 +3,12 @@ package R006 import ( + "flag" "go/ast" + "go/types" + "strings" + "github.com/bflad/tfproviderlint/helper/astutils" "github.com/bflad/tfproviderlint/helper/terraformtype/helper/resource" "github.com/bflad/tfproviderlint/passes/commentignore" "github.com/bflad/tfproviderlint/passes/helper/resource/retryfuncinfo" @@ -14,13 +18,28 @@ import ( const Doc = `check for RetryFunc that omit retryable errors The R006 analyzer reports when RetryFunc declarations are missing -retryable errors and should not be used as RetryFunc.` +retryable errors and should not be used as RetryFunc. + +Optional parameters: + - package-aliases Comma-separated list of additional Go import paths to consider as aliases for helper/resource, defaults to none. +` const analyzerName = "R006" +var ( + packageAliases string +) + +func parseFlags() flag.FlagSet { + var flags = flag.NewFlagSet(analyzerName, flag.ExitOnError) + flags.StringVar(&packageAliases, "package-aliases", "", "Comma-separated list of additional Go import paths to consider as aliases for helper/resource") + return *flags +} + var Analyzer = &analysis.Analyzer{ - Name: analyzerName, - Doc: Doc, + Name: analyzerName, + Doc: Doc, + Flags: parseFlags(), Requires: []*analysis.Analyzer{ commentignore.Analyzer, retryfuncinfo.Analyzer, @@ -28,6 +47,18 @@ var Analyzer = &analysis.Analyzer{ Run: run, } +func isPackageAliasIgnored(e ast.Expr, info *types.Info, packageAliasesList string) bool { + packageAliases := strings.Split(packageAliasesList, ",") + + for _, packageAlias := range packageAliases { + if astutils.IsModulePackageFunc(e, info, packageAlias, "", resource.FuncNameRetryableError) { + return true + } + } + + return false +} + func run(pass *analysis.Pass) (interface{}, error) { ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) retryFuncs := pass.ResultOf[retryfuncinfo.Analyzer].([]*resource.RetryFuncInfo) @@ -51,6 +82,11 @@ func run(pass *analysis.Pass) (interface{}, error) { return false } + if packageAliases != "" && isPackageAliasIgnored(callExpr.Fun, pass.TypesInfo, packageAliases) { + retryableErrorFound = true + return false + } + return true }) diff --git a/awsproviderlint/vendor/github.com/bflad/tfproviderlint/passes/R006/README.md b/awsproviderlint/vendor/github.com/bflad/tfproviderlint/passes/R006/README.md index 4afb29973356..af7441563a86 100644 --- a/awsproviderlint/vendor/github.com/bflad/tfproviderlint/passes/R006/README.md +++ b/awsproviderlint/vendor/github.com/bflad/tfproviderlint/passes/R006/README.md @@ -2,6 +2,10 @@ The R006 analyzer reports when `RetryFunc` declarations are missing retryable errors (e.g. `RetryableError()` calls) and should not be used as `RetryFunc`. +Optional parameters: + +- `-package-aliases` Comma-separated list of additional Go import paths to consider as aliases for helper/resource, defaults to none. + ## Flagged Code ```go diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 76a11a4180fc..868fd1b3cb00 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -70,7 +70,7 @@ github.com/bflad/gopaniccheck/passes/logpaniccallexpr github.com/bflad/gopaniccheck/passes/logpanicfcallexpr github.com/bflad/gopaniccheck/passes/logpaniclncallexpr github.com/bflad/gopaniccheck/passes/paniccallexpr -# github.com/bflad/tfproviderlint v0.26.0 +# github.com/bflad/tfproviderlint v0.27.0 ## explicit github.com/bflad/tfproviderlint/helper/analysisutils github.com/bflad/tfproviderlint/helper/astutils From ac93cbe89a22490d0d6b015ac1ab32c5ce735629 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Jul 2021 18:44:42 +0000 Subject: [PATCH 0942/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.38.71 to 1.39.0 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.71 to 1.39.0. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.71...v1.39.0) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5a3199e20f34..0bdea89223d0 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect - github.com/aws/aws-sdk-go v1.38.71 + github.com/aws/aws-sdk-go v1.39.0 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index 64815f1736ec..009b6a2c58dd 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.38.71 h1:aWhtgoOiDhBCfaAj9XbxzcyvjEAKovbtv7d5mCVBZXw= -github.com/aws/aws-sdk-go v1.38.71/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo= +github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From e5dd508992c895215fd8cb86f4459d9d03e9114f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Jul 2021 18:44:54 +0000 Subject: [PATCH 0943/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.38.71 to 1.39.0. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.38.71...v1.39.0) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 +- .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- .../aws/aws-sdk-go/internal/ini/doc.go | 33 ++++++++---- .../aws/aws-sdk-go/internal/ini/ini_parser.go | 51 ++++++++----------- .../aws/aws-sdk-go/internal/ini/visitor.go | 5 +- awsproviderlint/vendor/modules.txt | 2 +- 7 files changed, 54 insertions(+), 45 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index a1f0079246c0..4b3289a4fd4c 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.38.71 + github.com/aws/aws-sdk-go v1.39.0 github.com/bflad/tfproviderlint v0.26.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 54c82c3d98e1..6dad7baea218 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -70,8 +70,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.71 h1:aWhtgoOiDhBCfaAj9XbxzcyvjEAKovbtv7d5mCVBZXw= -github.com/aws/aws-sdk-go v1.38.71/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo= +github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.26.0 h1:Xd+hbVlSQhKlXifpqmHPvlcnOK1lRS4IZf+cXBAUpCs= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index 95a41a03b2b6..62fbbf774048 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.38.71" +const SDKVersion = "1.39.0" diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/doc.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/doc.go index 25ce0fe134de..1e55bbd07b91 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/doc.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/doc.go @@ -13,17 +13,30 @@ // } // // Below is the BNF that describes this parser -// Grammar: -// stmt -> value stmt' -// stmt' -> epsilon | op stmt -// value -> number | string | boolean | quoted_string +// Grammar: +// stmt -> section | stmt' +// stmt' -> epsilon | expr +// expr -> value (stmt)* | equal_expr (stmt)* +// equal_expr -> value ( ':' | '=' ) equal_expr' +// equal_expr' -> number | string | quoted_string +// quoted_string -> " quoted_string' +// quoted_string' -> string quoted_string_end +// quoted_string_end -> " // -// section -> [ section' -// section' -> value section_close -// section_close -> ] +// section -> [ section' +// section' -> section_value section_close +// section_value -> number | string_subset | boolean | quoted_string_subset +// quoted_string_subset -> " quoted_string_subset' +// quoted_string_subset' -> string_subset quoted_string_end +// quoted_string_subset -> " +// section_close -> ] // -// SkipState will skip (NL WS)+ +// value -> number | string_subset | boolean +// string -> ? UTF-8 Code-Points except '\n' (U+000A) and '\r\n' (U+000D U+000A) ? +// string_subset -> ? Code-points excepted by grammar except ':' (U+003A), '=' (U+003D), '[' (U+005B), and ']' (U+005D) ? // -// comment -> # comment' | ; comment' -// comment' -> epsilon | value +// SkipState will skip (NL WS)+ +// +// comment -> # comment' | ; comment' +// comment' -> epsilon | value package ini diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/ini_parser.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/ini_parser.go index 55fa73ebcf2a..0ba319491c08 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/ini_parser.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/ini_parser.go @@ -5,9 +5,12 @@ import ( "io" ) +// ParseState represents the current state of the parser. +type ParseState uint + // State enums for the parse table const ( - InvalidState = iota + InvalidState ParseState = iota // stmt -> value stmt' StatementState // stmt' -> MarkComplete | op stmt @@ -36,8 +39,8 @@ const ( ) // parseTable is a state machine to dictate the grammar above. -var parseTable = map[ASTKind]map[TokenType]int{ - ASTKindStart: map[TokenType]int{ +var parseTable = map[ASTKind]map[TokenType]ParseState{ + ASTKindStart: { TokenLit: StatementState, TokenSep: OpenScopeState, TokenWS: SkipTokenState, @@ -45,7 +48,7 @@ var parseTable = map[ASTKind]map[TokenType]int{ TokenComment: CommentState, TokenNone: TerminalState, }, - ASTKindCommentStatement: map[TokenType]int{ + ASTKindCommentStatement: { TokenLit: StatementState, TokenSep: OpenScopeState, TokenWS: SkipTokenState, @@ -53,7 +56,7 @@ var parseTable = map[ASTKind]map[TokenType]int{ TokenComment: CommentState, TokenNone: MarkCompleteState, }, - ASTKindExpr: map[TokenType]int{ + ASTKindExpr: { TokenOp: StatementPrimeState, TokenLit: ValueState, TokenSep: OpenScopeState, @@ -62,13 +65,15 @@ var parseTable = map[ASTKind]map[TokenType]int{ TokenComment: CommentState, TokenNone: MarkCompleteState, }, - ASTKindEqualExpr: map[TokenType]int{ - TokenLit: ValueState, - TokenWS: SkipTokenState, - TokenNL: SkipState, - TokenNone: SkipState, + ASTKindEqualExpr: { + TokenLit: ValueState, + TokenSep: ValueState, + TokenOp: ValueState, + TokenWS: SkipTokenState, + TokenNL: SkipState, + TokenNone: SkipState, }, - ASTKindStatement: map[TokenType]int{ + ASTKindStatement: { TokenLit: SectionState, TokenSep: CloseScopeState, TokenWS: SkipTokenState, @@ -76,9 +81,9 @@ var parseTable = map[ASTKind]map[TokenType]int{ TokenComment: CommentState, TokenNone: MarkCompleteState, }, - ASTKindExprStatement: map[TokenType]int{ + ASTKindExprStatement: { TokenLit: ValueState, - TokenSep: OpenScopeState, + TokenSep: ValueState, TokenOp: ValueState, TokenWS: ValueState, TokenNL: MarkCompleteState, @@ -86,14 +91,14 @@ var parseTable = map[ASTKind]map[TokenType]int{ TokenNone: TerminalState, TokenComma: SkipState, }, - ASTKindSectionStatement: map[TokenType]int{ + ASTKindSectionStatement: { TokenLit: SectionState, TokenOp: SectionState, TokenSep: CloseScopeState, TokenWS: SectionState, TokenNL: SkipTokenState, }, - ASTKindCompletedSectionStatement: map[TokenType]int{ + ASTKindCompletedSectionStatement: { TokenWS: SkipTokenState, TokenNL: SkipTokenState, TokenLit: StatementState, @@ -101,7 +106,7 @@ var parseTable = map[ASTKind]map[TokenType]int{ TokenComment: CommentState, TokenNone: MarkCompleteState, }, - ASTKindSkipStatement: map[TokenType]int{ + ASTKindSkipStatement: { TokenLit: StatementState, TokenSep: OpenScopeState, TokenWS: SkipTokenState, @@ -205,18 +210,6 @@ loop: case ValueState: // ValueState requires the previous state to either be an equal expression // or an expression statement. - // - // This grammar occurs when the RHS is a number, word, or quoted string. - // equal_expr -> lit op equal_expr' - // equal_expr' -> number | string | quoted_string - // quoted_string -> " quoted_string' - // quoted_string' -> string quoted_string_end - // quoted_string_end -> " - // - // otherwise - // expr_stmt -> equal_expr (expr_stmt')* - // expr_stmt' -> ws S | op S | MarkComplete - // S -> equal_expr' expr_stmt' switch k.Kind { case ASTKindEqualExpr: // assigning a value to some key @@ -243,7 +236,7 @@ loop: } children[len(children)-1] = rhs - k.SetChildren(children) + root.SetChildren(children) stack.Push(k) } diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/visitor.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/visitor.go index 94841c32443c..081cf4334241 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/visitor.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/internal/ini/visitor.go @@ -50,7 +50,10 @@ func (v *DefaultVisitor) VisitExpr(expr AST) error { rhs := children[1] - if rhs.Root.Type() != TokenLit { + // The right-hand value side the equality expression is allowed to contain '[', ']', ':', '=' in the values. + // If the token is not either a literal or one of the token types that identifies those four additional + // tokens then error. + if !(rhs.Root.Type() == TokenLit || rhs.Root.Type() == TokenOp || rhs.Root.Type() == TokenSep) { return NewParseError("unexpected token type") } diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 76a11a4180fc..7bffdfcc982f 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.38.71 +# github.com/aws/aws-sdk-go v1.39.0 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 38971b4f186d1d0367cc3a5cc92cf790c59a3a8f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Jul 2021 15:09:19 -0400 Subject: [PATCH 0944/1208] r/aws_eks_cluster: Remove extra 'ForceNew's. --- aws/resource_aws_eks_cluster.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/aws/resource_aws_eks_cluster.go b/aws/resource_aws_eks_cluster.go index c13ed4eb7a9d..3c8e1000a47f 100644 --- a/aws/resource_aws_eks_cluster.go +++ b/aws/resource_aws_eks_cluster.go @@ -91,7 +91,6 @@ func resourceAwsEksCluster() *schema.Resource { "key_arn": { Type: schema.TypeString, Required: true, - ForceNew: true, }, }, }, @@ -99,7 +98,6 @@ func resourceAwsEksCluster() *schema.Resource { "resources": { Type: schema.TypeSet, Required: true, - ForceNew: true, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.StringInSlice(tfeks.Resources_Values(), false), From 678491c778219987b09c555373d3a8809466aaa9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Jul 2021 15:32:32 -0400 Subject: [PATCH 0945/1208] Simplify acceptance test configurations. --- aws/resource_aws_transfer_server.go | 17 ------- aws/resource_aws_transfer_server_test.go | 63 ++++++------------------ 2 files changed, 16 insertions(+), 64 deletions(-) diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index c04b235b31bf..d388f43f5786 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -542,23 +542,6 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e return err } - if newEndpointTypeVpc && !oldEndpointTypeVpc { - // Wait for newly provisioned VPC Endpoint to become available. - output, err := finder.ServerByID(conn, d.Id()) - - if err != nil { - return fmt.Errorf("error reading Transfer Server (%s): %w", d.Id(), err) - } - - vpcEndpointID := aws.StringValue(output.EndpointDetails.VpcEndpointId) - - _, err = ec2waiter.VpcEndpointAvailable(meta.(*AWSClient).ec2conn, vpcEndpointID, d.Timeout(schema.TimeoutUpdate)) - - if err != nil { - return fmt.Errorf("error waiting for Transfer Server (%s) VPC Endpoint (%s) to become available: %w", d.Id(), vpcEndpointID, err) - } - } - if len(addressAllocationIDs) > 0 { input := &transfer.UpdateServerInput{ ServerId: aws.String(d.Id()), diff --git a/aws/resource_aws_transfer_server_test.go b/aws/resource_aws_transfer_server_test.go index c1274b96ed90..1bb9ab0d79aa 100644 --- a/aws/resource_aws_transfer_server_test.go +++ b/aws/resource_aws_transfer_server_test.go @@ -1040,6 +1040,16 @@ resource "aws_security_group" "test" { resource "aws_default_security_group" "test" { vpc_id = aws_vpc.test.id } + +resource "aws_eip" "test" { + count = 2 + + vpc = true + + tags = { + Name = %[1]q + } +} `, rName) } @@ -1310,17 +1320,7 @@ resource "aws_transfer_server" "test" { func testAccAWSTransferServerVpcAddressAllocationIdsConfig(rName string) string { return composeConfig( testAccAWSTransferServerConfigBaseVpc(rName), - fmt.Sprintf(` -resource "aws_eip" "test" { - count = 2 - - vpc = true - - tags = { - Name = %[1]q - } -} - + ` resource "aws_transfer_server" "test" { endpoint_type = "VPC" @@ -1330,23 +1330,13 @@ resource "aws_transfer_server" "test" { vpc_id = aws_vpc.test.id } } -`, rName)) +`) } func testAccAWSTransferServerVpcAddressAllocationIdsUpdateConfig(rName string) string { return composeConfig( testAccAWSTransferServerConfigBaseVpc(rName), - fmt.Sprintf(` -resource "aws_eip" "test" { - count = 2 - - vpc = true - - tags = { - Name = %[1]q - } -} - + ` resource "aws_transfer_server" "test" { endpoint_type = "VPC" @@ -1356,23 +1346,13 @@ resource "aws_transfer_server" "test" { vpc_id = aws_vpc.test.id } } -`, rName)) +`) } func testAccAWSTransferServerVpcAddressAllocationIdsSecurityGroupIdsConfig(rName string) string { return composeConfig( testAccAWSTransferServerConfigBaseVpc(rName), - fmt.Sprintf(` -resource "aws_eip" "test" { - count = 2 - - vpc = true - - tags = { - Name = %[1]q - } -} - + ` resource "aws_transfer_server" "test" { endpoint_type = "VPC" @@ -1383,7 +1363,7 @@ resource "aws_transfer_server" "test" { vpc_id = aws_vpc.test.id } } -`, rName)) +`) } func testAccAWSTransferServerVpcAddressAllocationIdsSecurityGroupIdsUpdateConfig(rName string) string { @@ -1398,17 +1378,6 @@ resource "aws_security_group" "test2" { Name = "%[1]s-2" } } - -resource "aws_eip" "test" { - count = 2 - - vpc = true - - tags = { - Name = %[1]q - } -} - resource "aws_transfer_server" "test" { endpoint_type = "VPC" From 5f0574f3461eb780e1b865316d39064b3fd89a24 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 4 Jul 2021 02:51:33 +0300 Subject: [PATCH 0946/1208] docs + more tests --- a.txt | 2 + ..._aws_ecr_replication_configuration_test.go | 49 +++++++++++++++++++ ...cr_replication_configuration.html.markdown | 24 +++++++++ 3 files changed, 75 insertions(+) create mode 100644 a.txt diff --git a/a.txt b/a.txt new file mode 100644 index 000000000000..8bdec30e0870 --- /dev/null +++ b/a.txt @@ -0,0 +1,2 @@ +==> Checking that code complies with gofmt requirements... +TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSEcrReplicationConfiguration_basic -timeout 180m diff --git a/aws/resource_aws_ecr_replication_configuration_test.go b/aws/resource_aws_ecr_replication_configuration_test.go index 133be0214c6f..d6d964d25b96 100644 --- a/aws/resource_aws_ecr_replication_configuration_test.go +++ b/aws/resource_aws_ecr_replication_configuration_test.go @@ -35,6 +35,32 @@ func TestAccAWSEcrReplicationConfiguration_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccAWSEcrReplicationMultipleRegionConfiguration(testAccGetAlternateRegion(), testAccGetThirdRegion()), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcrReplicationConfigurationExists(resourceName), + testAccCheckResourceAttrAccountID(resourceName, "registry_id"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.#", "2"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.0.region", testAccGetAlternateRegion()), + testAccCheckResourceAttrAccountID(resourceName, "replication_configuration.0.rule.0.destination.0.registry_id"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.1.region", testAccGetThirdRegion()), + testAccCheckResourceAttrAccountID(resourceName, "replication_configuration.0.rule.0.destination..registry_id"), + ), + }, + { + Config: testAccAWSEcrReplicationConfiguration(testAccGetAlternateRegion()), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcrReplicationConfigurationExists(resourceName), + testAccCheckResourceAttrAccountID(resourceName, "registry_id"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.#", "1"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.0.region", testAccGetAlternateRegion()), + testAccCheckResourceAttrAccountID(resourceName, "replication_configuration.0.rule.0.destination.0.registry_id"), + ), + }, }, }) } @@ -97,3 +123,26 @@ resource "aws_ecr_replication_configuration" "test" { } `, region) } + +func testAccAWSEcrReplicationMultipleRegionConfiguration(region1, region2 string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_ecr_replication_configuration" "test" { + replication_configuration { + rule { + destination { + region = %[1]q + registry_id = data.aws_caller_identity.current.account_id + } + + + destination { + region = %[2]q + registry_id = data.aws_caller_identity.current.account_id + } + } + } +} +`, region1, region2) +} diff --git a/website/docs/r/ecr_replication_configuration.html.markdown b/website/docs/r/ecr_replication_configuration.html.markdown index cb6735620569..b5da3657b977 100644 --- a/website/docs/r/ecr_replication_configuration.html.markdown +++ b/website/docs/r/ecr_replication_configuration.html.markdown @@ -29,6 +29,30 @@ resource "aws_ecr_replication_configuration" "example" { } ``` +## Multiple Region Usage + +```terraform +data "aws_caller_identity" "current" {} + +data "aws_regions" "example" {} + +resource "aws_ecr_replication_configuration" "example" { + replication_configuration { + rule { + destination { + region = data.aws_regions.example.names[0] + registry_id = data.aws_caller_identity.current.account_id + } + + destination { + region = data.aws_regions.example.names[1] + registry_id = data.aws_caller_identity.current.account_id + } + } + } +} +``` + ## Argument Reference The following arguments are supported: From 69fee06eb6ac2c108f5888b188669eb2b5b5f7ec Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 4 Jul 2021 02:53:55 +0300 Subject: [PATCH 0947/1208] fix test --- aws/resource_aws_ecr_replication_configuration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_ecr_replication_configuration_test.go b/aws/resource_aws_ecr_replication_configuration_test.go index d6d964d25b96..9ff3bc9c93bc 100644 --- a/aws/resource_aws_ecr_replication_configuration_test.go +++ b/aws/resource_aws_ecr_replication_configuration_test.go @@ -46,7 +46,7 @@ func TestAccAWSEcrReplicationConfiguration_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.0.region", testAccGetAlternateRegion()), testAccCheckResourceAttrAccountID(resourceName, "replication_configuration.0.rule.0.destination.0.registry_id"), resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rule.0.destination.1.region", testAccGetThirdRegion()), - testAccCheckResourceAttrAccountID(resourceName, "replication_configuration.0.rule.0.destination..registry_id"), + testAccCheckResourceAttrAccountID(resourceName, "replication_configuration.0.rule.0.destination.1.registry_id"), ), }, { From 9f001df9932c62dc7ed70c7f107ba3093e202040 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sun, 4 Jul 2021 02:58:58 +0300 Subject: [PATCH 0948/1208] doc fmt --- website/docs/r/ecr_replication_configuration.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/ecr_replication_configuration.html.markdown b/website/docs/r/ecr_replication_configuration.html.markdown index b5da3657b977..c98f137060a7 100644 --- a/website/docs/r/ecr_replication_configuration.html.markdown +++ b/website/docs/r/ecr_replication_configuration.html.markdown @@ -47,7 +47,7 @@ resource "aws_ecr_replication_configuration" "example" { destination { region = data.aws_regions.example.names[1] registry_id = data.aws_caller_identity.current.account_id - } + } } } } From 547ae52af6f320744679d40c5d24552f5fa9ae61 Mon Sep 17 00:00:00 2001 From: huikaihoo Date: Tue, 6 Jul 2021 11:53:05 +0800 Subject: [PATCH 0949/1208] Update amplify_branch.html.markdown Fix typo on `enable_notification` --- website/docs/r/amplify_branch.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/amplify_branch.html.markdown b/website/docs/r/amplify_branch.html.markdown index 38a78617f553..223f9427a27b 100644 --- a/website/docs/r/amplify_branch.html.markdown +++ b/website/docs/r/amplify_branch.html.markdown @@ -162,7 +162,7 @@ The following arguments are supported: * `display_name` - (Optional) The display name for a branch. This is used as the default domain prefix. * `enable_auto_build` - (Optional) Enables auto building for the branch. * `enable_basic_auth` - (Optional) Enables basic authorization for the branch. -* `enable_notifications` - (Optional) Enables notifications for the branch. +* `enable_notification` - (Optional) Enables notifications for the branch. * `enable_performance_mode` - (Optional) Enables performance mode for the branch. * `enable_pull_request_preview` - (Optional) Enables pull request previews for this branch. * `environment_variables` - (Optional) The environment variables for the branch. From b0a239dcbcd45cc606e9aaa343674e82a62477ba Mon Sep 17 00:00:00 2001 From: "zhigang.huang" Date: Tue, 6 Jul 2021 16:26:26 +0800 Subject: [PATCH 0950/1208] add tags when create target group in aws --- aws/resource_aws_lb_target_group.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index 23a5f91b252c..73ee689aa8c6 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -286,6 +286,8 @@ func suppressIfTargetType(t string) schema.SchemaDiffSuppressFunc { func resourceAwsLbTargetGroupCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).elbv2conn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) var groupName string if v, ok := d.GetOk("name"); ok { @@ -363,6 +365,10 @@ func resourceAwsLbTargetGroupCreate(d *schema.ResourceData, meta interface{}) er } } + if len(tags) > 0 { + params.Tags = tags.IgnoreAws().Elbv2Tags() + } + resp, err := conn.CreateTargetGroup(params) if err != nil { return fmt.Errorf("error creating LB Target Group: %w", err) From b56d16157e39290905a30cce94d6cc8438456263 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Jul 2021 16:48:48 -0400 Subject: [PATCH 0951/1208] r/aws_db_cluster_role_association - New resource. Co-authored-by: Matthieu ANTOINE --- ...esource_aws_db_cluster_role_association.go | 254 ++++++++++++++++++ ...ce_aws_db_cluster_role_association_test.go | 198 ++++++++++++++ .../db_cluster_role_association.html.markdown | 46 ++++ 3 files changed, 498 insertions(+) create mode 100644 aws/resource_aws_db_cluster_role_association.go create mode 100644 aws/resource_aws_db_cluster_role_association_test.go create mode 100644 website/docs/r/db_cluster_role_association.html.markdown diff --git a/aws/resource_aws_db_cluster_role_association.go b/aws/resource_aws_db_cluster_role_association.go new file mode 100644 index 000000000000..5137a3b01471 --- /dev/null +++ b/aws/resource_aws_db_cluster_role_association.go @@ -0,0 +1,254 @@ +package aws + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Constants not currently provided by the AWS Go SDK +const ( + rdsDbClusterRoleStatusActive = "ACTIVE" + rdsDbClusterRoleStatusDeleted = "DELETED" + rdsDbClusterRoleStatusPending = "PENDING" +) + +func resourceAwsDbClusterRoleAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsDbClusterRoleAssociationCreate, + Read: resourceAwsDbClusterRoleAssociationRead, + Delete: resourceAwsDbClusterRoleAssociationDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "db_cluster_identifier": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "feature_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "role_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateArn, + }, + }, + } +} + +func resourceAwsDbClusterRoleAssociationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).rdsconn + + dbClusterIdentifier := d.Get("db_cluster_identifier").(string) + roleArn := d.Get("role_arn").(string) + + input := &rds.AddRoleToDBClusterInput{ + DBClusterIdentifier: aws.String(dbClusterIdentifier), + FeatureName: aws.String(d.Get("feature_name").(string)), + RoleArn: aws.String(roleArn), + } + + log.Printf("[DEBUG] RDS DB Cluster (%s) IAM Role associating: %s", dbClusterIdentifier, roleArn) + _, err := conn.AddRoleToDBCluster(input) + + if err != nil { + return fmt.Errorf("error associating RDS DB Cluster (%s) IAM Role (%s): %s", dbClusterIdentifier, roleArn, err) + } + + d.SetId(fmt.Sprintf("%s,%s", dbClusterIdentifier, roleArn)) + + if err := waitForRdsDbClusterRoleAssociation(conn, dbClusterIdentifier, roleArn); err != nil { + return fmt.Errorf("error waiting for RDS DB Cluster (%s) IAM Role (%s) association: %s", dbClusterIdentifier, roleArn, err) + } + + return resourceAwsDbClusterRoleAssociationRead(d, meta) +} + +func resourceAwsDbClusterRoleAssociationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).rdsconn + + dbClusterIdentifier, roleArn, err := resourceAwsDbClusterRoleAssociationDecodeID(d.Id()) + + if err != nil { + return fmt.Errorf("error reading resource ID: %s", err) + } + + dbClusterRole, err := rdsDescribeDbClusterRole(conn, dbClusterIdentifier, roleArn) + + if isAWSErr(err, rds.ErrCodeDBClusterNotFoundFault, "") { + log.Printf("[WARN] RDS DB Cluster (%s) not found, removing from state", dbClusterIdentifier) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading RDS DB Cluster (%s) IAM Role (%s) association: %s", dbClusterIdentifier, roleArn, err) + } + + if dbClusterRole == nil { + log.Printf("[WARN] RDS DB Cluster (%s) IAM Role (%s) association not found, removing from state", dbClusterIdentifier, roleArn) + d.SetId("") + return nil + } + + d.Set("db_cluster_identifier", dbClusterIdentifier) + d.Set("feature_name", dbClusterRole.FeatureName) + d.Set("role_arn", dbClusterRole.RoleArn) + + return nil +} + +func resourceAwsDbClusterRoleAssociationDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).rdsconn + + dbClusterIdentifier, roleArn, err := resourceAwsDbClusterRoleAssociationDecodeID(d.Id()) + + if err != nil { + return fmt.Errorf("error reading resource ID: %s", err) + } + + input := &rds.RemoveRoleFromDBClusterInput{ + DBClusterIdentifier: aws.String(dbClusterIdentifier), + FeatureName: aws.String(d.Get("feature_name").(string)), + RoleArn: aws.String(roleArn), + } + + log.Printf("[DEBUG] RDS DB Cluster (%s) IAM Role disassociating: %s", dbClusterIdentifier, roleArn) + _, err = conn.RemoveRoleFromDBCluster(input) + + if isAWSErr(err, rds.ErrCodeDBClusterNotFoundFault, "") { + return nil + } + + if isAWSErr(err, rds.ErrCodeDBClusterRoleNotFoundFault, "") { + return nil + } + + if err != nil { + return fmt.Errorf("error disassociating RDS DB Cluster (%s) IAM Role (%s): %s", dbClusterIdentifier, roleArn, err) + } + + if err := waitForRdsDbClusterRoleDisassociation(conn, dbClusterIdentifier, roleArn); err != nil { + return fmt.Errorf("error waiting for RDS DB Cluster (%s) IAM Role (%s) disassociation: %s", dbClusterIdentifier, roleArn, err) + } + + return nil +} + +func resourceAwsDbClusterRoleAssociationDecodeID(id string) (string, string, error) { + parts := strings.SplitN(id, ",", 2) + + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("unexpected format of ID (%s), expected DB-CLUSTER-ID,ROLE-ARN", id) + } + + return parts[0], parts[1], nil +} + +func rdsDescribeDbClusterRole(conn *rds.RDS, dbClusterIdentifier, roleArn string) (*rds.DBClusterRole, error) { + input := &rds.DescribeDBClustersInput{ + DBClusterIdentifier: aws.String(dbClusterIdentifier), + } + + log.Printf("[DEBUG] Describing RDS DB Cluster: %s", input) + output, err := conn.DescribeDBClusters(input) + + if err != nil { + return nil, err + } + + var dbCluster *rds.DBCluster + + for _, outputDbCluster := range output.DBClusters { + if aws.StringValue(outputDbCluster.DBClusterIdentifier) == dbClusterIdentifier { + dbCluster = outputDbCluster + break + } + } + + if dbCluster == nil { + return nil, nil + } + + var dbClusterRole *rds.DBClusterRole + + for _, associatedRole := range dbCluster.AssociatedRoles { + if aws.StringValue(associatedRole.RoleArn) == roleArn { + dbClusterRole = associatedRole + break + } + } + + return dbClusterRole, nil +} + +func waitForRdsDbClusterRoleAssociation(conn *rds.RDS, dbClusterIdentifier, roleArn string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{rdsDbClusterRoleStatusPending}, + Target: []string{rdsDbClusterRoleStatusActive}, + Refresh: func() (interface{}, string, error) { + dbClusterRole, err := rdsDescribeDbClusterRole(conn, dbClusterIdentifier, roleArn) + + if err != nil { + return nil, "", err + } + + return dbClusterRole, aws.StringValue(dbClusterRole.Status), nil + }, + Timeout: 5 * time.Minute, + Delay: 5 * time.Second, + } + + log.Printf("[DEBUG] Waiting for RDS DB Cluster (%s) IAM Role association: %s", dbClusterIdentifier, roleArn) + _, err := stateConf.WaitForState() + + return err +} + +func waitForRdsDbClusterRoleDisassociation(conn *rds.RDS, dbClusterIdentifier, roleArn string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{ + rdsDbClusterRoleStatusActive, + rdsDbClusterRoleStatusPending, + }, + Target: []string{rdsDbClusterRoleStatusDeleted}, + Refresh: func() (interface{}, string, error) { + dbClusterRole, err := rdsDescribeDbClusterRole(conn, dbClusterIdentifier, roleArn) + + if isAWSErr(err, rds.ErrCodeDBClusterNotFoundFault, "") { + return &rds.DBClusterRole{}, rdsDbClusterRoleStatusDeleted, nil + } + + if err != nil { + return nil, "", err + } + + if dbClusterRole != nil { + return dbClusterRole, aws.StringValue(dbClusterRole.Status), nil + } + + return &rds.DBClusterRole{}, rdsDbClusterRoleStatusDeleted, nil + }, + Timeout: 5 * time.Minute, + Delay: 5 * time.Second, + } + + log.Printf("[DEBUG] Waiting for RDS DB Cluster (%s) IAM Role disassociation: %s", dbClusterIdentifier, roleArn) + _, err := stateConf.WaitForState() + + return err +} diff --git a/aws/resource_aws_db_cluster_role_association_test.go b/aws/resource_aws_db_cluster_role_association_test.go new file mode 100644 index 000000000000..93b1cb455cd8 --- /dev/null +++ b/aws/resource_aws_db_cluster_role_association_test.go @@ -0,0 +1,198 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/rds" + "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 TestAccAWSDbClusterRoleAssociation_basic(t *testing.T) { + var dbClusterRole1 rds.DBClusterRole + rName := acctest.RandomWithPrefix("tf-acc-test") + dbClusterResourceName := "aws_rds_cluster.test" + iamRoleResourceName := "aws_iam_role.test" + resourceName := "aws_db_cluster_role_association.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDbClusterRoleAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDbClusterRoleAssociationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDbClusterRoleAssociationExists(resourceName, &dbClusterRole1), + resource.TestCheckResourceAttrPair(resourceName, "db_cluster_identifier", dbClusterResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "feature_name", "s3Import"), + resource.TestCheckResourceAttrPair(resourceName, "role_arn", iamRoleResourceName, "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSDbClusterRoleAssociation_disappears(t *testing.T) { + var dbCluster1 rds.DBCluster + var dbClusterRole1 rds.DBClusterRole + rName := acctest.RandomWithPrefix("tf-acc-test") + dbClusterResourceName := "aws_rds_cluster.test" + resourceName := "aws_db_cluster_role_association.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDbClusterRoleAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDbClusterRoleAssociationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSClusterExists(dbClusterResourceName, &dbCluster1), + testAccCheckAWSDbClusterRoleAssociationExists(resourceName, &dbClusterRole1), + testAccCheckAWSDbClusterRoleAssociationDisappears(&dbCluster1, &dbClusterRole1), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSDbClusterRoleAssociationExists(resourceName string, dbClusterRole *rds.DBClusterRole) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + + if !ok { + return fmt.Errorf("Resource not found: %s", resourceName) + } + + dbClusterIdentifier, roleArn, err := resourceAwsDbClusterRoleAssociationDecodeID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("error reading resource ID: %s", err) + } + + conn := testAccProvider.Meta().(*AWSClient).rdsconn + + role, err := rdsDescribeDbClusterRole(conn, dbClusterIdentifier, roleArn) + + if err != nil { + return err + } + + if role == nil { + return fmt.Errorf("RDS DB Cluster IAM Role Association not found") + } + + if aws.StringValue(role.Status) != "ACTIVE" { + return fmt.Errorf("RDS DB Cluster (%s) IAM Role (%s) association exists in non-ACTIVE (%s) state", dbClusterIdentifier, roleArn, aws.StringValue(role.Status)) + } + + *dbClusterRole = *role + + return nil + } +} + +func testAccCheckAWSDbClusterRoleAssociationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).rdsconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_db_cluster_role_association" { + continue + } + + dbClusterIdentifier, roleArn, err := resourceAwsDbClusterRoleAssociationDecodeID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("error reading resource ID: %s", err) + } + + dbClusterRole, err := rdsDescribeDbClusterRole(conn, dbClusterIdentifier, roleArn) + + if isAWSErr(err, rds.ErrCodeDBClusterNotFoundFault, "") { + continue + } + + if err != nil { + return err + } + + if dbClusterRole == nil { + continue + } + + return fmt.Errorf("RDS DB Cluster (%s) IAM Role (%s) association still exists in non-deleted (%s) state", dbClusterIdentifier, roleArn, aws.StringValue(dbClusterRole.Status)) + } + + return nil +} + +func testAccCheckAWSDbClusterRoleAssociationDisappears(dbCluster *rds.DBCluster, dbClusterRole *rds.DBClusterRole) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).rdsconn + + input := &rds.RemoveRoleFromDBClusterInput{ + DBClusterIdentifier: dbCluster.DBClusterIdentifier, + FeatureName: dbClusterRole.FeatureName, + RoleArn: dbClusterRole.RoleArn, + } + + _, err := conn.RemoveRoleFromDBCluster(input) + + if err != nil { + return err + } + + return waitForRdsDbClusterRoleDisassociation(conn, aws.StringValue(dbCluster.DBClusterIdentifier), aws.StringValue(dbClusterRole.RoleArn)) + } +} + +func testAccAWSDbClusterRoleAssociationConfig(rName string) string { + return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(` +data "aws_iam_policy_document" "rds_assume_role_policy" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + + principals { + identifiers = ["rds.amazonaws.com"] + type = "Service" + } + } +} + +resource "aws_iam_role" "test" { + assume_role_policy = data.aws_iam_policy_document.rds_assume_role_policy.json + name = %[1]q +} + +resource "aws_rds_cluster" "test" { + cluster_identifier = %[1]q + engine = "aurora-postgresql" + availability_zones = [data.aws_availability_zones.available.names[0], data.aws_availability_zones.available.names[1], data.aws_availability_zones.available.names[2]] + database_name = "mydb" + master_username = "foo" + master_password = "foobarfoobarfoobar" + backup_retention_period = 5 + preferred_backup_window = "07:00-09:00" + skip_final_snapshot = true +} + +resource "aws_db_cluster_role_association" "test" { + db_cluster_identifier = aws_rds_cluster.test.id + feature_name = "s3Import" + role_arn = aws_iam_role.test.arn +} +`, rName)) +} diff --git a/website/docs/r/db_cluster_role_association.html.markdown b/website/docs/r/db_cluster_role_association.html.markdown new file mode 100644 index 000000000000..2845c9d6821a --- /dev/null +++ b/website/docs/r/db_cluster_role_association.html.markdown @@ -0,0 +1,46 @@ +--- +subcategory: "RDS" +layout: "aws" +page_title: "AWS: aws_db_cluster_role_association" +description: |- + Manages a RDS DB Cluster association with an IAM Role. +--- + +# Resource: aws_db_cluster_role_association + +Manages a RDS DB Cluster association with an IAM Role. Example use cases: + +* [Creating an IAM Role to Allow Amazon Aurora to Access AWS Services](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.Authorizing.IAM.CreateRole.html) +* [Importing Amazon S3 Data into an RDS PostgreSQL DB Cluster](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PostgreSQL.S3Import.html) + +## Example Usage + +```terraform +resource "aws_db_cluster_role_association" "example" { + db_cluster_identifier = "${aws_rds_cluster.example.id}" + feature_name = "S3_INTEGRATION" + role_arn = "${aws_iam_role.example.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `db_cluster_identifier` - (Required) DB Cluster Identifier to associate with the IAM Role. +* `feature_name` - (Required) Name of the feature for association. This can be found in the AWS documentation relevant to the integration or a full list is available in the `SupportedFeatureNames` list returned by [AWS CLI rds describe-db-engine-versions](https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-engine-versions.html). +* `role_arn` - (Required) Amazon Resource Name (ARN) of the IAM Role to associate with the DB Cluster. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - DB Cluster Identifier and IAM Role ARN separated by a comma (`,`) + +## Import + +`aws_db_cluster_role_association` can be imported using the DB Cluster Identifier and IAM Role ARN separated by a comma (`,`), e.g. + +``` +$ terraform import aws_db_cluster_role_association.example my-db-cluster,arn:aws:iam::123456789012:role/my-role +``` From 223edb168c7f20a3a2c81d1b63b14bc24c00b6a0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 6 Jul 2021 09:54:46 -0400 Subject: [PATCH 0952/1208] 'aws_db_cluster_role_association' -> 'aws_rds_cluster_role_association'. --- aws/provider.go | 1 + ...ource_aws_rds_cluster_role_association.go} | 16 +++--- ..._aws_rds_cluster_role_association_test.go} | 57 ++++++------------- ...ds_cluster_role_association.html.markdown} | 14 ++--- 4 files changed, 33 insertions(+), 55 deletions(-) rename aws/{resource_aws_db_cluster_role_association.go => resource_aws_rds_cluster_role_association.go} (92%) rename aws/{resource_aws_db_cluster_role_association_test.go => resource_aws_rds_cluster_role_association_test.go} (68%) rename website/docs/r/{db_cluster_role_association.html.markdown => rds_cluster_role_association.html.markdown} (73%) diff --git a/aws/provider.go b/aws/provider.go index 1a20232f3001..284c667ae22c 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -952,6 +952,7 @@ func Provider() *schema.Provider { "aws_rds_cluster_endpoint": resourceAwsRDSClusterEndpoint(), "aws_rds_cluster_instance": resourceAwsRDSClusterInstance(), "aws_rds_cluster_parameter_group": resourceAwsRDSClusterParameterGroup(), + "aws_rds_cluster_role_association": resourceAwsRDSClusterRoleAssociation(), "aws_rds_global_cluster": resourceAwsRDSGlobalCluster(), "aws_redshift_cluster": resourceAwsRedshiftCluster(), "aws_redshift_security_group": resourceAwsRedshiftSecurityGroup(), diff --git a/aws/resource_aws_db_cluster_role_association.go b/aws/resource_aws_rds_cluster_role_association.go similarity index 92% rename from aws/resource_aws_db_cluster_role_association.go rename to aws/resource_aws_rds_cluster_role_association.go index 5137a3b01471..dfae74a59ec5 100644 --- a/aws/resource_aws_db_cluster_role_association.go +++ b/aws/resource_aws_rds_cluster_role_association.go @@ -19,11 +19,11 @@ const ( rdsDbClusterRoleStatusPending = "PENDING" ) -func resourceAwsDbClusterRoleAssociation() *schema.Resource { +func resourceAwsRDSClusterRoleAssociation() *schema.Resource { return &schema.Resource{ - Create: resourceAwsDbClusterRoleAssociationCreate, - Read: resourceAwsDbClusterRoleAssociationRead, - Delete: resourceAwsDbClusterRoleAssociationDelete, + Create: resourceAwsRDSClusterRoleAssociationCreate, + Read: resourceAwsRDSClusterRoleAssociationRead, + Delete: resourceAwsRDSClusterRoleAssociationDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -50,7 +50,7 @@ func resourceAwsDbClusterRoleAssociation() *schema.Resource { } } -func resourceAwsDbClusterRoleAssociationCreate(d *schema.ResourceData, meta interface{}) error { +func resourceAwsRDSClusterRoleAssociationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn dbClusterIdentifier := d.Get("db_cluster_identifier").(string) @@ -75,10 +75,10 @@ func resourceAwsDbClusterRoleAssociationCreate(d *schema.ResourceData, meta inte return fmt.Errorf("error waiting for RDS DB Cluster (%s) IAM Role (%s) association: %s", dbClusterIdentifier, roleArn, err) } - return resourceAwsDbClusterRoleAssociationRead(d, meta) + return resourceAwsRDSClusterRoleAssociationRead(d, meta) } -func resourceAwsDbClusterRoleAssociationRead(d *schema.ResourceData, meta interface{}) error { +func resourceAwsRDSClusterRoleAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn dbClusterIdentifier, roleArn, err := resourceAwsDbClusterRoleAssociationDecodeID(d.Id()) @@ -112,7 +112,7 @@ func resourceAwsDbClusterRoleAssociationRead(d *schema.ResourceData, meta interf return nil } -func resourceAwsDbClusterRoleAssociationDelete(d *schema.ResourceData, meta interface{}) error { +func resourceAwsRDSClusterRoleAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn dbClusterIdentifier, roleArn, err := resourceAwsDbClusterRoleAssociationDecodeID(d.Id()) diff --git a/aws/resource_aws_db_cluster_role_association_test.go b/aws/resource_aws_rds_cluster_role_association_test.go similarity index 68% rename from aws/resource_aws_db_cluster_role_association_test.go rename to aws/resource_aws_rds_cluster_role_association_test.go index 93b1cb455cd8..aeb904b1adb1 100644 --- a/aws/resource_aws_db_cluster_role_association_test.go +++ b/aws/resource_aws_rds_cluster_role_association_test.go @@ -11,23 +11,23 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func TestAccAWSDbClusterRoleAssociation_basic(t *testing.T) { - var dbClusterRole1 rds.DBClusterRole +func TestAccAWSRDSClusterRoleAssociation_basic(t *testing.T) { + var dbClusterRole rds.DBClusterRole rName := acctest.RandomWithPrefix("tf-acc-test") dbClusterResourceName := "aws_rds_cluster.test" iamRoleResourceName := "aws_iam_role.test" - resourceName := "aws_db_cluster_role_association.test" + resourceName := "aws_rds_cluster_role_association.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), Providers: testAccProviders, - CheckDestroy: testAccCheckAWSDbClusterRoleAssociationDestroy, + CheckDestroy: testAccCheckAWSRDSClusterRoleAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSDbClusterRoleAssociationConfig(rName), + Config: testAccAWSRDSClusterRoleAssociationConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSDbClusterRoleAssociationExists(resourceName, &dbClusterRole1), + testAccCheckAWSRDSClusterRoleAssociationExists(resourceName, &dbClusterRole), resource.TestCheckResourceAttrPair(resourceName, "db_cluster_identifier", dbClusterResourceName, "id"), resource.TestCheckResourceAttr(resourceName, "feature_name", "s3Import"), resource.TestCheckResourceAttrPair(resourceName, "role_arn", iamRoleResourceName, "arn"), @@ -42,25 +42,22 @@ func TestAccAWSDbClusterRoleAssociation_basic(t *testing.T) { }) } -func TestAccAWSDbClusterRoleAssociation_disappears(t *testing.T) { - var dbCluster1 rds.DBCluster - var dbClusterRole1 rds.DBClusterRole +func TestAccAWSRDSClusterRoleAssociation_disappears(t *testing.T) { + var dbClusterRole rds.DBClusterRole rName := acctest.RandomWithPrefix("tf-acc-test") - dbClusterResourceName := "aws_rds_cluster.test" - resourceName := "aws_db_cluster_role_association.test" + resourceName := "aws_rds_cluster_role_association.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), Providers: testAccProviders, - CheckDestroy: testAccCheckAWSDbClusterRoleAssociationDestroy, + CheckDestroy: testAccCheckAWSRDSClusterRoleAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSDbClusterRoleAssociationConfig(rName), + Config: testAccAWSRDSClusterRoleAssociationConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSClusterExists(dbClusterResourceName, &dbCluster1), - testAccCheckAWSDbClusterRoleAssociationExists(resourceName, &dbClusterRole1), - testAccCheckAWSDbClusterRoleAssociationDisappears(&dbCluster1, &dbClusterRole1), + testAccCheckAWSRDSClusterRoleAssociationExists(resourceName, &dbClusterRole), + testAccCheckResourceDisappears(testAccProvider, resourceAwsRDSClusterRoleAssociation(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -68,7 +65,7 @@ func TestAccAWSDbClusterRoleAssociation_disappears(t *testing.T) { }) } -func testAccCheckAWSDbClusterRoleAssociationExists(resourceName string, dbClusterRole *rds.DBClusterRole) resource.TestCheckFunc { +func testAccCheckAWSRDSClusterRoleAssociationExists(resourceName string, dbClusterRole *rds.DBClusterRole) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -104,7 +101,7 @@ func testAccCheckAWSDbClusterRoleAssociationExists(resourceName string, dbCluste } } -func testAccCheckAWSDbClusterRoleAssociationDestroy(s *terraform.State) error { +func testAccCheckAWSRDSClusterRoleAssociationDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).rdsconn for _, rs := range s.RootModule().Resources { @@ -138,27 +135,7 @@ func testAccCheckAWSDbClusterRoleAssociationDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSDbClusterRoleAssociationDisappears(dbCluster *rds.DBCluster, dbClusterRole *rds.DBClusterRole) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).rdsconn - - input := &rds.RemoveRoleFromDBClusterInput{ - DBClusterIdentifier: dbCluster.DBClusterIdentifier, - FeatureName: dbClusterRole.FeatureName, - RoleArn: dbClusterRole.RoleArn, - } - - _, err := conn.RemoveRoleFromDBCluster(input) - - if err != nil { - return err - } - - return waitForRdsDbClusterRoleDisassociation(conn, aws.StringValue(dbCluster.DBClusterIdentifier), aws.StringValue(dbClusterRole.RoleArn)) - } -} - -func testAccAWSDbClusterRoleAssociationConfig(rName string) string { +func testAccAWSRDSClusterRoleAssociationConfig(rName string) string { return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(` data "aws_iam_policy_document" "rds_assume_role_policy" { statement { @@ -189,7 +166,7 @@ resource "aws_rds_cluster" "test" { skip_final_snapshot = true } -resource "aws_db_cluster_role_association" "test" { +resource "aws_rds_cluster_role_association" "test" { db_cluster_identifier = aws_rds_cluster.test.id feature_name = "s3Import" role_arn = aws_iam_role.test.arn diff --git a/website/docs/r/db_cluster_role_association.html.markdown b/website/docs/r/rds_cluster_role_association.html.markdown similarity index 73% rename from website/docs/r/db_cluster_role_association.html.markdown rename to website/docs/r/rds_cluster_role_association.html.markdown index 2845c9d6821a..8fbe9d16c87c 100644 --- a/website/docs/r/db_cluster_role_association.html.markdown +++ b/website/docs/r/rds_cluster_role_association.html.markdown @@ -1,12 +1,12 @@ --- subcategory: "RDS" layout: "aws" -page_title: "AWS: aws_db_cluster_role_association" +page_title: "AWS: aws_rds_cluster_role_association" description: |- Manages a RDS DB Cluster association with an IAM Role. --- -# Resource: aws_db_cluster_role_association +# Resource: aws_rds_cluster_role_association Manages a RDS DB Cluster association with an IAM Role. Example use cases: @@ -16,10 +16,10 @@ Manages a RDS DB Cluster association with an IAM Role. Example use cases: ## Example Usage ```terraform -resource "aws_db_cluster_role_association" "example" { - db_cluster_identifier = "${aws_rds_cluster.example.id}" +resource "aws_rds_cluster_role_association" "example" { + db_cluster_identifier = aws_rds_cluster.example.id feature_name = "S3_INTEGRATION" - role_arn = "${aws_iam_role.example.id}" + role_arn = aws_iam_role.example.id } ``` @@ -39,8 +39,8 @@ In addition to all arguments above, the following attributes are exported: ## Import -`aws_db_cluster_role_association` can be imported using the DB Cluster Identifier and IAM Role ARN separated by a comma (`,`), e.g. +`aws_rds_cluster_role_association` can be imported using the DB Cluster Identifier and IAM Role ARN separated by a comma (`,`), e.g. ``` -$ terraform import aws_db_cluster_role_association.example my-db-cluster,arn:aws:iam::123456789012:role/my-role +$ terraform import aws_rds_cluster_role_association.example my-db-cluster,arn:aws:iam::123456789012:role/my-role ``` From 8057b4e80f92650f2d3e4e38e18bfcc51449a918 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 6 Jul 2021 09:55:00 -0400 Subject: [PATCH 0953/1208] Add CHANGELOG entry. --- .changelog/12370.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/12370.txt diff --git a/.changelog/12370.txt b/.changelog/12370.txt new file mode 100644 index 000000000000..82be242611fd --- /dev/null +++ b/.changelog/12370.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_rds_cluster_role_association +``` \ No newline at end of file From d623472f416b4c6d72f13d70e8fbd3d7f0b98923 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 6 Jul 2021 10:49:34 -0400 Subject: [PATCH 0954/1208] Use internal finder and waiter packages. --- aws/internal/service/rds/enum.go | 7 + aws/internal/service/rds/finder/finder.go | 48 +++++ aws/internal/service/rds/id.go | 19 ++ aws/internal/service/rds/waiter/status.go | 17 ++ aws/internal/service/rds/waiter/waiter.go | 38 ++++ ...source_aws_rds_cluster_role_association.go | 186 ++++-------------- ...e_aws_rds_cluster_role_association_test.go | 38 ++-- 7 files changed, 178 insertions(+), 175 deletions(-) create mode 100644 aws/internal/service/rds/enum.go diff --git a/aws/internal/service/rds/enum.go b/aws/internal/service/rds/enum.go new file mode 100644 index 000000000000..84531413bf2d --- /dev/null +++ b/aws/internal/service/rds/enum.go @@ -0,0 +1,7 @@ +package rds + +const ( + DBClusterRoleStatusActive = "ACTIVE" + DBClusterRoleStatusDeleted = "DELETED" + DBClusterRoleStatusPending = "PENDING" +) diff --git a/aws/internal/service/rds/finder/finder.go b/aws/internal/service/rds/finder/finder.go index 8ef227f70998..76a5f33675d2 100644 --- a/aws/internal/service/rds/finder/finder.go +++ b/aws/internal/service/rds/finder/finder.go @@ -3,6 +3,8 @@ package finder import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" tfrds "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds" ) @@ -63,3 +65,49 @@ func DBProxyEndpoint(conn *rds.RDS, id string) (*rds.DBProxyEndpoint, error) { return dbProxyEndpoint, err } + +func DBClusterRoleByDBClusterIDAndRoleARN(conn *rds.RDS, dbClusterID, roleARN string) (*rds.DBClusterRole, error) { + dbCluster, err := DBClusterByID(conn, dbClusterID) + + if err != nil { + return nil, err + } + + for _, associatedRole := range dbCluster.AssociatedRoles { + if aws.StringValue(associatedRole.RoleArn) == roleARN { + if status := aws.StringValue(associatedRole.Status); status == tfrds.DBClusterRoleStatusDeleted { + return nil, &resource.NotFoundError{ + Message: status, + } + } + + return associatedRole, nil + } + } + + return nil, &resource.NotFoundError{} +} + +func DBClusterByID(conn *rds.RDS, id string) (*rds.DBCluster, error) { + input := &rds.DescribeDBClustersInput{ + DBClusterIdentifier: aws.String(id), + } + + output, err := conn.DescribeDBClusters(input) + + if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBClusterNotFoundFault) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if output == nil || len(output.DBClusters) == 0 || output.DBClusters[0] == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.DBClusters[0], nil +} diff --git a/aws/internal/service/rds/id.go b/aws/internal/service/rds/id.go index f8a8250f33a4..b0ac3c52bb4e 100644 --- a/aws/internal/service/rds/id.go +++ b/aws/internal/service/rds/id.go @@ -12,3 +12,22 @@ func ResourceAwsDbProxyEndpointParseID(id string) (string, string, error) { } return idParts[0], idParts[1], nil } + +const dbClusterRoleAssociationResourceIDSeparator = "," + +func DBClusterRoleAssociationCreateResourceID(dbClusterID, roleARN string) string { + parts := []string{dbClusterID, roleARN} + id := strings.Join(parts, dbClusterRoleAssociationResourceIDSeparator) + + return id +} + +func DBClusterRoleAssociationParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, dbClusterRoleAssociationResourceIDSeparator) + + if len(parts) == 2 && parts[0] != "" && parts[1] != "" { + return parts[0], parts[1], nil + } + + return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected DBCLUSTERID%[2]sROLEARN", id, dbClusterRoleAssociationResourceIDSeparator) +} diff --git a/aws/internal/service/rds/waiter/status.go b/aws/internal/service/rds/waiter/status.go index 59fa5e5b5e41..870f1b58e8e5 100644 --- a/aws/internal/service/rds/waiter/status.go +++ b/aws/internal/service/rds/waiter/status.go @@ -5,6 +5,7 @@ import ( "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -58,3 +59,19 @@ func DBProxyEndpointStatus(conn *rds.RDS, id string) resource.StateRefreshFunc { return output, aws.StringValue(output.Status), nil } } + +func DBClusterRoleStatus(conn *rds.RDS, dbClusterID, roleARN string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.DBClusterRoleByDBClusterIDAndRoleARN(conn, dbClusterID, roleARN) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} diff --git a/aws/internal/service/rds/waiter/waiter.go b/aws/internal/service/rds/waiter/waiter.go index 2e80027be93b..d3ad5da52d03 100644 --- a/aws/internal/service/rds/waiter/waiter.go +++ b/aws/internal/service/rds/waiter/waiter.go @@ -5,12 +5,16 @@ import ( "github.com/aws/aws-sdk-go/service/rds" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + tfrds "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds" ) const ( // Maximum amount of time to wait for an EventSubscription to return Deleted EventSubscriptionDeletedTimeout = 10 * time.Minute RdsClusterInitiateUpgradeTimeout = 5 * time.Minute + + DBClusterRoleAssociationCreatedTimeout = 5 * time.Minute + DBClusterRoleAssociationDeletedTimeout = 5 * time.Minute ) // EventSubscriptionDeleted waits for a EventSubscription to return Deleted @@ -69,3 +73,37 @@ func DBProxyEndpointDeleted(conn *rds.RDS, id string, timeout time.Duration) (*r return nil, err } + +func DBClusterRoleAssociationCreated(conn *rds.RDS, dbClusterID, roleARN string) (*rds.DBClusterRole, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{tfrds.DBClusterRoleStatusPending}, + Target: []string{tfrds.DBClusterRoleStatusActive}, + Refresh: DBClusterRoleStatus(conn, dbClusterID, roleARN), + Timeout: DBClusterRoleAssociationCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*rds.DBClusterRole); ok { + return output, err + } + + return nil, err +} + +func DBClusterRoleAssociationDeleted(conn *rds.RDS, dbClusterID, roleARN string) (*rds.DBClusterRole, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{tfrds.DBClusterRoleStatusActive, tfrds.DBClusterRoleStatusPending}, + Target: []string{}, + Refresh: DBClusterRoleStatus(conn, dbClusterID, roleARN), + Timeout: DBClusterRoleAssociationDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*rds.DBClusterRole); ok { + return output, err + } + + return nil, err +} diff --git a/aws/resource_aws_rds_cluster_role_association.go b/aws/resource_aws_rds_cluster_role_association.go index dfae74a59ec5..322cdae4422c 100644 --- a/aws/resource_aws_rds_cluster_role_association.go +++ b/aws/resource_aws_rds_cluster_role_association.go @@ -3,20 +3,15 @@ package aws import ( "fmt" "log" - "strings" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -// Constants not currently provided by the AWS Go SDK -const ( - rdsDbClusterRoleStatusActive = "ACTIVE" - rdsDbClusterRoleStatusDeleted = "DELETED" - rdsDbClusterRoleStatusPending = "PENDING" + tfrds "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsRDSClusterRoleAssociation() *schema.Resource { @@ -53,26 +48,27 @@ func resourceAwsRDSClusterRoleAssociation() *schema.Resource { func resourceAwsRDSClusterRoleAssociationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn - dbClusterIdentifier := d.Get("db_cluster_identifier").(string) - roleArn := d.Get("role_arn").(string) - + dbClusterID := d.Get("db_cluster_identifier").(string) + roleARN := d.Get("role_arn").(string) input := &rds.AddRoleToDBClusterInput{ - DBClusterIdentifier: aws.String(dbClusterIdentifier), + DBClusterIdentifier: aws.String(dbClusterID), FeatureName: aws.String(d.Get("feature_name").(string)), - RoleArn: aws.String(roleArn), + RoleArn: aws.String(roleARN), } - log.Printf("[DEBUG] RDS DB Cluster (%s) IAM Role associating: %s", dbClusterIdentifier, roleArn) + log.Printf("[DEBUG] Creating RDS DB Cluster IAM Role Association: %s", input) _, err := conn.AddRoleToDBCluster(input) if err != nil { - return fmt.Errorf("error associating RDS DB Cluster (%s) IAM Role (%s): %s", dbClusterIdentifier, roleArn, err) + return fmt.Errorf("error creating RDS DB Cluster (%s) IAM Role (%s) Association: %w", dbClusterID, roleARN, err) } - d.SetId(fmt.Sprintf("%s,%s", dbClusterIdentifier, roleArn)) + d.SetId(tfrds.DBClusterRoleAssociationCreateResourceID(dbClusterID, roleARN)) + + _, err = waiter.DBClusterRoleAssociationCreated(conn, dbClusterID, roleARN) - if err := waitForRdsDbClusterRoleAssociation(conn, dbClusterIdentifier, roleArn); err != nil { - return fmt.Errorf("error waiting for RDS DB Cluster (%s) IAM Role (%s) association: %s", dbClusterIdentifier, roleArn, err) + if err != nil { + return fmt.Errorf("error waiting for RDS DB Cluster (%s) IAM Role (%s) Association to create: %w", dbClusterID, roleARN, err) } return resourceAwsRDSClusterRoleAssociationRead(d, meta) @@ -81,33 +77,27 @@ func resourceAwsRDSClusterRoleAssociationCreate(d *schema.ResourceData, meta int func resourceAwsRDSClusterRoleAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn - dbClusterIdentifier, roleArn, err := resourceAwsDbClusterRoleAssociationDecodeID(d.Id()) + dbClusterID, roleARN, err := tfrds.DBClusterRoleAssociationParseResourceID(d.Id()) if err != nil { - return fmt.Errorf("error reading resource ID: %s", err) + return fmt.Errorf("error parsing RDS DB Cluster IAM Role Association ID: %s", err) } - dbClusterRole, err := rdsDescribeDbClusterRole(conn, dbClusterIdentifier, roleArn) + output, err := finder.DBClusterRoleByDBClusterIDAndRoleARN(conn, dbClusterID, roleARN) - if isAWSErr(err, rds.ErrCodeDBClusterNotFoundFault, "") { - log.Printf("[WARN] RDS DB Cluster (%s) not found, removing from state", dbClusterIdentifier) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] RDS DB Cluster (%s) IAM Role (%s) Association not found, removing from state", dbClusterID, roleARN) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error reading RDS DB Cluster (%s) IAM Role (%s) association: %s", dbClusterIdentifier, roleArn, err) + return fmt.Errorf("error reading RDS DB Cluster (%s) IAM Role (%s) Association: %w", dbClusterID, roleARN, err) } - if dbClusterRole == nil { - log.Printf("[WARN] RDS DB Cluster (%s) IAM Role (%s) association not found, removing from state", dbClusterIdentifier, roleArn) - d.SetId("") - return nil - } - - d.Set("db_cluster_identifier", dbClusterIdentifier) - d.Set("feature_name", dbClusterRole.FeatureName) - d.Set("role_arn", dbClusterRole.RoleArn) + d.Set("db_cluster_identifier", dbClusterID) + d.Set("feature_name", output.FeatureName) + d.Set("role_arn", output.RoleArn) return nil } @@ -115,140 +105,34 @@ func resourceAwsRDSClusterRoleAssociationRead(d *schema.ResourceData, meta inter func resourceAwsRDSClusterRoleAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn - dbClusterIdentifier, roleArn, err := resourceAwsDbClusterRoleAssociationDecodeID(d.Id()) + dbClusterID, roleARN, err := tfrds.DBClusterRoleAssociationParseResourceID(d.Id()) if err != nil { - return fmt.Errorf("error reading resource ID: %s", err) + return fmt.Errorf("error parsing RDS DB Cluster IAM Role Association ID: %s", err) } input := &rds.RemoveRoleFromDBClusterInput{ - DBClusterIdentifier: aws.String(dbClusterIdentifier), + DBClusterIdentifier: aws.String(dbClusterID), FeatureName: aws.String(d.Get("feature_name").(string)), - RoleArn: aws.String(roleArn), + RoleArn: aws.String(roleARN), } - log.Printf("[DEBUG] RDS DB Cluster (%s) IAM Role disassociating: %s", dbClusterIdentifier, roleArn) + log.Printf("[DEBUG] Deleting RDS DB Cluster IAM Role Association: %s", d.Id()) _, err = conn.RemoveRoleFromDBCluster(input) - if isAWSErr(err, rds.ErrCodeDBClusterNotFoundFault, "") { - return nil - } - - if isAWSErr(err, rds.ErrCodeDBClusterRoleNotFoundFault, "") { + if tfawserr.ErrCodeEquals(err, rds.ErrCodeDBClusterNotFoundFault) || tfawserr.ErrCodeEquals(err, rds.ErrCodeDBClusterRoleNotFoundFault) { return nil } if err != nil { - return fmt.Errorf("error disassociating RDS DB Cluster (%s) IAM Role (%s): %s", dbClusterIdentifier, roleArn, err) - } - - if err := waitForRdsDbClusterRoleDisassociation(conn, dbClusterIdentifier, roleArn); err != nil { - return fmt.Errorf("error waiting for RDS DB Cluster (%s) IAM Role (%s) disassociation: %s", dbClusterIdentifier, roleArn, err) + return fmt.Errorf("error deleting RDS DB Cluster (%s) IAM Role (%s) Association: %w", dbClusterID, roleARN, err) } - return nil -} - -func resourceAwsDbClusterRoleAssociationDecodeID(id string) (string, string, error) { - parts := strings.SplitN(id, ",", 2) - - if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return "", "", fmt.Errorf("unexpected format of ID (%s), expected DB-CLUSTER-ID,ROLE-ARN", id) - } - - return parts[0], parts[1], nil -} - -func rdsDescribeDbClusterRole(conn *rds.RDS, dbClusterIdentifier, roleArn string) (*rds.DBClusterRole, error) { - input := &rds.DescribeDBClustersInput{ - DBClusterIdentifier: aws.String(dbClusterIdentifier), - } - - log.Printf("[DEBUG] Describing RDS DB Cluster: %s", input) - output, err := conn.DescribeDBClusters(input) + _, err = waiter.DBClusterRoleAssociationDeleted(conn, dbClusterID, roleARN) if err != nil { - return nil, err - } - - var dbCluster *rds.DBCluster - - for _, outputDbCluster := range output.DBClusters { - if aws.StringValue(outputDbCluster.DBClusterIdentifier) == dbClusterIdentifier { - dbCluster = outputDbCluster - break - } - } - - if dbCluster == nil { - return nil, nil - } - - var dbClusterRole *rds.DBClusterRole - - for _, associatedRole := range dbCluster.AssociatedRoles { - if aws.StringValue(associatedRole.RoleArn) == roleArn { - dbClusterRole = associatedRole - break - } - } - - return dbClusterRole, nil -} - -func waitForRdsDbClusterRoleAssociation(conn *rds.RDS, dbClusterIdentifier, roleArn string) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{rdsDbClusterRoleStatusPending}, - Target: []string{rdsDbClusterRoleStatusActive}, - Refresh: func() (interface{}, string, error) { - dbClusterRole, err := rdsDescribeDbClusterRole(conn, dbClusterIdentifier, roleArn) - - if err != nil { - return nil, "", err - } - - return dbClusterRole, aws.StringValue(dbClusterRole.Status), nil - }, - Timeout: 5 * time.Minute, - Delay: 5 * time.Second, + return fmt.Errorf("error waiting for RDS DB Cluster (%s) IAM Role (%s) Association to delete: %w", dbClusterID, roleARN, err) } - log.Printf("[DEBUG] Waiting for RDS DB Cluster (%s) IAM Role association: %s", dbClusterIdentifier, roleArn) - _, err := stateConf.WaitForState() - - return err -} - -func waitForRdsDbClusterRoleDisassociation(conn *rds.RDS, dbClusterIdentifier, roleArn string) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{ - rdsDbClusterRoleStatusActive, - rdsDbClusterRoleStatusPending, - }, - Target: []string{rdsDbClusterRoleStatusDeleted}, - Refresh: func() (interface{}, string, error) { - dbClusterRole, err := rdsDescribeDbClusterRole(conn, dbClusterIdentifier, roleArn) - - if isAWSErr(err, rds.ErrCodeDBClusterNotFoundFault, "") { - return &rds.DBClusterRole{}, rdsDbClusterRoleStatusDeleted, nil - } - - if err != nil { - return nil, "", err - } - - if dbClusterRole != nil { - return dbClusterRole, aws.StringValue(dbClusterRole.Status), nil - } - - return &rds.DBClusterRole{}, rdsDbClusterRoleStatusDeleted, nil - }, - Timeout: 5 * time.Minute, - Delay: 5 * time.Second, - } - - log.Printf("[DEBUG] Waiting for RDS DB Cluster (%s) IAM Role disassociation: %s", dbClusterIdentifier, roleArn) - _, err := stateConf.WaitForState() - - return err + return nil } diff --git a/aws/resource_aws_rds_cluster_role_association_test.go b/aws/resource_aws_rds_cluster_role_association_test.go index aeb904b1adb1..988077e8c448 100644 --- a/aws/resource_aws_rds_cluster_role_association_test.go +++ b/aws/resource_aws_rds_cluster_role_association_test.go @@ -4,11 +4,13 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/rds" "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" + tfrds "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestAccAWSRDSClusterRoleAssociation_basic(t *testing.T) { @@ -65,37 +67,29 @@ func TestAccAWSRDSClusterRoleAssociation_disappears(t *testing.T) { }) } -func testAccCheckAWSRDSClusterRoleAssociationExists(resourceName string, dbClusterRole *rds.DBClusterRole) resource.TestCheckFunc { +func testAccCheckAWSRDSClusterRoleAssociationExists(resourceName string, v *rds.DBClusterRole) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { - return fmt.Errorf("Resource not found: %s", resourceName) + return fmt.Errorf("Not found: %s", resourceName) } - dbClusterIdentifier, roleArn, err := resourceAwsDbClusterRoleAssociationDecodeID(rs.Primary.ID) + dbClusterID, roleARN, err := tfrds.DBClusterRoleAssociationParseResourceID(rs.Primary.ID) if err != nil { - return fmt.Errorf("error reading resource ID: %s", err) + return err } conn := testAccProvider.Meta().(*AWSClient).rdsconn - role, err := rdsDescribeDbClusterRole(conn, dbClusterIdentifier, roleArn) + role, err := finder.DBClusterRoleByDBClusterIDAndRoleARN(conn, dbClusterID, roleARN) if err != nil { return err } - if role == nil { - return fmt.Errorf("RDS DB Cluster IAM Role Association not found") - } - - if aws.StringValue(role.Status) != "ACTIVE" { - return fmt.Errorf("RDS DB Cluster (%s) IAM Role (%s) association exists in non-ACTIVE (%s) state", dbClusterIdentifier, roleArn, aws.StringValue(role.Status)) - } - - *dbClusterRole = *role + *v = *role return nil } @@ -109,15 +103,15 @@ func testAccCheckAWSRDSClusterRoleAssociationDestroy(s *terraform.State) error { continue } - dbClusterIdentifier, roleArn, err := resourceAwsDbClusterRoleAssociationDecodeID(rs.Primary.ID) + dbClusterID, roleARN, err := tfrds.DBClusterRoleAssociationParseResourceID(rs.Primary.ID) if err != nil { - return fmt.Errorf("error reading resource ID: %s", err) + return err } - dbClusterRole, err := rdsDescribeDbClusterRole(conn, dbClusterIdentifier, roleArn) + _, err = finder.DBClusterRoleByDBClusterIDAndRoleARN(conn, dbClusterID, roleARN) - if isAWSErr(err, rds.ErrCodeDBClusterNotFoundFault, "") { + if tfresource.NotFound(err) { continue } @@ -125,11 +119,7 @@ func testAccCheckAWSRDSClusterRoleAssociationDestroy(s *terraform.State) error { return err } - if dbClusterRole == nil { - continue - } - - return fmt.Errorf("RDS DB Cluster (%s) IAM Role (%s) association still exists in non-deleted (%s) state", dbClusterIdentifier, roleArn, aws.StringValue(dbClusterRole.Status)) + return fmt.Errorf("RDS DB Cluster IAM Role Association %s still exists", rs.Primary.ID) } return nil From 9b61333318cb2bc3e5a38a2ba970444c319d494b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 6 Jul 2021 11:06:35 -0400 Subject: [PATCH 0955/1208] r/aws_rds_cluster_role_association: Additional acceptance tests. --- aws/internal/service/rds/finder/finder.go | 11 +++- aws/internal/service/rds/id.go | 12 ++--- aws/resource_aws_rds_cluster.go | 1 + ...source_aws_rds_cluster_role_association.go | 6 +-- ...e_aws_rds_cluster_role_association_test.go | 52 ++++++++++++++++++- 5 files changed, 70 insertions(+), 12 deletions(-) diff --git a/aws/internal/service/rds/finder/finder.go b/aws/internal/service/rds/finder/finder.go index 76a5f33675d2..a401d39b5b22 100644 --- a/aws/internal/service/rds/finder/finder.go +++ b/aws/internal/service/rds/finder/finder.go @@ -109,5 +109,14 @@ func DBClusterByID(conn *rds.RDS, id string) (*rds.DBCluster, error) { } } - return output.DBClusters[0], nil + dbCluster := output.DBClusters[0] + + // Eventual consistency check. + if aws.StringValue(dbCluster.DBClusterIdentifier) != id { + return nil, &resource.NotFoundError{ + LastRequest: input, + } + } + + return dbCluster, nil } diff --git a/aws/internal/service/rds/id.go b/aws/internal/service/rds/id.go index b0ac3c52bb4e..74e74c85784b 100644 --- a/aws/internal/service/rds/id.go +++ b/aws/internal/service/rds/id.go @@ -13,21 +13,21 @@ func ResourceAwsDbProxyEndpointParseID(id string) (string, string, error) { return idParts[0], idParts[1], nil } -const dbClusterRoleAssociationResourceIDSeparator = "," +const clusterRoleAssociationResourceIDSeparator = "," -func DBClusterRoleAssociationCreateResourceID(dbClusterID, roleARN string) string { +func ClusterRoleAssociationCreateResourceID(dbClusterID, roleARN string) string { parts := []string{dbClusterID, roleARN} - id := strings.Join(parts, dbClusterRoleAssociationResourceIDSeparator) + id := strings.Join(parts, clusterRoleAssociationResourceIDSeparator) return id } -func DBClusterRoleAssociationParseResourceID(id string) (string, string, error) { - parts := strings.Split(id, dbClusterRoleAssociationResourceIDSeparator) +func ClusterRoleAssociationParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, clusterRoleAssociationResourceIDSeparator) if len(parts) == 2 && parts[0] != "" && parts[1] != "" { return parts[0], parts[1], nil } - return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected DBCLUSTERID%[2]sROLEARN", id, dbClusterRoleAssociationResourceIDSeparator) + return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected DBCLUSTERID%[2]sROLEARN", id, clusterRoleAssociationResourceIDSeparator) } diff --git a/aws/resource_aws_rds_cluster.go b/aws/resource_aws_rds_cluster.go index bb54eb5533bb..7fbac5d135d1 100644 --- a/aws/resource_aws_rds_cluster.go +++ b/aws/resource_aws_rds_cluster.go @@ -415,6 +415,7 @@ func resourceAwsRDSCluster() *schema.Resource { "iam_roles": { Type: schema.TypeSet, Optional: true, + Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, Set: schema.HashString, }, diff --git a/aws/resource_aws_rds_cluster_role_association.go b/aws/resource_aws_rds_cluster_role_association.go index 322cdae4422c..a73fa2e7a179 100644 --- a/aws/resource_aws_rds_cluster_role_association.go +++ b/aws/resource_aws_rds_cluster_role_association.go @@ -63,7 +63,7 @@ func resourceAwsRDSClusterRoleAssociationCreate(d *schema.ResourceData, meta int return fmt.Errorf("error creating RDS DB Cluster (%s) IAM Role (%s) Association: %w", dbClusterID, roleARN, err) } - d.SetId(tfrds.DBClusterRoleAssociationCreateResourceID(dbClusterID, roleARN)) + d.SetId(tfrds.ClusterRoleAssociationCreateResourceID(dbClusterID, roleARN)) _, err = waiter.DBClusterRoleAssociationCreated(conn, dbClusterID, roleARN) @@ -77,7 +77,7 @@ func resourceAwsRDSClusterRoleAssociationCreate(d *schema.ResourceData, meta int func resourceAwsRDSClusterRoleAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn - dbClusterID, roleARN, err := tfrds.DBClusterRoleAssociationParseResourceID(d.Id()) + dbClusterID, roleARN, err := tfrds.ClusterRoleAssociationParseResourceID(d.Id()) if err != nil { return fmt.Errorf("error parsing RDS DB Cluster IAM Role Association ID: %s", err) @@ -105,7 +105,7 @@ func resourceAwsRDSClusterRoleAssociationRead(d *schema.ResourceData, meta inter func resourceAwsRDSClusterRoleAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).rdsconn - dbClusterID, roleARN, err := tfrds.DBClusterRoleAssociationParseResourceID(d.Id()) + dbClusterID, roleARN, err := tfrds.ClusterRoleAssociationParseResourceID(d.Id()) if err != nil { return fmt.Errorf("error parsing RDS DB Cluster IAM Role Association ID: %s", err) diff --git a/aws/resource_aws_rds_cluster_role_association_test.go b/aws/resource_aws_rds_cluster_role_association_test.go index 988077e8c448..71602b301509 100644 --- a/aws/resource_aws_rds_cluster_role_association_test.go +++ b/aws/resource_aws_rds_cluster_role_association_test.go @@ -67,6 +67,54 @@ func TestAccAWSRDSClusterRoleAssociation_disappears(t *testing.T) { }) } +func TestAccAWSRDSClusterRoleAssociation_disappears_cluster(t *testing.T) { + var dbClusterRole rds.DBClusterRole + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_rds_cluster_role_association.test" + clusterResourceName := "aws_rds_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRDSClusterRoleAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRDSClusterRoleAssociationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRDSClusterRoleAssociationExists(resourceName, &dbClusterRole), + testAccCheckResourceDisappears(testAccProvider, resourceAwsRDSCluster(), clusterResourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSRDSClusterRoleAssociation_disappears_role(t *testing.T) { + var dbClusterRole rds.DBClusterRole + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_rds_cluster_role_association.test" + roleResourceName := "aws_iam_role.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRDSClusterRoleAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRDSClusterRoleAssociationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRDSClusterRoleAssociationExists(resourceName, &dbClusterRole), + testAccCheckResourceDisappears(testAccProvider, resourceAwsIamRole(), roleResourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAWSRDSClusterRoleAssociationExists(resourceName string, v *rds.DBClusterRole) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -75,7 +123,7 @@ func testAccCheckAWSRDSClusterRoleAssociationExists(resourceName string, v *rds. return fmt.Errorf("Not found: %s", resourceName) } - dbClusterID, roleARN, err := tfrds.DBClusterRoleAssociationParseResourceID(rs.Primary.ID) + dbClusterID, roleARN, err := tfrds.ClusterRoleAssociationParseResourceID(rs.Primary.ID) if err != nil { return err @@ -103,7 +151,7 @@ func testAccCheckAWSRDSClusterRoleAssociationDestroy(s *terraform.State) error { continue } - dbClusterID, roleARN, err := tfrds.DBClusterRoleAssociationParseResourceID(rs.Primary.ID) + dbClusterID, roleARN, err := tfrds.ClusterRoleAssociationParseResourceID(rs.Primary.ID) if err != nil { return err From 7bd40b65afe076444940fdb892f1469570240002 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 6 Jul 2021 11:19:46 -0400 Subject: [PATCH 0956/1208] Documentation udpdate. Note that RDS Cluster IAM Role Associations can now be managed via either the aws_rds_cluster.iam_roles attribute or the aws_rds_cluster_role_association resource, not both. --- .changelog/12370.txt | 4 ++++ website/docs/r/rds_cluster.html.markdown | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/.changelog/12370.txt b/.changelog/12370.txt index 82be242611fd..9a39c9e4cb6f 100644 --- a/.changelog/12370.txt +++ b/.changelog/12370.txt @@ -1,3 +1,7 @@ ```release-note:new-resource aws_rds_cluster_role_association +``` + +```release-note:enhancement +aws_rds_cluster: Set `iam_roles` as Computed to prevent drift when the `aws_rds_cluster_role_association` resource is used ``` \ No newline at end of file diff --git a/website/docs/r/rds_cluster.html.markdown b/website/docs/r/rds_cluster.html.markdown index 82bd7cb7d4c8..31b3548087b4 100644 --- a/website/docs/r/rds_cluster.html.markdown +++ b/website/docs/r/rds_cluster.html.markdown @@ -28,6 +28,11 @@ for more information. ~> **Note:** All arguments including the username and password will be stored in the raw state as plain-text. [Read more about sensitive data in state](https://www.terraform.io/docs/state/sensitive-data.html). +~> **NOTE on RDS Clusters and RDS Cluster Role Associations:** Terraform provides both a standalone [RDS Cluster Role Association](rds_cluster_role_association.html) - (an association between an RDS Cluster and a single IAM Role) and +an RDS Cluster resource with `iam_roles` attributes. +Use one resource or the other to associate IAM Roles and RDS Clusters. +Not doing so will cause a conflict of associations and will result in the association being overwritten. + ## Example Usage ### Aurora MySQL 2.x (MySQL 5.7) From ef35c30c06fecdf98475cc4100822c4c806fd39b Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 6 Jul 2021 15:44:35 +0000 Subject: [PATCH 0957/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b7731a01b7e..daf1257a6f68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,14 @@ ## 3.49.0 (Unreleased) + +FEATURES: + +* **New Resource:** `aws_rds_cluster_role_association` ([#12370](https://github.com/hashicorp/terraform-provider-aws/issues/12370)) + +ENHANCEMENTS: + +* aws_rds_cluster: Set `iam_roles` as Computed to prevent drift when the `aws_rds_cluster_role_association` resource is used ([#12370](https://github.com/hashicorp/terraform-provider-aws/issues/12370)) +* resource/aws_transfer_server: Add `security_group_ids` argument to `endpoint_details` configuration block. ([#17539](https://github.com/hashicorp/terraform-provider-aws/issues/17539)) + ## 3.48.0 (July 02, 2021) FEATURES: From 8edd03acddbe6df19eee76341a03fb14cbc020ab Mon Sep 17 00:00:00 2001 From: kuritonasu <33165903+kuritonasu@users.noreply.github.com> Date: Wed, 7 Jul 2021 15:38:18 +0300 Subject: [PATCH 0958/1208] docs: removed duplicate example code snippet --- website/docs/r/transfer_server.html.markdown | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index 2b754ab8544e..b226803b975b 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -24,16 +24,6 @@ resource "aws_transfer_server" "example" { } ``` -### Basic - -```terraform -resource "aws_transfer_server" "example" { - tags = { - Name = "Example" - } -} -``` - ### Security Policy Name ```terraform From c7afaa8e68797b504b049e2a3256acd33ec694bf Mon Sep 17 00:00:00 2001 From: kuritonasu <33165903+kuritonasu@users.noreply.github.com> Date: Wed, 7 Jul 2021 16:10:37 +0300 Subject: [PATCH 0959/1208] docs: removed duplicate example code snippet (Security Policy Name) --- website/docs/r/transfer_server.html.markdown | 8 -------- 1 file changed, 8 deletions(-) diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index b226803b975b..c72fa091dc16 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -32,14 +32,6 @@ resource "aws_transfer_server" "example" { } ``` -### Security Policy Name - -```terraform -resource "aws_transfer_server" "example" { - security_policy_name = "TransferSecurityPolicy-2020-06" -} -``` - ### VPC Endpoint ```terraform From c2f28d02e8a2e480cb353d2fd12fadbb5b2fe372 Mon Sep 17 00:00:00 2001 From: Will Varney Date: Tue, 2 Mar 2021 10:29:00 +0000 Subject: [PATCH 0960/1208] New resource: aws_eks_identity_provider_config. This adds a new resource for associating an identity provider with an EKS cluster. This commit implements only the required fields. --- aws/provider.go | 1 + ...source_aws_eks_identity_provider_config.go | 312 ++++++++++++++++++ ...e_aws_eks_identity_provider_config_test.go | 276 ++++++++++++++++ 3 files changed, 589 insertions(+) create mode 100644 aws/resource_aws_eks_identity_provider_config.go create mode 100644 aws/resource_aws_eks_identity_provider_config_test.go diff --git a/aws/provider.go b/aws/provider.go index 284c667ae22c..8364ac2b7ccd 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -729,6 +729,7 @@ func Provider() *schema.Provider { "aws_eks_cluster": resourceAwsEksCluster(), "aws_eks_addon": resourceAwsEksAddon(), "aws_eks_fargate_profile": resourceAwsEksFargateProfile(), + "aws_eks_identity_provider_config": resourceAwsEksIdentityProviderConfig(), "aws_eks_node_group": resourceAwsEksNodeGroup(), "aws_elasticache_cluster": resourceAwsElasticacheCluster(), "aws_elasticache_global_replication_group": resourceAwsElasticacheGlobalReplicationGroup(), diff --git a/aws/resource_aws_eks_identity_provider_config.go b/aws/resource_aws_eks_identity_provider_config.go new file mode 100644 index 000000000000..49aa3cd94990 --- /dev/null +++ b/aws/resource_aws_eks_identity_provider_config.go @@ -0,0 +1,312 @@ +package aws + +import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/eks" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "log" + "strings" + "time" +) + +const typeOidc string = "oidc" + +func resourceAwsEksIdentityProviderConfig() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceAwsEksIdentityProviderConfigCreate, + ReadContext: resourceAwsEksIdentityProviderConfigRead, + DeleteContext: resourceAwsEksIdentityProviderConfigDelete, + + // TODO - Not sure if I can enable importing? + + // TODO - AWS is suggesting it can take 15-20 minutes to associate an identity provider with EKS. Seeing `context deadline exceeded`. + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(25 * time.Minute), + Delete: schema.DefaultTimeout(25 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "cluster_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.NoZeroValues, + }, + // TODO - Do I set ForceNew here to true as it doesn't look like you can update a identity provider config + "oidc": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "client_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.NoZeroValues, + }, + "identity_provider_config_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.NoZeroValues, + }, + "issuer_url": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + }, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsEksIdentityProviderConfigCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).eksconn + clusterName := d.Get("cluster_name").(string) + + //TODO - Should I break away from the aws sdk api and move the name outside of the oidc map? + configName, oidcRequest := expandEksOidcIdentityProviderConfigRequest(d.Get("oidc").([]interface{})) + + id := fmt.Sprintf("%s:%s", clusterName, configName) + + input := &eks.AssociateIdentityProviderConfigInput{ + ClientRequestToken: aws.String(resource.UniqueId()), + ClusterName: aws.String(clusterName), + Oidc: oidcRequest, + } + + //if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { + // input.Tags = keyvaluetags.New(v).IgnoreAws().EksTags() + //} + + _, err := conn.AssociateIdentityProviderConfig(input) + if err != nil { + return diag.Errorf("error associating EKS Identity Provider Config (%s): %s", id, err) + } + + d.SetId(id) + + stateConf := resource.StateChangeConf{ + Pending: []string{eks.ConfigStatusCreating}, + Target: []string{eks.ConfigStatusActive}, + Timeout: d.Timeout(schema.TimeoutCreate), + Refresh: refreshEksIdentityProviderConfigStatus(conn, clusterName, &eks.IdentityProviderConfig{ + Name: aws.String(configName), + Type: aws.String(typeOidc), + }), + } + + if _, err := stateConf.WaitForStateContext(ctx); err != nil { + return diag.Errorf("error waiting for EKS Identity Provider Config (%s) association: %s", d.Id(), err) + } + + return resourceAwsEksIdentityProviderConfigRead(ctx, d, meta) +} + +func resourceAwsEksIdentityProviderConfigRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).eksconn + //ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + clusterName, configName, err := resourceAwsEksIdentityProviderConfigParseId(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + input := &eks.DescribeIdentityProviderConfigInput{ + ClusterName: aws.String(clusterName), + IdentityProviderConfig: &eks.IdentityProviderConfig{ + Name: aws.String(configName), + Type: aws.String(typeOidc), + }, + } + + output, err := conn.DescribeIdentityProviderConfigWithContext(ctx, input) + + if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] EKS Identity Provider Config (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return diag.Errorf("error reading EKS Identity Provider Config (%s): %s", d.Id(), err) + } + + config := output.IdentityProviderConfig + + if config == nil { + log.Printf("[WARN] EKS Identity Provider Config (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + // TODO - Do I need the nil check here? + if config.Oidc == nil { + log.Printf("[WARN] EKS OIDC Identity Provider Config (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + d.Set("cluster_name", clusterName) + + if err := d.Set("oidc", flattenEksOidcIdentityProviderConfig(config.Oidc)); err != nil { + return diag.Errorf("error setting oidc: %s", err) + } + + d.Set("status", config.Oidc.Status) + + //if err := d.Set("tags", keyvaluetags.EksKeyValueTags(fargateProfile.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + // return fmt.Errorf("error setting tags: %s", err) + //} + + return nil +} + +func resourceAwsEksIdentityProviderConfigDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).eksconn + + clusterName, configName, err := resourceAwsEksIdentityProviderConfigParseId(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + config := &eks.IdentityProviderConfig{ + Name: aws.String(configName), + Type: aws.String(typeOidc), + } + + log.Printf("[DEBUG] Disassociating EKS Identity Provider Config: %s", d.Id()) + input := &eks.DisassociateIdentityProviderConfigInput{ + ClusterName: aws.String(clusterName), + IdentityProviderConfig: config, + } + + _, err = conn.DisassociateIdentityProviderConfigWithContext(ctx, input) + + if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + return nil + } + + // TODO - if we timeout on the association whilst acc testing this will fail with: + // { + // RespMetadata: { + // StatusCode: 400, + // RequestID: "abf3f851-04e7-4d66-867e-f871897efbb3" + // }, + // ClusterName: "tf-acc-test-387064423719985885", + // Message_: "Identity provider config is not associated with cluster tf-acc-test-387064423719985885" + // } + if err != nil { + return diag.Errorf("error disassociating EKS Identity Provider Config (%s): %s", d.Id(), err) + } + + if err := waitForEksIdentityProviderConfigDisassociation(ctx, conn, clusterName, config, d.Timeout(schema.TimeoutDelete)); err != nil { + return diag.Errorf("error waiting for EKS Identity Provider Config (%s) disassociation: %s", d.Id(), err) + } + + return nil +} + +func refreshEksIdentityProviderConfigStatus(conn *eks.EKS, clusterName string, config *eks.IdentityProviderConfig) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &eks.DescribeIdentityProviderConfigInput{ + ClusterName: aws.String(clusterName), + IdentityProviderConfig: config, + } + + output, err := conn.DescribeIdentityProviderConfig(input) + + if err != nil { + return "", "", err + } + + identityProviderConfig := output.IdentityProviderConfig + + // TODO: not sure about the use of StringValue here. + if identityProviderConfig == nil { + return identityProviderConfig, "", fmt.Errorf("EKS Identity Provider Config (%s:%s) missing", clusterName, aws.StringValue(config.Name)) + } + + oidc := identityProviderConfig.Oidc + + // TODO: Should I be checking for nil on OIDC here too? + if oidc == nil { + return identityProviderConfig, "", fmt.Errorf("EKS OIDC Identity Provider Config (%s:%s) missing", clusterName, aws.StringValue(config.Name)) + } + + return identityProviderConfig, aws.StringValue(oidc.Status), nil + } +} + +func waitForEksIdentityProviderConfigDisassociation(ctx context.Context, conn *eks.EKS, clusterName string, config *eks.IdentityProviderConfig, timeout time.Duration) error { + stateConf := resource.StateChangeConf{ + Pending: []string{ + eks.ConfigStatusActive, + eks.ConfigStatusDeleting, + }, + Target: []string{""}, + Timeout: timeout, + Refresh: refreshEksIdentityProviderConfigStatus(conn, clusterName, config), + } + _, err := stateConf.WaitForStateContext(ctx) + + if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + return nil + } + + return err +} + +func resourceAwsEksIdentityProviderConfigParseId(id string) (string, string, error) { + parts := strings.Split(id, ":") + + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("unexpected format of ID (%s), expected cluster-name:identity-provider-config-name", id) + } + + return parts[0], parts[1], nil +} + +func expandEksOidcIdentityProviderConfigRequest(l []interface{}) (string, *eks.OidcIdentityProviderConfigRequest) { + if len(l) == 0 { + return "", nil + } + + m := l[0].(map[string]interface{}) + + configName := m["identity_provider_config_name"].(string) + oidcIdentityProviderConfigRequest := &eks.OidcIdentityProviderConfigRequest{ + ClientId: aws.String(m["client_id"].(string)), + IdentityProviderConfigName: aws.String(configName), + IssuerUrl: aws.String(m["issuer_url"].(string)), + } + + return configName, oidcIdentityProviderConfigRequest +} + +func flattenEksOidcIdentityProviderConfig(config *eks.OidcIdentityProviderConfig) []map[string]interface{} { + if config == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "client_id": aws.StringValue(config.ClientId), + "identity_provider_config_name": aws.StringValue(config.IdentityProviderConfigName), + "issuer_url": aws.StringValue(config.IssuerUrl), + } + + return []map[string]interface{}{m} +} diff --git a/aws/resource_aws_eks_identity_provider_config_test.go b/aws/resource_aws_eks_identity_provider_config_test.go new file mode 100644 index 000000000000..7b1ccd189c8e --- /dev/null +++ b/aws/resource_aws_eks_identity_provider_config_test.go @@ -0,0 +1,276 @@ +package aws + +import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/eks" + "github.com/hashicorp/go-multierror" + "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" + "log" + "testing" + "time" +) + +func init() { + resource.AddTestSweepers("aws_eks_identity_provider_config", &resource.Sweeper{ + Name: "aws_eks_identity_provider_config", + F: testSweepEksIdentityProviderConfigs, + }) +} + +func testSweepEksIdentityProviderConfigs(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).eksconn + + var errors error + input := &eks.ListClustersInput{} + err = conn.ListClustersPages(input, func(page *eks.ListClustersOutput, lastPage bool) bool { + for _, cluster := range page.Clusters { + clusterName := aws.StringValue(cluster) + input := &eks.ListIdentityProviderConfigsInput{ + ClusterName: cluster, + } + err := conn.ListIdentityProviderConfigsPages(input, func(page *eks.ListIdentityProviderConfigsOutput, lastPage bool) bool { + for _, config := range page.IdentityProviderConfigs { + configName := aws.StringValue(config.Name) + log.Printf("[INFO] Disassociating Identity Provider Config %q", configName) + input := &eks.DisassociateIdentityProviderConfigInput{ + ClusterName: cluster, + IdentityProviderConfig: config, + } + _, err := conn.DisassociateIdentityProviderConfig(input) + + if err != nil && !isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + errors = multierror.Append(errors, fmt.Errorf("error disassociating Identity Provider Config %q: %w", configName, err)) + continue + } + + // TODO - Should I use context.Background here? + if err := waitForEksIdentityProviderConfigDisassociation(context.Background(), conn, clusterName, config, 10*time.Minute); err != nil { + errors = multierror.Append(errors, fmt.Errorf("error waiting for EKS Identity Provider Config %q disassociation: %w", configName, err)) + continue + } + } + return true + }) + if err != nil { + errors = multierror.Append(errors, fmt.Errorf("error listing Identity Provider Configs for EKS Cluster %s: %w", clusterName, err)) + } + } + + return true + }) + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping EKS Clusters sweep for %s: %s", region, err) + return errors // In case we have completed some pages, but had errors + } + if err != nil { + errors = multierror.Append(errors, fmt.Errorf("error retrieving EKS Clusters: %w", err)) + } + + return errors +} + +func TestAccAWSEksIdentityProviderConfig_basic(t *testing.T) { + var config eks.IdentityProviderConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + eksClusterResourceName := "aws_eks_cluster.test" + resourceName := "aws_eks_identity_provider_config.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksIdentityProviderConfigProviderConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + resource.TestCheckResourceAttrPair(resourceName, "cluster_name", eksClusterResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.identity_provider_config_name", rName), + resource.TestCheckResourceAttr(resourceName, "oidc.0.client_id", "test-url.apps.googleusercontent.com"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.issuer_url", "https://accounts.google.com/.well-known/openid-configuration"), + ), + }, + }, + }) +} + +func testAccCheckAWSEksIdentityProviderConfigExists(resourceName string, config *eks.IdentityProviderConfig) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No EKS Identity Profile Config is set") + } + + clusterName, configName, err := resourceAwsEksIdentityProviderConfigParseId(rs.Primary.ID) + if err != nil { + return err + } + + conn := testAccProvider.Meta().(*AWSClient).eksconn + + input := &eks.DescribeIdentityProviderConfigInput{ + ClusterName: aws.String(clusterName), + IdentityProviderConfig: &eks.IdentityProviderConfig{ + Name: aws.String(configName), + Type: aws.String(typeOidc), + }, + } + + output, err := conn.DescribeIdentityProviderConfig(input) + + if err != nil { + return err + } + + if output == nil || output.IdentityProviderConfig == nil { + return fmt.Errorf("EKS Identity Provider Config (%s) not found", rs.Primary.ID) + } + + if aws.StringValue(output.IdentityProviderConfig.Oidc.IdentityProviderConfigName) != configName { + return fmt.Errorf("EKS OIDC Identity Provider Config (%s) not found", rs.Primary.ID) + } + + if got, want := aws.StringValue(output.IdentityProviderConfig.Oidc.Status), eks.ConfigStatusActive; got != want { + return fmt.Errorf("EKS OIDC Identity Provider Config (%s) not in %s status, got: %s", rs.Primary.ID, want, got) + } + + *config = eks.IdentityProviderConfig{ + Name: output.IdentityProviderConfig.Oidc.IdentityProviderConfigName, + Type: aws.String(typeOidc), + } + + return nil + } +} + +// TODO - still needs some work +func testAccCheckAWSEksIdentityProviderConfigDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).eksconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_eks_identity_provider_config" { + continue + } + + clusterName, configName, err := resourceAwsEksIdentityProviderConfigParseId(rs.Primary.ID) + if err != nil { + return err + } + + input := &eks.DescribeIdentityProviderConfigInput{ + ClusterName: aws.String(clusterName), + IdentityProviderConfig: &eks.IdentityProviderConfig{ + Name: aws.String(configName), + Type: aws.String(typeOidc), + }, + } + + output, err := conn.DescribeIdentityProviderConfig(input) + + if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + continue + } + + if output != nil && output.IdentityProviderConfig != nil && aws.StringValue(output.IdentityProviderConfig.Oidc.IdentityProviderConfigName) == configName { + return fmt.Errorf("EKS Identity Provider Config (%s) still exists", rs.Primary.ID) + } + } + + return nil +} + +func testAccAWSEksIdentityProviderConfigBase(rName string) string { + return fmt.Sprintf(` +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +data "aws_partition" "current" {} + +resource "aws_iam_role" "cluster" { + name = "%[1]s-cluster" + + assume_role_policy = jsonencode({ + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "eks.${data.aws_partition.current.dns_suffix}" + } + }] + Version = "2012-10-17" + }) +} + +resource "aws_iam_role_policy_attachment" "cluster-AmazonEKSClusterPolicy" { + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEKSClusterPolicy" + role = aws_iam_role.cluster.name +} + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + enable_dns_hostnames = true + enable_dns_support = true + + tags = { + Name = "tf-acc-test-eks-identity-provider-config" + "kubernetes.io/cluster/%[1]s" = "shared" + } +} + +resource "aws_subnet" "test" { + count = 2 + + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = "10.0.${count.index}.0/24" + vpc_id = aws_vpc.test.id + + tags = { + Name = "tf-acc-test-eks-identity-provider-config" + "kubernetes.io/cluster/%[1]s" = "shared" + } +} + +resource "aws_eks_cluster" "test" { + name = %[1]q + role_arn = aws_iam_role.cluster.arn + + vpc_config { + subnet_ids = aws_subnet.test[*].id + } + + depends_on = [aws_iam_role_policy_attachment.cluster-AmazonEKSClusterPolicy] +} +`, rName) +} + +func testAccAWSEksIdentityProviderConfigProviderConfigName(rName string) string { + return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` +resource "aws_eks_identity_provider_config" "test" { + cluster_name = aws_eks_cluster.test.name + oidc { + client_id = "test-url.apps.googleusercontent.com" + identity_provider_config_name = %[1]q + issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + } +} +`, rName) +} From 4a7b303c8db7c5aa1b6404b03e616439a2ccdb63 Mon Sep 17 00:00:00 2001 From: Will Varney Date: Tue, 2 Mar 2021 11:15:20 +0000 Subject: [PATCH 0961/1208] New resource: aws_eks_identity_provider_config. This adds a new resource for associating an identity provider with an EKS cluster. This commit adds a placeholder for the changelog entry and initial documentation for the resource. --- .changelog/pending.txt | 3 + go.sum | 5 ++ ...eks_identity_provider_config.html.markdown | 69 +++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 .changelog/pending.txt create mode 100644 website/docs/r/eks_identity_provider_config.html.markdown diff --git a/.changelog/pending.txt b/.changelog/pending.txt new file mode 100644 index 000000000000..9b0b4cd67b69 --- /dev/null +++ b/.changelog/pending.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_eks_identity_provider_config +``` \ No newline at end of file diff --git a/go.sum b/go.sum index 009b6a2c58dd..15c3f8ef9683 100644 --- a/go.sum +++ b/go.sum @@ -50,6 +50,7 @@ github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U= github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= @@ -62,6 +63,7 @@ github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJE github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -95,7 +97,9 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= @@ -294,6 +298,7 @@ github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/website/docs/r/eks_identity_provider_config.html.markdown b/website/docs/r/eks_identity_provider_config.html.markdown new file mode 100644 index 000000000000..be71227d6833 --- /dev/null +++ b/website/docs/r/eks_identity_provider_config.html.markdown @@ -0,0 +1,69 @@ +--- +subcategory: "EKS" +layout: "aws" +page_title: "AWS: aws_eks_identity_provider_config" +description: |- + Manages an EKS Identity Provider Configuration +--- + +# Resource: aws_eks_identity_provider_config + +Manages an EKS Identity Provider Configuration. + +## Example Usage + +```hcl +resource "aws_eks_identity_provider_config" "example" { + cluster_name = aws_eks_cluster.example.name + oidc { + client_id = "your client_id" + identity_provider_config_name = "example" + issuer_url = "your issuer_url" + } +} +``` + +## Argument Reference + +The following arguments are required: + +* `cluster_name` – Name of the EKS Cluster. +* `oidc` - Nested attribute containing [OpenID Connect](https://openid.net/connect/) identity provider information for the cluster. + * `client_id` – Client ID for the OpenID Connect identity provider. + * `identity_provider_config_name` – The name of the identity provider config. + * `issuer_url` - Issuer URL for the OpenID Connect identity provider. + +The following arguments are optional: + +* `tags` - (Optional) Key-value map of resource tags. + +### selector Configuration Block + +The following arguments are required: + +* `namespace` - (Required) Kubernetes namespace for selection. + +The following arguments are optional: + +* `labels` - (Optional) Key-value map of Kubernetes labels for selection. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: + +* `id` - EKS Cluster name and EKS Identity Provider Configuration name separated by a colon (`:`). +* `status` - Status of the EKS Identity Provider Configuration. + +## Timeouts + +`aws_eks_identity_provider_config` provides the following [Timeouts](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts) configuration options: + +* `create` - (Default `25 minutes`) How long to wait for the EKS Identity Provider Configuration to be associated. +* `delete` - (Default `25 minutes`) How long to wait for the EKS Identity Provider Configuration to be disassociated. + +## Import + +EKS Fargate Profiles can be imported using the `cluster_name` and `fargate_profile_name` separated by a colon (`:`), e.g. + +``` +$ terraform import aws_eks_identity_provider_config.my_identity_provider_config my_cluster:my_identity_provider_config +``` From 4ff23ac57bce5614ce4b31767f9767a3283a2fb0 Mon Sep 17 00:00:00 2001 From: Will Varney Date: Tue, 2 Mar 2021 12:47:56 +0000 Subject: [PATCH 0962/1208] New resource: aws_eks_identity_provider_config. This adds a new resource for associating an identity provider with an EKS cluster. This commit adds a the ability to import an existing identity provider config resource. --- aws/resource_aws_eks_identity_provider_config.go | 5 +++-- aws/resource_aws_eks_identity_provider_config_test.go | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_eks_identity_provider_config.go b/aws/resource_aws_eks_identity_provider_config.go index 49aa3cd94990..dfefa7b16c00 100644 --- a/aws/resource_aws_eks_identity_provider_config.go +++ b/aws/resource_aws_eks_identity_provider_config.go @@ -22,9 +22,10 @@ func resourceAwsEksIdentityProviderConfig() *schema.Resource { ReadContext: resourceAwsEksIdentityProviderConfigRead, DeleteContext: resourceAwsEksIdentityProviderConfigDelete, - // TODO - Not sure if I can enable importing? + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, - // TODO - AWS is suggesting it can take 15-20 minutes to associate an identity provider with EKS. Seeing `context deadline exceeded`. Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(25 * time.Minute), Delete: schema.DefaultTimeout(25 * time.Minute), diff --git a/aws/resource_aws_eks_identity_provider_config_test.go b/aws/resource_aws_eks_identity_provider_config_test.go index 7b1ccd189c8e..71c401f9d910 100644 --- a/aws/resource_aws_eks_identity_provider_config_test.go +++ b/aws/resource_aws_eks_identity_provider_config_test.go @@ -99,6 +99,11 @@ func TestAccAWSEksIdentityProviderConfig_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "oidc.0.issuer_url", "https://accounts.google.com/.well-known/openid-configuration"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } From fae1a31c18144a151fec9007ff21c3ca7ea0ef68 Mon Sep 17 00:00:00 2001 From: Will Varney Date: Tue, 2 Mar 2021 17:35:00 +0000 Subject: [PATCH 0963/1208] New resource: aws_eks_identity_provider_config. This adds a new resource for associating an identity provider with an EKS cluster. This commit adds a test for if the resource dissapears and handles an invalid request exception when the identity provider config is not associated to the specified cluster on delete. --- ...source_aws_eks_identity_provider_config.go | 13 ++---- ...e_aws_eks_identity_provider_config_test.go | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/aws/resource_aws_eks_identity_provider_config.go b/aws/resource_aws_eks_identity_provider_config.go index dfefa7b16c00..74d3f6d683c0 100644 --- a/aws/resource_aws_eks_identity_provider_config.go +++ b/aws/resource_aws_eks_identity_provider_config.go @@ -197,19 +197,12 @@ func resourceAwsEksIdentityProviderConfigDelete(ctx context.Context, d *schema.R _, err = conn.DisassociateIdentityProviderConfigWithContext(ctx, input) - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + // TODO - Is checking for the exception message too brittle? + if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") || + isAWSErr(err, eks.ErrCodeInvalidRequestException, "Identity provider config is not associated with cluster") { return nil } - // TODO - if we timeout on the association whilst acc testing this will fail with: - // { - // RespMetadata: { - // StatusCode: 400, - // RequestID: "abf3f851-04e7-4d66-867e-f871897efbb3" - // }, - // ClusterName: "tf-acc-test-387064423719985885", - // Message_: "Identity provider config is not associated with cluster tf-acc-test-387064423719985885" - // } if err != nil { return diag.Errorf("error disassociating EKS Identity Provider Config (%s): %s", d.Id(), err) } diff --git a/aws/resource_aws_eks_identity_provider_config_test.go b/aws/resource_aws_eks_identity_provider_config_test.go index 71c401f9d910..e702cd086feb 100644 --- a/aws/resource_aws_eks_identity_provider_config_test.go +++ b/aws/resource_aws_eks_identity_provider_config_test.go @@ -108,6 +108,28 @@ func TestAccAWSEksIdentityProviderConfig_basic(t *testing.T) { }) } +func TestAccAWSEksIdentityProviderConfig_disappears(t *testing.T) { + var config eks.IdentityProviderConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_eks_identity_provider_config.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksIdentityProviderConfigProviderConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + testAccCheckAWSEksIdentityProviderConfigDisappears(rName, &config), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckAWSEksIdentityProviderConfigExists(resourceName string, config *eks.IdentityProviderConfig) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -197,6 +219,29 @@ func testAccCheckAWSEksIdentityProviderConfigDestroy(s *terraform.State) error { return nil } +func testAccCheckAWSEksIdentityProviderConfigDisappears(clusterName string, config *eks.IdentityProviderConfig) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).eksconn + + input := &eks.DisassociateIdentityProviderConfigInput{ + ClusterName: aws.String(clusterName), + IdentityProviderConfig: config, + } + + _, err := conn.DisassociateIdentityProviderConfig(input) + + if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + return nil + } + + if err != nil { + return err + } + + return waitForEksIdentityProviderConfigDisassociation(context.Background(), conn, clusterName, config, 25*time.Minute) + } +} + func testAccAWSEksIdentityProviderConfigBase(rName string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { From ff36e80dd945299030b198e7d105e2f5529d5c91 Mon Sep 17 00:00:00 2001 From: Will Varney Date: Fri, 5 Mar 2021 18:07:34 +0000 Subject: [PATCH 0964/1208] New resource: aws_eks_identity_provider_config. This adds a new resource for associating an identity provider with an EKS cluster. This commit adds the optional fields to the resource and tests for them. It also adds tests for the validation on the schema. --- ...source_aws_eks_identity_provider_config.go | 93 +++++++- ...e_aws_eks_identity_provider_config_test.go | 207 +++++++++++++++++- ...eks_identity_provider_config.html.markdown | 18 +- 3 files changed, 294 insertions(+), 24 deletions(-) diff --git a/aws/resource_aws_eks_identity_provider_config.go b/aws/resource_aws_eks_identity_provider_config.go index 74d3f6d683c0..7a09591aced9 100644 --- a/aws/resource_aws_eks_identity_provider_config.go +++ b/aws/resource_aws_eks_identity_provider_config.go @@ -5,10 +5,12 @@ import ( "fmt" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" + "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" "log" "strings" "time" @@ -38,7 +40,6 @@ func resourceAwsEksIdentityProviderConfig() *schema.Resource { ForceNew: true, ValidateFunc: validation.NoZeroValues, }, - // TODO - Do I set ForceNew here to true as it doesn't look like you can update a identity provider config "oidc": { Type: schema.TypeList, Required: true, @@ -51,6 +52,18 @@ func resourceAwsEksIdentityProviderConfig() *schema.Resource { ForceNew: true, ValidateFunc: validation.NoZeroValues, }, + "groups_claim": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.NoZeroValues, + }, + "groups_prefix": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.NoZeroValues, + }, "identity_provider_config_name": { Type: schema.TypeString, Required: true, @@ -63,9 +76,35 @@ func resourceAwsEksIdentityProviderConfig() *schema.Resource { ForceNew: true, ValidateFunc: validation.IsURLWithHTTPS, }, + "required_claims": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + ValidateDiagFunc: all( + validation.MapKeyLenBetween(1, 63), + validation.MapValueLenBetween(1, 253), + ), + Elem: &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + }, + }, + "username_claim": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.NoZeroValues, + }, + "username_prefix": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.NoZeroValues, + }, }, }, }, + "tags": tagsSchemaForceNew(), "status": { Type: schema.TypeString, Computed: true, @@ -74,6 +113,16 @@ func resourceAwsEksIdentityProviderConfig() *schema.Resource { } } +func all(validators ...schema.SchemaValidateDiagFunc) schema.SchemaValidateDiagFunc { + return func(i interface{}, k cty.Path) diag.Diagnostics { + var diags diag.Diagnostics + for _, validator := range validators { + diags = append(diags, validator(i, k)...) + } + return diags + } +} + func resourceAwsEksIdentityProviderConfigCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).eksconn clusterName := d.Get("cluster_name").(string) @@ -89,9 +138,9 @@ func resourceAwsEksIdentityProviderConfigCreate(ctx context.Context, d *schema.R Oidc: oidcRequest, } - //if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { - // input.Tags = keyvaluetags.New(v).IgnoreAws().EksTags() - //} + if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { + input.Tags = keyvaluetags.New(v).IgnoreAws().EksTags() + } _, err := conn.AssociateIdentityProviderConfig(input) if err != nil { @@ -119,7 +168,7 @@ func resourceAwsEksIdentityProviderConfigCreate(ctx context.Context, d *schema.R func resourceAwsEksIdentityProviderConfigRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).eksconn - //ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig clusterName, configName, err := resourceAwsEksIdentityProviderConfigParseId(d.Id()) if err != nil { @@ -154,7 +203,6 @@ func resourceAwsEksIdentityProviderConfigRead(ctx context.Context, d *schema.Res return nil } - // TODO - Do I need the nil check here? if config.Oidc == nil { log.Printf("[WARN] EKS OIDC Identity Provider Config (%s) not found, removing from state", d.Id()) d.SetId("") @@ -169,9 +217,9 @@ func resourceAwsEksIdentityProviderConfigRead(ctx context.Context, d *schema.Res d.Set("status", config.Oidc.Status) - //if err := d.Set("tags", keyvaluetags.EksKeyValueTags(fargateProfile.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - // return fmt.Errorf("error setting tags: %s", err) - //} + if err := d.Set("tags", keyvaluetags.EksKeyValueTags(config.Oidc.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return diag.Errorf("error setting tags: %s", err) + } return nil } @@ -229,14 +277,12 @@ func refreshEksIdentityProviderConfigStatus(conn *eks.EKS, clusterName string, c identityProviderConfig := output.IdentityProviderConfig - // TODO: not sure about the use of StringValue here. if identityProviderConfig == nil { return identityProviderConfig, "", fmt.Errorf("EKS Identity Provider Config (%s:%s) missing", clusterName, aws.StringValue(config.Name)) } oidc := identityProviderConfig.Oidc - // TODO: Should I be checking for nil on OIDC here too? if oidc == nil { return identityProviderConfig, "", fmt.Errorf("EKS OIDC Identity Provider Config (%s:%s) missing", clusterName, aws.StringValue(config.Name)) } @@ -288,6 +334,26 @@ func expandEksOidcIdentityProviderConfigRequest(l []interface{}) (string, *eks.O IssuerUrl: aws.String(m["issuer_url"].(string)), } + if v, ok := m["groups_claim"].(string); ok && v != "" { + oidcIdentityProviderConfigRequest.GroupsClaim = aws.String(v) + } + + if v, ok := m["groups_prefix"].(string); ok && v != "" { + oidcIdentityProviderConfigRequest.GroupsPrefix = aws.String(v) + } + + if v, ok := m["required_claims"].(map[string]interface{}); ok && len(v) > 0 { + oidcIdentityProviderConfigRequest.RequiredClaims = stringMapToPointers(v) + } + + if v, ok := m["username_claim"].(string); ok && v != "" { + oidcIdentityProviderConfigRequest.UsernameClaim = aws.String(v) + } + + if v, ok := m["username_prefix"].(string); ok && v != "" { + oidcIdentityProviderConfigRequest.UsernamePrefix = aws.String(v) + } + return configName, oidcIdentityProviderConfigRequest } @@ -298,8 +364,13 @@ func flattenEksOidcIdentityProviderConfig(config *eks.OidcIdentityProviderConfig m := map[string]interface{}{ "client_id": aws.StringValue(config.ClientId), + "groups_claim": aws.StringValue(config.GroupsClaim), + "groups_prefix": aws.StringValue(config.GroupsPrefix), "identity_provider_config_name": aws.StringValue(config.IdentityProviderConfigName), "issuer_url": aws.StringValue(config.IssuerUrl), + "required_claims": aws.StringValueMap(config.RequiredClaims), + "username_claim": aws.StringValue(config.UsernameClaim), + "username_prefix": aws.StringValue(config.UsernamePrefix), } return []map[string]interface{}{m} diff --git a/aws/resource_aws_eks_identity_provider_config_test.go b/aws/resource_aws_eks_identity_provider_config_test.go index e702cd086feb..4d7a94d2664f 100644 --- a/aws/resource_aws_eks_identity_provider_config_test.go +++ b/aws/resource_aws_eks_identity_provider_config_test.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "log" + "regexp" "testing" "time" ) @@ -88,15 +89,21 @@ func TestAccAWSEksIdentityProviderConfig_basic(t *testing.T) { ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ + { + Config: testAccAWSEksIdentityProviderConfigProvider_Oidc_IssuerUrl(rName, "http://accounts.google.com/.well-known/openid-configuration"), + ExpectError: regexp.MustCompile(`expected .* to have a url with schema of: "https", got http://accounts.google.com/.well-known/openid-configuration`), + }, { Config: testAccAWSEksIdentityProviderConfigProviderConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), resource.TestCheckResourceAttrPair(resourceName, "cluster_name", eksClusterResourceName, "name"), resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), - resource.TestCheckResourceAttr(resourceName, "oidc.0.identity_provider_config_name", rName), resource.TestCheckResourceAttr(resourceName, "oidc.0.client_id", "test-url.apps.googleusercontent.com"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.identity_provider_config_name", rName), resource.TestCheckResourceAttr(resourceName, "oidc.0.issuer_url", "https://accounts.google.com/.well-known/openid-configuration"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -130,6 +137,126 @@ func TestAccAWSEksIdentityProviderConfig_disappears(t *testing.T) { }) } +func TestAccAWSEksIdentityProviderConfig_Oidc_Group(t *testing.T) { + var config eks.IdentityProviderConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_eks_identity_provider_config.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksIdentityProviderConfigProvider_Oidc_Groups(rName, "groups", "oidc:"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.groups_claim", "groups"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.groups_prefix", "oidc:"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSEksIdentityProviderConfig_Oidc_Username(t *testing.T) { + var config eks.IdentityProviderConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_eks_identity_provider_config.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksIdentityProviderConfigProvider_Oidc_Username(rName, "email", "-"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.username_claim", "email"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.username_prefix", "-"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(t *testing.T) { + var config eks.IdentityProviderConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_eks_identity_provider_config.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, "4qkvw9k2RbpSO6wgCbynY10T6Rc2n89PQblyi6bZ5VhfpMr6V7FVvrA12FiJxarh", "valueOne", "keyTwo", "valueTwo"), + ExpectError: regexp.MustCompile("Bad map key length"), + }, + { + Config: testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, "keyOne", "bUUUiuIXeFGw0M2VwiCVjR8oIIavv0PF49Ba6yNwOOC7IcoLawczSeb6MpEIhqtXKcf9aogW4uc4smLGvdTQ8uTTkVFvQTPyWXQ3F0uZP02YyoSw0d9MZ7laGRjpXSph9oFE2UlT5IyRaXIsTwl1qvItvVXLN40Pd3PDyPa6de4nlYcRNy6YIikZz2P1QUSYuvMGSJxGUzhTKYRUniolIt1vjHsXt3MAsaJtCcWz0tjLWalvG27pQ3Gl5Cs7K1", "keyTwo", "valueTwo"), + ExpectError: regexp.MustCompile("Bad map value length"), + }, + { + Config: testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, "keyOne", "valueOne", "keyTwo", "valueTwo"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.%", "2"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.keyOne", "valueOne"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.keyTwo", "valueTwo"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSEksIdentityProviderConfig_Tags(t *testing.T) { + var config eks.IdentityProviderConfig + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_eks_identity_provider_config.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksIdentityProviderConfig_Tags(rName, "keyOne", "valueOne", "keyTwo", "valueTwo"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.keyOne", "valueOne"), + resource.TestCheckResourceAttr(resourceName, "tags.keyTwo", "valueTwo"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAWSEksIdentityProviderConfigExists(resourceName string, config *eks.IdentityProviderConfig) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -183,7 +310,6 @@ func testAccCheckAWSEksIdentityProviderConfigExists(resourceName string, config } } -// TODO - still needs some work func testAccCheckAWSEksIdentityProviderConfigDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).eksconn @@ -324,3 +450,80 @@ resource "aws_eks_identity_provider_config" "test" { } `, rName) } + +func testAccAWSEksIdentityProviderConfigProvider_Oidc_IssuerUrl(rName, issuerUrl string) string { + return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` +resource "aws_eks_identity_provider_config" "test" { + cluster_name = aws_eks_cluster.test.name + oidc { + client_id = "test-url.apps.googleusercontent.com" + identity_provider_config_name = %[1]q + issuer_url = %[2]q + } +} +`, rName, issuerUrl) +} + +func testAccAWSEksIdentityProviderConfigProvider_Oidc_Groups(rName, groupsClaim, groupsPrefix string) string { + return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` +resource "aws_eks_identity_provider_config" "test" { + cluster_name = aws_eks_cluster.test.name + oidc { + client_id = "test-url.apps.googleusercontent.com" + groups_claim = %[2]q + groups_prefix = %[3]q + identity_provider_config_name = %[1]q + issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + } +} +`, rName, groupsClaim, groupsPrefix) +} + +func testAccAWSEksIdentityProviderConfigProvider_Oidc_Username(rName, usernameClaim, usernamePrefix string) string { + return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` +resource "aws_eks_identity_provider_config" "test" { + cluster_name = aws_eks_cluster.test.name + oidc { + client_id = "test-url.apps.googleusercontent.com" + identity_provider_config_name = %[1]q + issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + username_claim = %[2]q + username_prefix = %[3]q + } +} +`, rName, usernameClaim, usernamePrefix) +} + +func testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo string) string { + return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` +resource "aws_eks_identity_provider_config" "test" { + cluster_name = aws_eks_cluster.test.name + oidc { + client_id = "test-url.apps.googleusercontent.com" + identity_provider_config_name = %[1]q + issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + required_claims = { + %[2]q = %[3]q + %[4]q = %[5]q + } + } +} +`, rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo) +} + +func testAccAWSEksIdentityProviderConfig_Tags(rName, tagsKeyOne, tagsValueOne, tagsKeyTwo, tagsValueTwo string) string { + return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` +resource "aws_eks_identity_provider_config" "test" { + cluster_name = aws_eks_cluster.test.name + oidc { + client_id = "test-url.apps.googleusercontent.com" + identity_provider_config_name = %[1]q + issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + } + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagsKeyOne, tagsValueOne, tagsKeyTwo, tagsValueTwo) +} diff --git a/website/docs/r/eks_identity_provider_config.html.markdown b/website/docs/r/eks_identity_provider_config.html.markdown index be71227d6833..f480b0568b3b 100644 --- a/website/docs/r/eks_identity_provider_config.html.markdown +++ b/website/docs/r/eks_identity_provider_config.html.markdown @@ -35,18 +35,14 @@ The following arguments are required: The following arguments are optional: +* `oidc` + * `groups_claim` - The JWT claim that the provider will use to return groups. + * `groups_prefix` - A prefix that is prepended to group claims e.g. `oidc:`. + * `required_claims` - The key value pairs that describe required claims in the identity token. + * `username_claim` - The JWT claim that the provider will use as the username. + * `username_prefix` - A prefix that is prepended to username claims. * `tags` - (Optional) Key-value map of resource tags. -### selector Configuration Block - -The following arguments are required: - -* `namespace` - (Required) Kubernetes namespace for selection. - -The following arguments are optional: - -* `labels` - (Optional) Key-value map of Kubernetes labels for selection. - ## Attributes Reference In addition to all arguments above, the following attributes are exported: @@ -62,7 +58,7 @@ In addition to all arguments above, the following attributes are exported: ## Import -EKS Fargate Profiles can be imported using the `cluster_name` and `fargate_profile_name` separated by a colon (`:`), e.g. +EKS Identity Provider Configuration can be imported using the `cluster_name` and `identity_provider_config_name` separated by a colon (`:`), e.g. ``` $ terraform import aws_eks_identity_provider_config.my_identity_provider_config my_cluster:my_identity_provider_config From 01d0616e3e505941d02828946dffe3822d1ba90b Mon Sep 17 00:00:00 2001 From: Will Varney Date: Mon, 8 Mar 2021 10:31:27 +0000 Subject: [PATCH 0965/1208] New resource: aws_eks_identity_provider_config. This adds a new resource for associating an identity provider with an EKS cluster. This commit fixes the formatting of the terraform code in string templates and fixes the wrong grouping for imports. --- ...source_aws_eks_identity_provider_config.go | 7 ++- ...e_aws_eks_identity_provider_config_test.go | 61 ++++++++++--------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/aws/resource_aws_eks_identity_provider_config.go b/aws/resource_aws_eks_identity_provider_config.go index 7a09591aced9..e5a27b4cd1c1 100644 --- a/aws/resource_aws_eks_identity_provider_config.go +++ b/aws/resource_aws_eks_identity_provider_config.go @@ -3,6 +3,10 @@ package aws import ( "context" "fmt" + "log" + "strings" + "time" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" "github.com/hashicorp/go-cty/cty" @@ -11,9 +15,6 @@ import ( "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" - "log" - "strings" - "time" ) const typeOidc string = "oidc" diff --git a/aws/resource_aws_eks_identity_provider_config_test.go b/aws/resource_aws_eks_identity_provider_config_test.go index 4d7a94d2664f..4b2207a9898a 100644 --- a/aws/resource_aws_eks_identity_provider_config_test.go +++ b/aws/resource_aws_eks_identity_provider_config_test.go @@ -3,16 +3,17 @@ package aws import ( "context" "fmt" + "log" + "regexp" + "testing" + "time" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" "github.com/hashicorp/go-multierror" "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" - "log" - "regexp" - "testing" - "time" ) func init() { @@ -441,11 +442,11 @@ resource "aws_eks_cluster" "test" { func testAccAWSEksIdentityProviderConfigProviderConfigName(rName string) string { return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { - cluster_name = aws_eks_cluster.test.name + cluster_name = aws_eks_cluster.test.name oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "test-url.apps.googleusercontent.com" identity_provider_config_name = %[1]q - issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + issuer_url = "https://accounts.google.com/.well-known/openid-configuration" } } `, rName) @@ -454,11 +455,11 @@ resource "aws_eks_identity_provider_config" "test" { func testAccAWSEksIdentityProviderConfigProvider_Oidc_IssuerUrl(rName, issuerUrl string) string { return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { - cluster_name = aws_eks_cluster.test.name + cluster_name = aws_eks_cluster.test.name oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "test-url.apps.googleusercontent.com" identity_provider_config_name = %[1]q - issuer_url = %[2]q + issuer_url = %[2]q } } `, rName, issuerUrl) @@ -467,13 +468,13 @@ resource "aws_eks_identity_provider_config" "test" { func testAccAWSEksIdentityProviderConfigProvider_Oidc_Groups(rName, groupsClaim, groupsPrefix string) string { return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { - cluster_name = aws_eks_cluster.test.name + cluster_name = aws_eks_cluster.test.name oidc { - client_id = "test-url.apps.googleusercontent.com" - groups_claim = %[2]q - groups_prefix = %[3]q + client_id = "test-url.apps.googleusercontent.com" + groups_claim = %[2]q + groups_prefix = %[3]q identity_provider_config_name = %[1]q - issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + issuer_url = "https://accounts.google.com/.well-known/openid-configuration" } } `, rName, groupsClaim, groupsPrefix) @@ -482,13 +483,13 @@ resource "aws_eks_identity_provider_config" "test" { func testAccAWSEksIdentityProviderConfigProvider_Oidc_Username(rName, usernameClaim, usernamePrefix string) string { return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { - cluster_name = aws_eks_cluster.test.name + cluster_name = aws_eks_cluster.test.name oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "test-url.apps.googleusercontent.com" identity_provider_config_name = %[1]q - issuer_url = "https://accounts.google.com/.well-known/openid-configuration" - username_claim = %[2]q - username_prefix = %[3]q + issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + username_claim = %[2]q + username_prefix = %[3]q } } `, rName, usernameClaim, usernamePrefix) @@ -497,15 +498,15 @@ resource "aws_eks_identity_provider_config" "test" { func testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo string) string { return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { - cluster_name = aws_eks_cluster.test.name + cluster_name = aws_eks_cluster.test.name oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "test-url.apps.googleusercontent.com" identity_provider_config_name = %[1]q - issuer_url = "https://accounts.google.com/.well-known/openid-configuration" - required_claims = { - %[2]q = %[3]q - %[4]q = %[5]q - } + issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + required_claims = { + %[2]q = %[3]q + %[4]q = %[5]q + } } } `, rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo) @@ -514,11 +515,11 @@ resource "aws_eks_identity_provider_config" "test" { func testAccAWSEksIdentityProviderConfig_Tags(rName, tagsKeyOne, tagsValueOne, tagsKeyTwo, tagsValueTwo string) string { return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { - cluster_name = aws_eks_cluster.test.name + cluster_name = aws_eks_cluster.test.name oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "test-url.apps.googleusercontent.com" identity_provider_config_name = %[1]q - issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + issuer_url = "https://accounts.google.com/.well-known/openid-configuration" } tags = { %[2]q = %[3]q From 439ca460b77bd99b63801d2a5a1499a85b113028 Mon Sep 17 00:00:00 2001 From: Will Varney Date: Mon, 8 Mar 2021 10:53:05 +0000 Subject: [PATCH 0966/1208] New resource: aws_eks_identity_provider_config. This adds a new resource for associating an identity provider with an EKS cluster. This commit fixes the formatting of the terraform code in the docs and the indenting of unordered lists. --- ...eks_identity_provider_config.html.markdown | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/website/docs/r/eks_identity_provider_config.html.markdown b/website/docs/r/eks_identity_provider_config.html.markdown index f480b0568b3b..d687898e953f 100644 --- a/website/docs/r/eks_identity_provider_config.html.markdown +++ b/website/docs/r/eks_identity_provider_config.html.markdown @@ -14,11 +14,11 @@ Manages an EKS Identity Provider Configuration. ```hcl resource "aws_eks_identity_provider_config" "example" { - cluster_name = aws_eks_cluster.example.name + cluster_name = aws_eks_cluster.example.name oidc { - client_id = "your client_id" + client_id = "your client_id" identity_provider_config_name = "example" - issuer_url = "your issuer_url" + issuer_url = "your issuer_url" } } ``` @@ -29,18 +29,18 @@ The following arguments are required: * `cluster_name` – Name of the EKS Cluster. * `oidc` - Nested attribute containing [OpenID Connect](https://openid.net/connect/) identity provider information for the cluster. - * `client_id` – Client ID for the OpenID Connect identity provider. - * `identity_provider_config_name` – The name of the identity provider config. - * `issuer_url` - Issuer URL for the OpenID Connect identity provider. + * `client_id` – Client ID for the OpenID Connect identity provider. + * `identity_provider_config_name` – The name of the identity provider config. + * `issuer_url` - Issuer URL for the OpenID Connect identity provider. The following arguments are optional: * `oidc` - * `groups_claim` - The JWT claim that the provider will use to return groups. - * `groups_prefix` - A prefix that is prepended to group claims e.g. `oidc:`. - * `required_claims` - The key value pairs that describe required claims in the identity token. - * `username_claim` - The JWT claim that the provider will use as the username. - * `username_prefix` - A prefix that is prepended to username claims. + * `groups_claim` - The JWT claim that the provider will use to return groups. + * `groups_prefix` - A prefix that is prepended to group claims e.g. `oidc:`. + * `required_claims` - The key value pairs that describe required claims in the identity token. + * `username_claim` - The JWT claim that the provider will use as the username. + * `username_prefix` - A prefix that is prepended to username claims. * `tags` - (Optional) Key-value map of resource tags. ## Attributes Reference From d647de8868017b2702c71ec7702ddfc1b24037ae Mon Sep 17 00:00:00 2001 From: Will Varney Date: Mon, 8 Mar 2021 13:27:28 +0000 Subject: [PATCH 0967/1208] New resource: aws_eks_identity_provider_config. This adds a new resource for associating an identity provider with an EKS cluster. This commit renames the changelog entry to the pull request number. --- .changelog/{pending.txt => 17959.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changelog/{pending.txt => 17959.txt} (100%) diff --git a/.changelog/pending.txt b/.changelog/17959.txt similarity index 100% rename from .changelog/pending.txt rename to .changelog/17959.txt From d3812eb3fea8182d47554e15c0b868ee9fc0e1b6 Mon Sep 17 00:00:00 2001 From: Will Varney Date: Fri, 11 Jun 2021 15:07:37 +0100 Subject: [PATCH 0968/1208] New resource: aws_eks_identity_provider_config. Moving to the new 'expandStringMap' method after pulling updates from upstream main branch. --- aws/resource_aws_eks_identity_provider_config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_eks_identity_provider_config.go b/aws/resource_aws_eks_identity_provider_config.go index e5a27b4cd1c1..1bb126a3dc22 100644 --- a/aws/resource_aws_eks_identity_provider_config.go +++ b/aws/resource_aws_eks_identity_provider_config.go @@ -344,7 +344,7 @@ func expandEksOidcIdentityProviderConfigRequest(l []interface{}) (string, *eks.O } if v, ok := m["required_claims"].(map[string]interface{}); ok && len(v) > 0 { - oidcIdentityProviderConfigRequest.RequiredClaims = stringMapToPointers(v) + oidcIdentityProviderConfigRequest.RequiredClaims = expandStringMap(v) } if v, ok := m["username_claim"].(string); ok && v != "" { From 4222c31756da28fcc0fb38ecdfa9eb2365b0cd13 Mon Sep 17 00:00:00 2001 From: Will Varney Date: Tue, 29 Jun 2021 14:48:53 +0100 Subject: [PATCH 0969/1208] New resource: aws_eks_identity_provider_config. Adding in the required 'ErrorCheck' to fix the awsproviderlint error. Moving from using the background context to the TODO context in the acceptance tests. --- aws/resource_aws_eks_identity_provider_config_test.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_eks_identity_provider_config_test.go b/aws/resource_aws_eks_identity_provider_config_test.go index 4b2207a9898a..adcb0f24a6ed 100644 --- a/aws/resource_aws_eks_identity_provider_config_test.go +++ b/aws/resource_aws_eks_identity_provider_config_test.go @@ -53,8 +53,7 @@ func testSweepEksIdentityProviderConfigs(region string) error { continue } - // TODO - Should I use context.Background here? - if err := waitForEksIdentityProviderConfigDisassociation(context.Background(), conn, clusterName, config, 10*time.Minute); err != nil { + if err := waitForEksIdentityProviderConfigDisassociation(context.TODO(), conn, clusterName, config, 10*time.Minute); err != nil { errors = multierror.Append(errors, fmt.Errorf("error waiting for EKS Identity Provider Config %q disassociation: %w", configName, err)) continue } @@ -87,6 +86,7 @@ func TestAccAWSEksIdentityProviderConfig_basic(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ @@ -123,6 +123,7 @@ func TestAccAWSEksIdentityProviderConfig_disappears(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ @@ -145,6 +146,7 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_Group(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ @@ -173,6 +175,7 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_Username(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ @@ -201,6 +204,7 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ @@ -237,6 +241,7 @@ func TestAccAWSEksIdentityProviderConfig_Tags(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ @@ -365,7 +370,7 @@ func testAccCheckAWSEksIdentityProviderConfigDisappears(clusterName string, conf return err } - return waitForEksIdentityProviderConfigDisassociation(context.Background(), conn, clusterName, config, 25*time.Minute) + return waitForEksIdentityProviderConfigDisassociation(context.TODO(), conn, clusterName, config, 25*time.Minute) } } From 2d000de23ac4609097e72b65a69e57f6e676e424 Mon Sep 17 00:00:00 2001 From: Will Varney Date: Wed, 30 Jun 2021 10:16:46 +0100 Subject: [PATCH 0970/1208] New resource: aws_eks_identity_provider_config. Running a go mod tidy to clean up go.sum. --- go.sum | 5 ----- 1 file changed, 5 deletions(-) diff --git a/go.sum b/go.sum index 15c3f8ef9683..009b6a2c58dd 100644 --- a/go.sum +++ b/go.sum @@ -50,7 +50,6 @@ github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U= github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= @@ -63,7 +62,6 @@ github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJE github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -97,9 +95,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= @@ -298,7 +294,6 @@ github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= From eb34721ac26f91852a807d9c414e2e49e9757fd5 Mon Sep 17 00:00:00 2001 From: Will Varney Date: Mon, 5 Jul 2021 15:00:24 +0100 Subject: [PATCH 0971/1208] New resource: aws_eks_identity_provider_config. Fixing the tfproviderdocs linting error around using 'terraform' and not 'hcl' for the markdown code samples. --- website/docs/r/eks_identity_provider_config.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/eks_identity_provider_config.html.markdown b/website/docs/r/eks_identity_provider_config.html.markdown index d687898e953f..1aff5578d6cc 100644 --- a/website/docs/r/eks_identity_provider_config.html.markdown +++ b/website/docs/r/eks_identity_provider_config.html.markdown @@ -12,7 +12,7 @@ Manages an EKS Identity Provider Configuration. ## Example Usage -```hcl +```terraform resource "aws_eks_identity_provider_config" "example" { cluster_name = aws_eks_cluster.example.name oidc { From 312700fa615ee161309cbfc5a80204d872d54be4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 7 Jul 2021 11:25:51 -0400 Subject: [PATCH 0972/1208] r/aws_eks_identity_provider_config: Use internal finder and waiter packages. --- aws/internal/service/eks/enum.go | 4 + aws/internal/service/eks/finder/finder.go | 33 +++ aws/internal/service/eks/id.go | 19 ++ aws/internal/service/eks/waiter/status.go | 16 ++ aws/internal/service/eks/waiter/waiter.go | 34 +++ ...source_aws_eks_identity_provider_config.go | 246 +++++++--------- ...e_aws_eks_identity_provider_config_test.go | 263 ++++++++---------- ...eks_identity_provider_config.html.markdown | 34 +-- 8 files changed, 344 insertions(+), 305 deletions(-) diff --git a/aws/internal/service/eks/enum.go b/aws/internal/service/eks/enum.go index 8e0f2c21f43b..e21b72d590bf 100644 --- a/aws/internal/service/eks/enum.go +++ b/aws/internal/service/eks/enum.go @@ -1,5 +1,9 @@ package eks +const ( + IdentityProviderConfigTypeOidc = "oidc" +) + const ( ResourcesSecrets = "secrets" ) diff --git a/aws/internal/service/eks/finder/finder.go b/aws/internal/service/eks/finder/finder.go index 8aef2b0ba6c0..3334e44c6eb6 100644 --- a/aws/internal/service/eks/finder/finder.go +++ b/aws/internal/service/eks/finder/finder.go @@ -7,6 +7,7 @@ import ( "github.com/aws/aws-sdk-go/service/eks" "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" ) func AddonByClusterNameAndAddonName(ctx context.Context, conn *eks.EKS, clusterName, addonName string) (*eks.Addon, error) { @@ -214,3 +215,35 @@ func NodegroupUpdateByClusterNameNodegroupNameAndID(conn *eks.EKS, clusterName, return output.Update, nil } + +func OidcIdentityProviderConfigByClusterNameAndConfigName(ctx context.Context, conn *eks.EKS, clusterName, configName string) (*eks.OidcIdentityProviderConfig, error) { + input := &eks.DescribeIdentityProviderConfigInput{ + ClusterName: aws.String(clusterName), + IdentityProviderConfig: &eks.IdentityProviderConfig{ + Name: aws.String(configName), + Type: aws.String(tfeks.IdentityProviderConfigTypeOidc), + }, + } + + output, err := conn.DescribeIdentityProviderConfigWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.IdentityProviderConfig == nil || output.IdentityProviderConfig.Oidc == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.IdentityProviderConfig.Oidc, nil +} diff --git a/aws/internal/service/eks/id.go b/aws/internal/service/eks/id.go index 8aec4cf9a3e5..66c86d64104b 100644 --- a/aws/internal/service/eks/id.go +++ b/aws/internal/service/eks/id.go @@ -43,6 +43,25 @@ func FargateProfileParseResourceID(id string) (string, string, error) { return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected cluster-name%[2]sfargate-profile-name", id, fargateProfileResourceIDSeparator) } +const identityProviderConfigResourceIDSeparator = ":" + +func IdentityProviderConfigCreateResourceID(clusterName, configName string) string { + parts := []string{clusterName, configName} + id := strings.Join(parts, identityProviderConfigResourceIDSeparator) + + return id +} + +func IdentityProviderConfigParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, identityProviderConfigResourceIDSeparator) + + if len(parts) == 2 && parts[0] != "" && parts[1] != "" { + return parts[0], parts[1], nil + } + + return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected cluster-name%[2]sconfig-name", id, identityProviderConfigResourceIDSeparator) +} + const nodeGroupResourceIDSeparator = ":" func NodeGroupCreateResourceID(clusterName, nodeGroupName string) string { diff --git a/aws/internal/service/eks/waiter/status.go b/aws/internal/service/eks/waiter/status.go index 96a1a3daa46d..c0b4920ef1cd 100644 --- a/aws/internal/service/eks/waiter/status.go +++ b/aws/internal/service/eks/waiter/status.go @@ -121,3 +121,19 @@ func NodegroupUpdateStatus(conn *eks.EKS, clusterName, nodeGroupName, id string) return output, aws.StringValue(output.Status), nil } } + +func OidcIdentityProviderConfigStatus(ctx context.Context, conn *eks.EKS, clusterName, configName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.OidcIdentityProviderConfigByClusterNameAndConfigName(ctx, conn, clusterName, configName) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Status), nil + } +} diff --git a/aws/internal/service/eks/waiter/waiter.go b/aws/internal/service/eks/waiter/waiter.go index 171f55c27fee..2a3289dacd87 100644 --- a/aws/internal/service/eks/waiter/waiter.go +++ b/aws/internal/service/eks/waiter/waiter.go @@ -240,3 +240,37 @@ func NodegroupUpdateSuccessful(conn *eks.EKS, clusterName, nodeGroupName, id str return nil, err } + +func OidcIdentityProviderConfigCreated(ctx context.Context, conn *eks.EKS, clusterName, configName string, timeout time.Duration) (*eks.OidcIdentityProviderConfig, error) { + stateConf := resource.StateChangeConf{ + Pending: []string{eks.ConfigStatusCreating}, + Target: []string{eks.ConfigStatusActive}, + Refresh: OidcIdentityProviderConfigStatus(ctx, conn, clusterName, configName), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*eks.OidcIdentityProviderConfig); ok { + return output, err + } + + return nil, err +} + +func OidcIdentityProviderConfigDeleted(ctx context.Context, conn *eks.EKS, clusterName, configName string, timeout time.Duration) (*eks.OidcIdentityProviderConfig, error) { + stateConf := resource.StateChangeConf{ + Pending: []string{eks.ConfigStatusActive, eks.ConfigStatusDeleting}, + Target: []string{}, + Refresh: OidcIdentityProviderConfigStatus(ctx, conn, clusterName, configName), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*eks.OidcIdentityProviderConfig); ok { + return output, err + } + + return nil, err +} diff --git a/aws/resource_aws_eks_identity_provider_config.go b/aws/resource_aws_eks_identity_provider_config.go index 1bb126a3dc22..6f37517df7f8 100644 --- a/aws/resource_aws_eks_identity_provider_config.go +++ b/aws/resource_aws_eks_identity_provider_config.go @@ -2,23 +2,24 @@ package aws import ( "context" - "fmt" "log" - "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -const typeOidc string = "oidc" - func resourceAwsEksIdentityProviderConfig() *schema.Resource { return &schema.Resource{ CreateContext: resourceAwsEksIdentityProviderConfigCreate, @@ -35,16 +36,23 @@ func resourceAwsEksIdentityProviderConfig() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "cluster_name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validation.NoZeroValues, }, + "oidc": { Type: schema.TypeList, Required: true, ForceNew: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "client_id": { @@ -81,14 +89,11 @@ func resourceAwsEksIdentityProviderConfig() *schema.Resource { Type: schema.TypeMap, Optional: true, ForceNew: true, - ValidateDiagFunc: all( + ValidateDiagFunc: allDiagFunc( validation.MapKeyLenBetween(1, 63), validation.MapValueLenBetween(1, 253), ), - Elem: &schema.Schema{ - Type: schema.TypeString, - ForceNew: true, - }, + Elem: &schema.Schema{Type: schema.TypeString}, }, "username_claim": { Type: schema.TypeString, @@ -105,16 +110,19 @@ func resourceAwsEksIdentityProviderConfig() *schema.Resource { }, }, }, - "tags": tagsSchemaForceNew(), + "status": { Type: schema.TypeString, Computed: true, }, + + "tags": tagsSchemaForceNew(), }, } } -func all(validators ...schema.SchemaValidateDiagFunc) schema.SchemaValidateDiagFunc { +// https://github.com/hashicorp/terraform-plugin-sdk/issues/780. +func allDiagFunc(validators ...schema.SchemaValidateDiagFunc) schema.SchemaValidateDiagFunc { return func(i interface{}, k cty.Path) diag.Diagnostics { var diags diag.Diagnostics for _, validator := range validators { @@ -128,15 +136,13 @@ func resourceAwsEksIdentityProviderConfigCreate(ctx context.Context, d *schema.R conn := meta.(*AWSClient).eksconn clusterName := d.Get("cluster_name").(string) - //TODO - Should I break away from the aws sdk api and move the name outside of the oidc map? - configName, oidcRequest := expandEksOidcIdentityProviderConfigRequest(d.Get("oidc").([]interface{})) - - id := fmt.Sprintf("%s:%s", clusterName, configName) + configName, oidc := expandEksOidcIdentityProviderConfigRequest(d.Get("oidc").([]interface{})[0].(map[string]interface{})) + id := tfeks.IdentityProviderConfigCreateResourceID(clusterName, configName) input := &eks.AssociateIdentityProviderConfigInput{ ClientRequestToken: aws.String(resource.UniqueId()), ClusterName: aws.String(clusterName), - Oidc: oidcRequest, + Oidc: oidc, } if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { @@ -144,23 +150,16 @@ func resourceAwsEksIdentityProviderConfigCreate(ctx context.Context, d *schema.R } _, err := conn.AssociateIdentityProviderConfig(input) + if err != nil { return diag.Errorf("error associating EKS Identity Provider Config (%s): %s", id, err) } d.SetId(id) - stateConf := resource.StateChangeConf{ - Pending: []string{eks.ConfigStatusCreating}, - Target: []string{eks.ConfigStatusActive}, - Timeout: d.Timeout(schema.TimeoutCreate), - Refresh: refreshEksIdentityProviderConfigStatus(conn, clusterName, &eks.IdentityProviderConfig{ - Name: aws.String(configName), - Type: aws.String(typeOidc), - }), - } + _, err = waiter.OidcIdentityProviderConfigCreated(ctx, conn, clusterName, configName, d.Timeout(schema.TimeoutCreate)) - if _, err := stateConf.WaitForStateContext(ctx); err != nil { + if err != nil { return diag.Errorf("error waiting for EKS Identity Provider Config (%s) association: %s", d.Id(), err) } @@ -171,22 +170,15 @@ func resourceAwsEksIdentityProviderConfigRead(ctx context.Context, d *schema.Res conn := meta.(*AWSClient).eksconn ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - clusterName, configName, err := resourceAwsEksIdentityProviderConfigParseId(d.Id()) + clusterName, configName, err := tfeks.IdentityProviderConfigParseResourceID(d.Id()) + if err != nil { return diag.FromErr(err) } - input := &eks.DescribeIdentityProviderConfigInput{ - ClusterName: aws.String(clusterName), - IdentityProviderConfig: &eks.IdentityProviderConfig{ - Name: aws.String(configName), - Type: aws.String(typeOidc), - }, - } + oidc, err := finder.OidcIdentityProviderConfigByClusterNameAndConfigName(ctx, conn, clusterName, configName) - output, err := conn.DescribeIdentityProviderConfigWithContext(ctx, input) - - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] EKS Identity Provider Config (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -196,29 +188,16 @@ func resourceAwsEksIdentityProviderConfigRead(ctx context.Context, d *schema.Res return diag.Errorf("error reading EKS Identity Provider Config (%s): %s", d.Id(), err) } - config := output.IdentityProviderConfig - - if config == nil { - log.Printf("[WARN] EKS Identity Provider Config (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - - if config.Oidc == nil { - log.Printf("[WARN] EKS OIDC Identity Provider Config (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - - d.Set("cluster_name", clusterName) + d.Set("arn", oidc.IdentityProviderConfigArn) + d.Set("cluster_name", oidc.ClusterName) - if err := d.Set("oidc", flattenEksOidcIdentityProviderConfig(config.Oidc)); err != nil { + if err := d.Set("oidc", []interface{}{flattenEksOidcIdentityProviderConfig(oidc)}); err != nil { return diag.Errorf("error setting oidc: %s", err) } - d.Set("status", config.Oidc.Status) + d.Set("status", oidc.Status) - if err := d.Set("tags", keyvaluetags.EksKeyValueTags(config.Oidc.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + if err := d.Set("tags", keyvaluetags.EksKeyValueTags(oidc.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return diag.Errorf("error setting tags: %s", err) } @@ -228,27 +207,26 @@ func resourceAwsEksIdentityProviderConfigRead(ctx context.Context, d *schema.Res func resourceAwsEksIdentityProviderConfigDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).eksconn - clusterName, configName, err := resourceAwsEksIdentityProviderConfigParseId(d.Id()) + clusterName, configName, err := tfeks.IdentityProviderConfigParseResourceID(d.Id()) + if err != nil { return diag.FromErr(err) } - config := &eks.IdentityProviderConfig{ - Name: aws.String(configName), - Type: aws.String(typeOidc), - } - log.Printf("[DEBUG] Disassociating EKS Identity Provider Config: %s", d.Id()) - input := &eks.DisassociateIdentityProviderConfigInput{ - ClusterName: aws.String(clusterName), - IdentityProviderConfig: config, - } + _, err = conn.DisassociateIdentityProviderConfigWithContext(ctx, &eks.DisassociateIdentityProviderConfigInput{ + ClusterName: aws.String(clusterName), + IdentityProviderConfig: &eks.IdentityProviderConfig{ + Name: aws.String(configName), + Type: aws.String(tfeks.IdentityProviderConfigTypeOidc), + }, + }) - _, err = conn.DisassociateIdentityProviderConfigWithContext(ctx, input) + if tfawserr.ErrCodeEquals(err, eks.ErrCodeResourceNotFoundException) { + return nil + } - // TODO - Is checking for the exception message too brittle? - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") || - isAWSErr(err, eks.ErrCodeInvalidRequestException, "Identity provider config is not associated with cluster") { + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidRequestException, "Identity provider config is not associated with cluster") { return nil } @@ -256,123 +234,97 @@ func resourceAwsEksIdentityProviderConfigDelete(ctx context.Context, d *schema.R return diag.Errorf("error disassociating EKS Identity Provider Config (%s): %s", d.Id(), err) } - if err := waitForEksIdentityProviderConfigDisassociation(ctx, conn, clusterName, config, d.Timeout(schema.TimeoutDelete)); err != nil { + _, err = waiter.OidcIdentityProviderConfigDeleted(ctx, conn, clusterName, configName, d.Timeout(schema.TimeoutDelete)) + + if err != nil { return diag.Errorf("error waiting for EKS Identity Provider Config (%s) disassociation: %s", d.Id(), err) } return nil } -func refreshEksIdentityProviderConfigStatus(conn *eks.EKS, clusterName string, config *eks.IdentityProviderConfig) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - input := &eks.DescribeIdentityProviderConfigInput{ - ClusterName: aws.String(clusterName), - IdentityProviderConfig: config, - } - - output, err := conn.DescribeIdentityProviderConfig(input) - - if err != nil { - return "", "", err - } - - identityProviderConfig := output.IdentityProviderConfig +func expandEksOidcIdentityProviderConfigRequest(tfMap map[string]interface{}) (string, *eks.OidcIdentityProviderConfigRequest) { + if tfMap == nil { + return "", nil + } - if identityProviderConfig == nil { - return identityProviderConfig, "", fmt.Errorf("EKS Identity Provider Config (%s:%s) missing", clusterName, aws.StringValue(config.Name)) - } + apiObject := &eks.OidcIdentityProviderConfigRequest{} - oidc := identityProviderConfig.Oidc + if v, ok := tfMap["client_id"].(string); ok && v != "" { + apiObject.ClientId = aws.String(v) + } - if oidc == nil { - return identityProviderConfig, "", fmt.Errorf("EKS OIDC Identity Provider Config (%s:%s) missing", clusterName, aws.StringValue(config.Name)) - } + if v, ok := tfMap["groups_claim"].(string); ok && v != "" { + apiObject.GroupsClaim = aws.String(v) + } - return identityProviderConfig, aws.StringValue(oidc.Status), nil + if v, ok := tfMap["groups_prefix"].(string); ok && v != "" { + apiObject.GroupsPrefix = aws.String(v) } -} -func waitForEksIdentityProviderConfigDisassociation(ctx context.Context, conn *eks.EKS, clusterName string, config *eks.IdentityProviderConfig, timeout time.Duration) error { - stateConf := resource.StateChangeConf{ - Pending: []string{ - eks.ConfigStatusActive, - eks.ConfigStatusDeleting, - }, - Target: []string{""}, - Timeout: timeout, - Refresh: refreshEksIdentityProviderConfigStatus(conn, clusterName, config), + var identityProviderConfigName string + if v, ok := tfMap["identity_provider_config_name"].(string); ok && v != "" { + identityProviderConfigName = v + apiObject.IdentityProviderConfigName = aws.String(v) } - _, err := stateConf.WaitForStateContext(ctx) - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - return nil + if v, ok := tfMap["issuer_url"].(string); ok && v != "" { + apiObject.IssuerUrl = aws.String(v) } - return err -} + if v, ok := tfMap["required_claims"].(map[string]interface{}); ok && len(v) > 0 { + apiObject.RequiredClaims = expandStringMap(v) + } -func resourceAwsEksIdentityProviderConfigParseId(id string) (string, string, error) { - parts := strings.Split(id, ":") + if v, ok := tfMap["username_claim"].(string); ok && v != "" { + apiObject.UsernameClaim = aws.String(v) + } - if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return "", "", fmt.Errorf("unexpected format of ID (%s), expected cluster-name:identity-provider-config-name", id) + if v, ok := tfMap["username_prefix"].(string); ok && v != "" { + apiObject.UsernamePrefix = aws.String(v) } - return parts[0], parts[1], nil + return identityProviderConfigName, apiObject } -func expandEksOidcIdentityProviderConfigRequest(l []interface{}) (string, *eks.OidcIdentityProviderConfigRequest) { - if len(l) == 0 { - return "", nil +func flattenEksOidcIdentityProviderConfig(apiObject *eks.OidcIdentityProviderConfig) map[string]interface{} { + if apiObject == nil { + return nil } - m := l[0].(map[string]interface{}) + tfMap := map[string]interface{}{} - configName := m["identity_provider_config_name"].(string) - oidcIdentityProviderConfigRequest := &eks.OidcIdentityProviderConfigRequest{ - ClientId: aws.String(m["client_id"].(string)), - IdentityProviderConfigName: aws.String(configName), - IssuerUrl: aws.String(m["issuer_url"].(string)), + if v := apiObject.ClientId; v != nil { + tfMap["client_id"] = aws.StringValue(v) } - if v, ok := m["groups_claim"].(string); ok && v != "" { - oidcIdentityProviderConfigRequest.GroupsClaim = aws.String(v) + if v := apiObject.GroupsClaim; v != nil { + tfMap["groups_claim"] = aws.StringValue(v) } - if v, ok := m["groups_prefix"].(string); ok && v != "" { - oidcIdentityProviderConfigRequest.GroupsPrefix = aws.String(v) + if v := apiObject.GroupsPrefix; v != nil { + tfMap["groups_prefix"] = aws.StringValue(v) } - if v, ok := m["required_claims"].(map[string]interface{}); ok && len(v) > 0 { - oidcIdentityProviderConfigRequest.RequiredClaims = expandStringMap(v) + if v := apiObject.IdentityProviderConfigName; v != nil { + tfMap["identity_provider_config_name"] = aws.StringValue(v) } - if v, ok := m["username_claim"].(string); ok && v != "" { - oidcIdentityProviderConfigRequest.UsernameClaim = aws.String(v) + if v := apiObject.IssuerUrl; v != nil { + tfMap["issuer_url"] = aws.StringValue(v) } - if v, ok := m["username_prefix"].(string); ok && v != "" { - oidcIdentityProviderConfigRequest.UsernamePrefix = aws.String(v) + if v := apiObject.RequiredClaims; v != nil { + tfMap["required_claims"] = aws.StringValueMap(v) } - return configName, oidcIdentityProviderConfigRequest -} - -func flattenEksOidcIdentityProviderConfig(config *eks.OidcIdentityProviderConfig) []map[string]interface{} { - if config == nil { - return []map[string]interface{}{} + if v := apiObject.UsernameClaim; v != nil { + tfMap["username_claim"] = aws.StringValue(v) } - m := map[string]interface{}{ - "client_id": aws.StringValue(config.ClientId), - "groups_claim": aws.StringValue(config.GroupsClaim), - "groups_prefix": aws.StringValue(config.GroupsPrefix), - "identity_provider_config_name": aws.StringValue(config.IdentityProviderConfigName), - "issuer_url": aws.StringValue(config.IssuerUrl), - "required_claims": aws.StringValueMap(config.RequiredClaims), - "username_claim": aws.StringValue(config.UsernameClaim), - "username_prefix": aws.StringValue(config.UsernamePrefix), + if v := apiObject.UsernamePrefix; v != nil { + tfMap["username_prefix"] = aws.StringValue(v) } - return []map[string]interface{}{m} + return tfMap } diff --git a/aws/resource_aws_eks_identity_provider_config_test.go b/aws/resource_aws_eks_identity_provider_config_test.go index adcb0f24a6ed..72bd5d6b3c2d 100644 --- a/aws/resource_aws_eks_identity_provider_config_test.go +++ b/aws/resource_aws_eks_identity_provider_config_test.go @@ -6,14 +6,16 @@ import ( "log" "regexp" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/eks" - "github.com/hashicorp/go-multierror" + multierror "github.com/hashicorp/go-multierror" "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" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -26,63 +28,72 @@ func init() { func testSweepEksIdentityProviderConfigs(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } + ctx := context.TODO() conn := client.(*AWSClient).eksconn - - var errors error input := &eks.ListClustersInput{} - err = conn.ListClustersPages(input, func(page *eks.ListClustersOutput, lastPage bool) bool { + var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) + + err = conn.ListClustersPagesWithContext(ctx, input, func(page *eks.ListClustersOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + for _, cluster := range page.Clusters { - clusterName := aws.StringValue(cluster) input := &eks.ListIdentityProviderConfigsInput{ ClusterName: cluster, } - err := conn.ListIdentityProviderConfigsPages(input, func(page *eks.ListIdentityProviderConfigsOutput, lastPage bool) bool { - for _, config := range page.IdentityProviderConfigs { - configName := aws.StringValue(config.Name) - log.Printf("[INFO] Disassociating Identity Provider Config %q", configName) - input := &eks.DisassociateIdentityProviderConfigInput{ - ClusterName: cluster, - IdentityProviderConfig: config, - } - _, err := conn.DisassociateIdentityProviderConfig(input) - - if err != nil && !isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - errors = multierror.Append(errors, fmt.Errorf("error disassociating Identity Provider Config %q: %w", configName, err)) - continue - } - - if err := waitForEksIdentityProviderConfigDisassociation(context.TODO(), conn, clusterName, config, 10*time.Minute); err != nil { - errors = multierror.Append(errors, fmt.Errorf("error waiting for EKS Identity Provider Config %q disassociation: %w", configName, err)) - continue - } + + err := conn.ListIdentityProviderConfigsPagesWithContext(ctx, input, func(page *eks.ListIdentityProviderConfigsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, identityProviderConfig := range page.IdentityProviderConfigs { + r := resourceAwsEksIdentityProviderConfig() + d := r.Data(nil) + d.SetId(tfeks.IdentityProviderConfigCreateResourceID(aws.StringValue(cluster), aws.StringValue(identityProviderConfig.Name))) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - return true + + return !lastPage }) + if err != nil { - errors = multierror.Append(errors, fmt.Errorf("error listing Identity Provider Configs for EKS Cluster %s: %w", clusterName, err)) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Identity Provider Configs (%s): %w", region, err)) } } - return true + return !lastPage }) + if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping EKS Clusters sweep for %s: %s", region, err) - return errors // In case we have completed some pages, but had errors + log.Print(fmt.Errorf("[WARN] Skipping EKS Identity Provider Configs sweep for %s: %w", region, err)) + return sweeperErrs // In case we have completed some pages, but had errors + } + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EKS Clusters (%s): %w", region, err)) } + + err = testSweepResourceOrchestrator(sweepResources) + if err != nil { - errors = multierror.Append(errors, fmt.Errorf("error retrieving EKS Clusters: %w", err)) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping EKS Identity Provider Configs (%s): %w", region, err)) } - return errors + return sweeperErrs.ErrorOrNil() } func TestAccAWSEksIdentityProviderConfig_basic(t *testing.T) { - var config eks.IdentityProviderConfig + var config eks.OidcIdentityProviderConfig rName := acctest.RandomWithPrefix("tf-acc-test") eksClusterResourceName := "aws_eks_cluster.test" resourceName := "aws_eks_identity_provider_config.test" + ctx := context.TODO() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, @@ -91,19 +102,24 @@ func TestAccAWSEksIdentityProviderConfig_basic(t *testing.T) { CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksIdentityProviderConfigProvider_Oidc_IssuerUrl(rName, "http://accounts.google.com/.well-known/openid-configuration"), - ExpectError: regexp.MustCompile(`expected .* to have a url with schema of: "https", got http://accounts.google.com/.well-known/openid-configuration`), + Config: testAccAWSEksIdentityProviderConfigProvider_Oidc_IssuerUrl(rName, "http://example.com"), + ExpectError: regexp.MustCompile(`expected .* to have a url with schema of: "https", got http://example.com`), }, { Config: testAccAWSEksIdentityProviderConfigProviderConfigName(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "eks", regexp.MustCompile(fmt.Sprintf("identityproviderconfig/%[1]s/oidc/%[1]s/.+", rName))), resource.TestCheckResourceAttrPair(resourceName, "cluster_name", eksClusterResourceName, "name"), resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), - resource.TestCheckResourceAttr(resourceName, "oidc.0.client_id", "test-url.apps.googleusercontent.com"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.client_id", "example.net"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.groups_claim", ""), + resource.TestCheckResourceAttr(resourceName, "oidc.0.groups_prefix", ""), resource.TestCheckResourceAttr(resourceName, "oidc.0.identity_provider_config_name", rName), - resource.TestCheckResourceAttr(resourceName, "oidc.0.issuer_url", "https://accounts.google.com/.well-known/openid-configuration"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.issuer_url", "https://example.com"), resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.%", "0"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.username_claim", ""), + resource.TestCheckResourceAttr(resourceName, "oidc.0.username_prefix", ""), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, @@ -117,9 +133,10 @@ func TestAccAWSEksIdentityProviderConfig_basic(t *testing.T) { } func TestAccAWSEksIdentityProviderConfig_disappears(t *testing.T) { - var config eks.IdentityProviderConfig + var config eks.OidcIdentityProviderConfig rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_identity_provider_config.test" + ctx := context.TODO() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, @@ -130,8 +147,8 @@ func TestAccAWSEksIdentityProviderConfig_disappears(t *testing.T) { { Config: testAccAWSEksIdentityProviderConfigProviderConfigName(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), - testAccCheckAWSEksIdentityProviderConfigDisappears(rName, &config), + testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), + testAccCheckResourceDisappears(testAccProvider, resourceAwsEksIdentityProviderConfig(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -140,9 +157,10 @@ func TestAccAWSEksIdentityProviderConfig_disappears(t *testing.T) { } func TestAccAWSEksIdentityProviderConfig_Oidc_Group(t *testing.T) { - var config eks.IdentityProviderConfig + var config eks.OidcIdentityProviderConfig rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_identity_provider_config.test" + ctx := context.TODO() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, @@ -153,7 +171,7 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_Group(t *testing.T) { { Config: testAccAWSEksIdentityProviderConfigProvider_Oidc_Groups(rName, "groups", "oidc:"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), resource.TestCheckResourceAttr(resourceName, "oidc.0.groups_claim", "groups"), resource.TestCheckResourceAttr(resourceName, "oidc.0.groups_prefix", "oidc:"), @@ -169,9 +187,10 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_Group(t *testing.T) { } func TestAccAWSEksIdentityProviderConfig_Oidc_Username(t *testing.T) { - var config eks.IdentityProviderConfig + var config eks.OidcIdentityProviderConfig rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_identity_provider_config.test" + ctx := context.TODO() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, @@ -182,7 +201,7 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_Username(t *testing.T) { { Config: testAccAWSEksIdentityProviderConfigProvider_Oidc_Username(rName, "email", "-"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), resource.TestCheckResourceAttr(resourceName, "oidc.0.username_claim", "email"), resource.TestCheckResourceAttr(resourceName, "oidc.0.username_prefix", "-"), @@ -198,9 +217,10 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_Username(t *testing.T) { } func TestAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(t *testing.T) { - var config eks.IdentityProviderConfig + var config eks.OidcIdentityProviderConfig rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_identity_provider_config.test" + ctx := context.TODO() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, @@ -219,7 +239,7 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(t *testing.T) { { Config: testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, "keyOne", "valueOne", "keyTwo", "valueTwo"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.%", "2"), resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.keyOne", "valueOne"), resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.keyTwo", "valueTwo"), @@ -235,9 +255,10 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(t *testing.T) { } func TestAccAWSEksIdentityProviderConfig_Tags(t *testing.T) { - var config eks.IdentityProviderConfig + var config eks.OidcIdentityProviderConfig rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_identity_provider_config.test" + ctx := context.TODO() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, @@ -248,7 +269,7 @@ func TestAccAWSEksIdentityProviderConfig_Tags(t *testing.T) { { Config: testAccAWSEksIdentityProviderConfig_Tags(rName, "keyOne", "valueOne", "keyTwo", "valueTwo"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksIdentityProviderConfigExists(resourceName, &config), + testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.keyOne", "valueOne"), resource.TestCheckResourceAttr(resourceName, "tags.keyTwo", "valueTwo"), @@ -263,7 +284,7 @@ func TestAccAWSEksIdentityProviderConfig_Tags(t *testing.T) { }) } -func testAccCheckAWSEksIdentityProviderConfigExists(resourceName string, config *eks.IdentityProviderConfig) resource.TestCheckFunc { +func testAccCheckAWSEksIdentityProviderConfigExists(ctx context.Context, resourceName string, config *eks.OidcIdentityProviderConfig) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -271,52 +292,31 @@ func testAccCheckAWSEksIdentityProviderConfigExists(resourceName string, config } if rs.Primary.ID == "" { - return fmt.Errorf("No EKS Identity Profile Config is set") + return fmt.Errorf("No EKS Identity Profile Config ID is set") } - clusterName, configName, err := resourceAwsEksIdentityProviderConfigParseId(rs.Primary.ID) + clusterName, configName, err := tfeks.IdentityProviderConfigParseResourceID(rs.Primary.ID) + if err != nil { return err } conn := testAccProvider.Meta().(*AWSClient).eksconn - input := &eks.DescribeIdentityProviderConfigInput{ - ClusterName: aws.String(clusterName), - IdentityProviderConfig: &eks.IdentityProviderConfig{ - Name: aws.String(configName), - Type: aws.String(typeOidc), - }, - } - - output, err := conn.DescribeIdentityProviderConfig(input) + output, err := finder.OidcIdentityProviderConfigByClusterNameAndConfigName(ctx, conn, clusterName, configName) if err != nil { return err } - if output == nil || output.IdentityProviderConfig == nil { - return fmt.Errorf("EKS Identity Provider Config (%s) not found", rs.Primary.ID) - } - - if aws.StringValue(output.IdentityProviderConfig.Oidc.IdentityProviderConfigName) != configName { - return fmt.Errorf("EKS OIDC Identity Provider Config (%s) not found", rs.Primary.ID) - } - - if got, want := aws.StringValue(output.IdentityProviderConfig.Oidc.Status), eks.ConfigStatusActive; got != want { - return fmt.Errorf("EKS OIDC Identity Provider Config (%s) not in %s status, got: %s", rs.Primary.ID, want, got) - } - - *config = eks.IdentityProviderConfig{ - Name: output.IdentityProviderConfig.Oidc.IdentityProviderConfigName, - Type: aws.String(typeOidc), - } + *config = *output return nil } } func testAccCheckAWSEksIdentityProviderConfigDestroy(s *terraform.State) error { + ctx := context.TODO() conn := testAccProvider.Meta().(*AWSClient).eksconn for _, rs := range s.RootModule().Resources { @@ -324,54 +324,26 @@ func testAccCheckAWSEksIdentityProviderConfigDestroy(s *terraform.State) error { continue } - clusterName, configName, err := resourceAwsEksIdentityProviderConfigParseId(rs.Primary.ID) + clusterName, configName, err := tfeks.IdentityProviderConfigParseResourceID(rs.Primary.ID) + if err != nil { return err } - input := &eks.DescribeIdentityProviderConfigInput{ - ClusterName: aws.String(clusterName), - IdentityProviderConfig: &eks.IdentityProviderConfig{ - Name: aws.String(configName), - Type: aws.String(typeOidc), - }, - } + _, err = finder.OidcIdentityProviderConfigByClusterNameAndConfigName(ctx, conn, clusterName, configName) - output, err := conn.DescribeIdentityProviderConfig(input) - - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { + if tfresource.NotFound(err) { continue } - if output != nil && output.IdentityProviderConfig != nil && aws.StringValue(output.IdentityProviderConfig.Oidc.IdentityProviderConfigName) == configName { - return fmt.Errorf("EKS Identity Provider Config (%s) still exists", rs.Primary.ID) - } - } - - return nil -} - -func testAccCheckAWSEksIdentityProviderConfigDisappears(clusterName string, config *eks.IdentityProviderConfig) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).eksconn - - input := &eks.DisassociateIdentityProviderConfigInput{ - ClusterName: aws.String(clusterName), - IdentityProviderConfig: config, - } - - _, err := conn.DisassociateIdentityProviderConfig(input) - - if isAWSErr(err, eks.ErrCodeResourceNotFoundException, "") { - return nil - } - if err != nil { return err } - return waitForEksIdentityProviderConfigDisassociation(context.TODO(), conn, clusterName, config, 25*time.Minute) + return fmt.Errorf("EKS Identity Profile Config %s still exists", rs.Primary.ID) } + + return nil } func testAccAWSEksIdentityProviderConfigBase(rName string) string { @@ -387,8 +359,8 @@ data "aws_availability_zones" "available" { data "aws_partition" "current" {} -resource "aws_iam_role" "cluster" { - name = "%[1]s-cluster" +resource "aws_iam_role" "test" { + name = %[1]q assume_role_policy = jsonencode({ Statement = [{ @@ -404,7 +376,7 @@ resource "aws_iam_role" "cluster" { resource "aws_iam_role_policy_attachment" "cluster-AmazonEKSClusterPolicy" { policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEKSClusterPolicy" - role = aws_iam_role.cluster.name + role = aws_iam_role.test.name } resource "aws_vpc" "test" { @@ -413,7 +385,7 @@ resource "aws_vpc" "test" { enable_dns_support = true tags = { - Name = "tf-acc-test-eks-identity-provider-config" + Name = %[1]q "kubernetes.io/cluster/%[1]s" = "shared" } } @@ -426,14 +398,14 @@ resource "aws_subnet" "test" { vpc_id = aws_vpc.test.id tags = { - Name = "tf-acc-test-eks-identity-provider-config" + Name = %[1]q "kubernetes.io/cluster/%[1]s" = "shared" } } resource "aws_eks_cluster" "test" { name = %[1]q - role_arn = aws_iam_role.cluster.arn + role_arn = aws_iam_role.test.arn vpc_config { subnet_ids = aws_subnet.test[*].id @@ -445,91 +417,98 @@ resource "aws_eks_cluster" "test" { } func testAccAWSEksIdentityProviderConfigProviderConfigName(rName string) string { - return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name + oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "example.net" identity_provider_config_name = %[1]q - issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + issuer_url = "https://example.com" } } -`, rName) +`, rName)) } func testAccAWSEksIdentityProviderConfigProvider_Oidc_IssuerUrl(rName, issuerUrl string) string { - return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name + oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "example.net" identity_provider_config_name = %[1]q issuer_url = %[2]q } } -`, rName, issuerUrl) +`, rName, issuerUrl)) } func testAccAWSEksIdentityProviderConfigProvider_Oidc_Groups(rName, groupsClaim, groupsPrefix string) string { - return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name + oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "example.net" groups_claim = %[2]q groups_prefix = %[3]q identity_provider_config_name = %[1]q - issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + issuer_url = "https://example.com" } } -`, rName, groupsClaim, groupsPrefix) +`, rName, groupsClaim, groupsPrefix)) } func testAccAWSEksIdentityProviderConfigProvider_Oidc_Username(rName, usernameClaim, usernamePrefix string) string { - return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name + oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "example.net" identity_provider_config_name = %[1]q - issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + issuer_url = "https://example.com" username_claim = %[2]q username_prefix = %[3]q } } -`, rName, usernameClaim, usernamePrefix) +`, rName, usernameClaim, usernamePrefix)) } func testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo string) string { - return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name + oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "example.net" identity_provider_config_name = %[1]q - issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + issuer_url = "https://example.com" required_claims = { %[2]q = %[3]q %[4]q = %[5]q } } } -`, rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo) +`, rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo)) } func testAccAWSEksIdentityProviderConfig_Tags(rName, tagsKeyOne, tagsValueOne, tagsKeyTwo, tagsValueTwo string) string { - return testAccAWSEksIdentityProviderConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name + oidc { - client_id = "test-url.apps.googleusercontent.com" + client_id = "example.net" identity_provider_config_name = %[1]q - issuer_url = "https://accounts.google.com/.well-known/openid-configuration" + issuer_url = "https://example.com" } + tags = { %[2]q = %[3]q %[4]q = %[5]q } } -`, rName, tagsKeyOne, tagsValueOne, tagsKeyTwo, tagsValueTwo) +`, rName, tagsKeyOne, tagsValueOne, tagsKeyTwo, tagsValueTwo)) } diff --git a/website/docs/r/eks_identity_provider_config.html.markdown b/website/docs/r/eks_identity_provider_config.html.markdown index 1aff5578d6cc..ac6840ce8be3 100644 --- a/website/docs/r/eks_identity_provider_config.html.markdown +++ b/website/docs/r/eks_identity_provider_config.html.markdown @@ -3,7 +3,7 @@ subcategory: "EKS" layout: "aws" page_title: "AWS: aws_eks_identity_provider_config" description: |- - Manages an EKS Identity Provider Configuration + Manages an EKS Identity Provider Configuration. --- # Resource: aws_eks_identity_provider_config @@ -15,6 +15,7 @@ Manages an EKS Identity Provider Configuration. ```terraform resource "aws_eks_identity_provider_config" "example" { cluster_name = aws_eks_cluster.example.name + oidc { client_id = "your client_id" identity_provider_config_name = "example" @@ -25,27 +26,28 @@ resource "aws_eks_identity_provider_config" "example" { ## Argument Reference -The following arguments are required: +The following arguments are supported: -* `cluster_name` – Name of the EKS Cluster. -* `oidc` - Nested attribute containing [OpenID Connect](https://openid.net/connect/) identity provider information for the cluster. - * `client_id` – Client ID for the OpenID Connect identity provider. - * `identity_provider_config_name` – The name of the identity provider config. - * `issuer_url` - Issuer URL for the OpenID Connect identity provider. +* `cluster_name` – (Required) Name of the EKS Cluster. +* `oidc` - (Required) Nested attribute containing [OpenID Connect](https://openid.net/connect/) identity provider information for the cluster. Detailed below. +* `tags` - (Optional) A map of tags to assign to the resource. -The following arguments are optional: +### oidc Configuration Block -* `oidc` - * `groups_claim` - The JWT claim that the provider will use to return groups. - * `groups_prefix` - A prefix that is prepended to group claims e.g. `oidc:`. - * `required_claims` - The key value pairs that describe required claims in the identity token. - * `username_claim` - The JWT claim that the provider will use as the username. - * `username_prefix` - A prefix that is prepended to username claims. -* `tags` - (Optional) Key-value map of resource tags. +* `client_id` – (Required) Client ID for the OpenID Connect identity provider. +* `groups_claim` - (Optional) The JWT claim that the provider will use to return groups. +* `groups_prefix` - (Optional) A prefix that is prepended to group claims e.g. `oidc:`. +* `identity_provider_config_name` – (Required) The name of the identity provider config. +* `issuer_url` - (Required) Issuer URL for the OpenID Connect identity provider. +* `required_claims` - (Optional) The key value pairs that describe required claims in the identity token. +* `username_claim` - (Optional) The JWT claim that the provider will use as the username. +* `username_prefix` - (Optional) A prefix that is prepended to username claims. ## Attributes Reference + In addition to all arguments above, the following attributes are exported: +* `arn` - Amazon Resource Name (ARN) of the EKS Identity Provider Configuration. * `id` - EKS Cluster name and EKS Identity Provider Configuration name separated by a colon (`:`). * `status` - Status of the EKS Identity Provider Configuration. @@ -58,7 +60,7 @@ In addition to all arguments above, the following attributes are exported: ## Import -EKS Identity Provider Configuration can be imported using the `cluster_name` and `identity_provider_config_name` separated by a colon (`:`), e.g. +EKS Identity Provider Configurations can be imported using the `cluster_name` and `identity_provider_config_name` separated by a colon (`:`), e.g. ``` $ terraform import aws_eks_identity_provider_config.my_identity_provider_config my_cluster:my_identity_provider_config From 1d7e5d1eb62c5c41d66c3b1e31b0974d823c877a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 7 Jul 2021 12:28:35 -0400 Subject: [PATCH 0973/1208] r/aws_eks_identity_provider_config: Tags can be updated; Add 'tags_all'. --- ...source_aws_eks_identity_provider_config.go | 37 ++++++++++++++++--- ...eks_identity_provider_config.html.markdown | 3 +- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_eks_identity_provider_config.go b/aws/resource_aws_eks_identity_provider_config.go index 6f37517df7f8..452fee75d96f 100644 --- a/aws/resource_aws_eks_identity_provider_config.go +++ b/aws/resource_aws_eks_identity_provider_config.go @@ -24,12 +24,15 @@ func resourceAwsEksIdentityProviderConfig() *schema.Resource { return &schema.Resource{ CreateContext: resourceAwsEksIdentityProviderConfigCreate, ReadContext: resourceAwsEksIdentityProviderConfigRead, + UpdateContext: resourceAwsEksIdentityProviderConfigUpdate, DeleteContext: resourceAwsEksIdentityProviderConfigDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, + CustomizeDiff: SetTagsDiff, + Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(25 * time.Minute), Delete: schema.DefaultTimeout(25 * time.Minute), @@ -116,7 +119,8 @@ func resourceAwsEksIdentityProviderConfig() *schema.Resource { Computed: true, }, - "tags": tagsSchemaForceNew(), + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, } } @@ -134,8 +138,10 @@ func allDiagFunc(validators ...schema.SchemaValidateDiagFunc) schema.SchemaValid func resourceAwsEksIdentityProviderConfigCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).eksconn - clusterName := d.Get("cluster_name").(string) + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) + clusterName := d.Get("cluster_name").(string) configName, oidc := expandEksOidcIdentityProviderConfigRequest(d.Get("oidc").([]interface{})[0].(map[string]interface{})) id := tfeks.IdentityProviderConfigCreateResourceID(clusterName, configName) @@ -145,8 +151,8 @@ func resourceAwsEksIdentityProviderConfigCreate(ctx context.Context, d *schema.R Oidc: oidc, } - if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { - input.Tags = keyvaluetags.New(v).IgnoreAws().EksTags() + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().EksTags() } _, err := conn.AssociateIdentityProviderConfig(input) @@ -168,6 +174,7 @@ func resourceAwsEksIdentityProviderConfigCreate(ctx context.Context, d *schema.R func resourceAwsEksIdentityProviderConfigRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).eksconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig clusterName, configName, err := tfeks.IdentityProviderConfigParseResourceID(d.Id()) @@ -197,13 +204,33 @@ func resourceAwsEksIdentityProviderConfigRead(ctx context.Context, d *schema.Res d.Set("status", oidc.Status) - if err := d.Set("tags", keyvaluetags.EksKeyValueTags(oidc.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + tags := keyvaluetags.EksKeyValueTags(oidc.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + + //lintignore:AWSR002 + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { return diag.Errorf("error setting tags: %s", err) } + if err := d.Set("tags_all", tags.Map()); err != nil { + return diag.Errorf("error setting tags_all: %s", err) + } + return nil } +func resourceAwsEksIdentityProviderConfigUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).eksconn + + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + if err := keyvaluetags.EksUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return diag.Errorf("error updating tags: %s", err) + } + } + + return resourceAwsEksIdentityProviderConfigRead(ctx, d, meta) +} + func resourceAwsEksIdentityProviderConfigDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).eksconn diff --git a/website/docs/r/eks_identity_provider_config.html.markdown b/website/docs/r/eks_identity_provider_config.html.markdown index ac6840ce8be3..ffe45bc08f53 100644 --- a/website/docs/r/eks_identity_provider_config.html.markdown +++ b/website/docs/r/eks_identity_provider_config.html.markdown @@ -30,7 +30,7 @@ The following arguments are supported: * `cluster_name` – (Required) Name of the EKS Cluster. * `oidc` - (Required) Nested attribute containing [OpenID Connect](https://openid.net/connect/) identity provider information for the cluster. Detailed below. -* `tags` - (Optional) A map of tags to assign to the resource. +* `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ### oidc Configuration Block @@ -50,6 +50,7 @@ In addition to all arguments above, the following attributes are exported: * `arn` - Amazon Resource Name (ARN) of the EKS Identity Provider Configuration. * `id` - EKS Cluster name and EKS Identity Provider Configuration name separated by a colon (`:`). * `status` - Status of the EKS Identity Provider Configuration. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block). ## Timeouts From 4125dae3b5ad4f757b4cdb61d685eae522835962 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 7 Jul 2021 12:29:14 -0400 Subject: [PATCH 0974/1208] r/aws_eks_identity_provider_config: Tweak test configurations. --- ...e_aws_eks_identity_provider_config_test.go | 105 +++++++++++------- 1 file changed, 65 insertions(+), 40 deletions(-) diff --git a/aws/resource_aws_eks_identity_provider_config_test.go b/aws/resource_aws_eks_identity_provider_config_test.go index 72bd5d6b3c2d..9d8cbfb7a616 100644 --- a/aws/resource_aws_eks_identity_provider_config_test.go +++ b/aws/resource_aws_eks_identity_provider_config_test.go @@ -102,11 +102,11 @@ func TestAccAWSEksIdentityProviderConfig_basic(t *testing.T) { CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksIdentityProviderConfigProvider_Oidc_IssuerUrl(rName, "http://example.com"), + Config: testAccAWSEksIdentityProviderConfigConfigIssuerUrl(rName, "http://example.com"), ExpectError: regexp.MustCompile(`expected .* to have a url with schema of: "https", got http://example.com`), }, { - Config: testAccAWSEksIdentityProviderConfigProviderConfigName(rName), + Config: testAccAWSEksIdentityProviderConfigConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "eks", regexp.MustCompile(fmt.Sprintf("identityproviderconfig/%[1]s/oidc/%[1]s/.+", rName))), @@ -145,7 +145,7 @@ func TestAccAWSEksIdentityProviderConfig_disappears(t *testing.T) { CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksIdentityProviderConfigProviderConfigName(rName), + Config: testAccAWSEksIdentityProviderConfigConfigName(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), testAccCheckResourceDisappears(testAccProvider, resourceAwsEksIdentityProviderConfig(), resourceName), @@ -156,7 +156,7 @@ func TestAccAWSEksIdentityProviderConfig_disappears(t *testing.T) { }) } -func TestAccAWSEksIdentityProviderConfig_Oidc_Group(t *testing.T) { +func TestAccAWSEksIdentityProviderConfig_OIDC_Groups(t *testing.T) { var config eks.OidcIdentityProviderConfig rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_identity_provider_config.test" @@ -169,7 +169,7 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_Group(t *testing.T) { CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksIdentityProviderConfigProvider_Oidc_Groups(rName, "groups", "oidc:"), + Config: testAccAWSEksIdentityProviderConfigConfigGroups(rName, "groups", "oidc:"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), @@ -186,7 +186,7 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_Group(t *testing.T) { }) } -func TestAccAWSEksIdentityProviderConfig_Oidc_Username(t *testing.T) { +func TestAccAWSEksIdentityProviderConfig_OIDC_Username(t *testing.T) { var config eks.OidcIdentityProviderConfig rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_identity_provider_config.test" @@ -199,7 +199,7 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_Username(t *testing.T) { CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksIdentityProviderConfigProvider_Oidc_Username(rName, "email", "-"), + Config: testAccAWSEksIdentityProviderConfigConfigUsername(rName, "email", "-"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), @@ -216,7 +216,7 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_Username(t *testing.T) { }) } -func TestAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(t *testing.T) { +func TestAccAWSEksIdentityProviderConfig_OIDC_RequiredClaims(t *testing.T) { var config eks.OidcIdentityProviderConfig rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_identity_provider_config.test" @@ -229,15 +229,15 @@ func TestAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(t *testing.T) { CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, "4qkvw9k2RbpSO6wgCbynY10T6Rc2n89PQblyi6bZ5VhfpMr6V7FVvrA12FiJxarh", "valueOne", "keyTwo", "valueTwo"), + Config: testAccAWSEksIdentityProviderConfigConfigRequiredClaims(rName, "4qkvw9k2RbpSO6wgCbynY10T6Rc2n89PQblyi6bZ5VhfpMr6V7FVvrA12FiJxarh", "valueOne", "keyTwo", "valueTwo"), ExpectError: regexp.MustCompile("Bad map key length"), }, { - Config: testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, "keyOne", "bUUUiuIXeFGw0M2VwiCVjR8oIIavv0PF49Ba6yNwOOC7IcoLawczSeb6MpEIhqtXKcf9aogW4uc4smLGvdTQ8uTTkVFvQTPyWXQ3F0uZP02YyoSw0d9MZ7laGRjpXSph9oFE2UlT5IyRaXIsTwl1qvItvVXLN40Pd3PDyPa6de4nlYcRNy6YIikZz2P1QUSYuvMGSJxGUzhTKYRUniolIt1vjHsXt3MAsaJtCcWz0tjLWalvG27pQ3Gl5Cs7K1", "keyTwo", "valueTwo"), + Config: testAccAWSEksIdentityProviderConfigConfigRequiredClaims(rName, "keyOne", "bUUUiuIXeFGw0M2VwiCVjR8oIIavv0PF49Ba6yNwOOC7IcoLawczSeb6MpEIhqtXKcf9aogW4uc4smLGvdTQ8uTTkVFvQTPyWXQ3F0uZP02YyoSw0d9MZ7laGRjpXSph9oFE2UlT5IyRaXIsTwl1qvItvVXLN40Pd3PDyPa6de4nlYcRNy6YIikZz2P1QUSYuvMGSJxGUzhTKYRUniolIt1vjHsXt3MAsaJtCcWz0tjLWalvG27pQ3Gl5Cs7K1", "keyTwo", "valueTwo"), ExpectError: regexp.MustCompile("Bad map value length"), }, { - Config: testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, "keyOne", "valueOne", "keyTwo", "valueTwo"), + Config: testAccAWSEksIdentityProviderConfigConfigRequiredClaims(rName, "keyOne", "valueOne", "keyTwo", "valueTwo"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.%", "2"), @@ -267,12 +267,11 @@ func TestAccAWSEksIdentityProviderConfig_Tags(t *testing.T) { CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksIdentityProviderConfig_Tags(rName, "keyOne", "valueOne", "keyTwo", "valueTwo"), + Config: testAccAWSEksIdentityProviderConfigConfigTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.keyOne", "valueOne"), - resource.TestCheckResourceAttr(resourceName, "tags.keyTwo", "valueTwo"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { @@ -280,6 +279,23 @@ func TestAccAWSEksIdentityProviderConfig_Tags(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccAWSEksIdentityProviderConfigConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSEksIdentityProviderConfigConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, }, }) } @@ -346,17 +362,8 @@ func testAccCheckAWSEksIdentityProviderConfigDestroy(s *terraform.State) error { return nil } -func testAccAWSEksIdentityProviderConfigBase(rName string) string { - return fmt.Sprintf(` -data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } -} - +func testAccAWSEksIdentityProviderConfigConfigBase(rName string) string { + return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(` data "aws_partition" "current" {} resource "aws_iam_role" "test" { @@ -413,11 +420,11 @@ resource "aws_eks_cluster" "test" { depends_on = [aws_iam_role_policy_attachment.cluster-AmazonEKSClusterPolicy] } -`, rName) +`, rName)) } -func testAccAWSEksIdentityProviderConfigProviderConfigName(rName string) string { - return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` +func testAccAWSEksIdentityProviderConfigConfigName(rName string) string { + return composeConfig(testAccAWSEksIdentityProviderConfigConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name @@ -430,8 +437,8 @@ resource "aws_eks_identity_provider_config" "test" { `, rName)) } -func testAccAWSEksIdentityProviderConfigProvider_Oidc_IssuerUrl(rName, issuerUrl string) string { - return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` +func testAccAWSEksIdentityProviderConfigConfigIssuerUrl(rName, issuerUrl string) string { + return composeConfig(testAccAWSEksIdentityProviderConfigConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name @@ -444,8 +451,8 @@ resource "aws_eks_identity_provider_config" "test" { `, rName, issuerUrl)) } -func testAccAWSEksIdentityProviderConfigProvider_Oidc_Groups(rName, groupsClaim, groupsPrefix string) string { - return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` +func testAccAWSEksIdentityProviderConfigConfigGroups(rName, groupsClaim, groupsPrefix string) string { + return composeConfig(testAccAWSEksIdentityProviderConfigConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name @@ -460,8 +467,8 @@ resource "aws_eks_identity_provider_config" "test" { `, rName, groupsClaim, groupsPrefix)) } -func testAccAWSEksIdentityProviderConfigProvider_Oidc_Username(rName, usernameClaim, usernamePrefix string) string { - return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` +func testAccAWSEksIdentityProviderConfigConfigUsername(rName, usernameClaim, usernamePrefix string) string { + return composeConfig(testAccAWSEksIdentityProviderConfigConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name @@ -476,8 +483,8 @@ resource "aws_eks_identity_provider_config" "test" { `, rName, usernameClaim, usernamePrefix)) } -func testAccAWSEksIdentityProviderConfig_Oidc_RequiredClaims(rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo string) string { - return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` +func testAccAWSEksIdentityProviderConfigConfigRequiredClaims(rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo string) string { + return composeConfig(testAccAWSEksIdentityProviderConfigConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name @@ -494,8 +501,26 @@ resource "aws_eks_identity_provider_config" "test" { `, rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo)) } -func testAccAWSEksIdentityProviderConfig_Tags(rName, tagsKeyOne, tagsValueOne, tagsKeyTwo, tagsValueTwo string) string { - return composeConfig(testAccAWSEksIdentityProviderConfigBase(rName), fmt.Sprintf(` +func testAccAWSEksIdentityProviderConfigConfigTags1(rName, tagKey1, tagValue1 string) string { + return composeConfig(testAccAWSEksIdentityProviderConfigConfigBase(rName), fmt.Sprintf(` +resource "aws_eks_identity_provider_config" "test" { + cluster_name = aws_eks_cluster.test.name + + oidc { + client_id = "example.net" + identity_provider_config_name = %[1]q + issuer_url = "https://example.com" + } + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1)) +} + +func testAccAWSEksIdentityProviderConfigConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return composeConfig(testAccAWSEksIdentityProviderConfigConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name @@ -510,5 +535,5 @@ resource "aws_eks_identity_provider_config" "test" { %[4]q = %[5]q } } -`, rName, tagsKeyOne, tagsValueOne, tagsKeyTwo, tagsValueTwo)) +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } From 518228c504d812694dcf970ab92830700b080927 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 7 Jul 2021 12:38:17 -0400 Subject: [PATCH 0975/1208] r/aws_eks_identity_provider_config: Consolidate to 'TestAccAWSEksIdentityProviderConfig_AllOidcOptions'. --- ...e_aws_eks_identity_provider_config_test.go | 117 +++--------------- 1 file changed, 15 insertions(+), 102 deletions(-) diff --git a/aws/resource_aws_eks_identity_provider_config_test.go b/aws/resource_aws_eks_identity_provider_config_test.go index 9d8cbfb7a616..db33da83f0fd 100644 --- a/aws/resource_aws_eks_identity_provider_config_test.go +++ b/aws/resource_aws_eks_identity_provider_config_test.go @@ -156,7 +156,7 @@ func TestAccAWSEksIdentityProviderConfig_disappears(t *testing.T) { }) } -func TestAccAWSEksIdentityProviderConfig_OIDC_Groups(t *testing.T) { +func TestAccAWSEksIdentityProviderConfig_AllOidcOptions(t *testing.T) { var config eks.OidcIdentityProviderConfig rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_eks_identity_provider_config.test" @@ -169,80 +169,20 @@ func TestAccAWSEksIdentityProviderConfig_OIDC_Groups(t *testing.T) { CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksIdentityProviderConfigConfigGroups(rName, "groups", "oidc:"), + Config: testAccAWSEksIdentityProviderConfigAllOidcOptions(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.client_id", "example.net"), resource.TestCheckResourceAttr(resourceName, "oidc.0.groups_claim", "groups"), resource.TestCheckResourceAttr(resourceName, "oidc.0.groups_prefix", "oidc:"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccAWSEksIdentityProviderConfig_OIDC_Username(t *testing.T) { - var config eks.OidcIdentityProviderConfig - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_eks_identity_provider_config.test" - ctx := context.TODO() - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, - ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), - ProviderFactories: testAccProviderFactories, - CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSEksIdentityProviderConfigConfigUsername(rName, "email", "-"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), - resource.TestCheckResourceAttr(resourceName, "oidc.#", "1"), - resource.TestCheckResourceAttr(resourceName, "oidc.0.username_claim", "email"), - resource.TestCheckResourceAttr(resourceName, "oidc.0.username_prefix", "-"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccAWSEksIdentityProviderConfig_OIDC_RequiredClaims(t *testing.T) { - var config eks.OidcIdentityProviderConfig - rName := acctest.RandomWithPrefix("tf-acc-test") - resourceName := "aws_eks_identity_provider_config.test" - ctx := context.TODO() - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, - ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), - ProviderFactories: testAccProviderFactories, - CheckDestroy: testAccCheckAWSEksIdentityProviderConfigDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSEksIdentityProviderConfigConfigRequiredClaims(rName, "4qkvw9k2RbpSO6wgCbynY10T6Rc2n89PQblyi6bZ5VhfpMr6V7FVvrA12FiJxarh", "valueOne", "keyTwo", "valueTwo"), - ExpectError: regexp.MustCompile("Bad map key length"), - }, - { - Config: testAccAWSEksIdentityProviderConfigConfigRequiredClaims(rName, "keyOne", "bUUUiuIXeFGw0M2VwiCVjR8oIIavv0PF49Ba6yNwOOC7IcoLawczSeb6MpEIhqtXKcf9aogW4uc4smLGvdTQ8uTTkVFvQTPyWXQ3F0uZP02YyoSw0d9MZ7laGRjpXSph9oFE2UlT5IyRaXIsTwl1qvItvVXLN40Pd3PDyPa6de4nlYcRNy6YIikZz2P1QUSYuvMGSJxGUzhTKYRUniolIt1vjHsXt3MAsaJtCcWz0tjLWalvG27pQ3Gl5Cs7K1", "keyTwo", "valueTwo"), - ExpectError: regexp.MustCompile("Bad map value length"), - }, - { - Config: testAccAWSEksIdentityProviderConfigConfigRequiredClaims(rName, "keyOne", "valueOne", "keyTwo", "valueTwo"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSEksIdentityProviderConfigExists(ctx, resourceName, &config), + resource.TestCheckResourceAttr(resourceName, "oidc.0.identity_provider_config_name", rName), + resource.TestCheckResourceAttr(resourceName, "oidc.0.issuer_url", "https://example.com"), resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.%", "2"), resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.keyOne", "valueOne"), resource.TestCheckResourceAttr(resourceName, "oidc.0.required_claims.keyTwo", "valueTwo"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.username_claim", "email"), + resource.TestCheckResourceAttr(resourceName, "oidc.0.username_prefix", "-"), ), }, { @@ -451,54 +391,27 @@ resource "aws_eks_identity_provider_config" "test" { `, rName, issuerUrl)) } -func testAccAWSEksIdentityProviderConfigConfigGroups(rName, groupsClaim, groupsPrefix string) string { +func testAccAWSEksIdentityProviderConfigAllOidcOptions(rName string) string { return composeConfig(testAccAWSEksIdentityProviderConfigConfigBase(rName), fmt.Sprintf(` resource "aws_eks_identity_provider_config" "test" { cluster_name = aws_eks_cluster.test.name oidc { client_id = "example.net" - groups_claim = %[2]q - groups_prefix = %[3]q + groups_claim = "groups" + groups_prefix = "oidc:" identity_provider_config_name = %[1]q issuer_url = "https://example.com" - } -} -`, rName, groupsClaim, groupsPrefix)) -} + username_claim = "email" + username_prefix = "-" -func testAccAWSEksIdentityProviderConfigConfigUsername(rName, usernameClaim, usernamePrefix string) string { - return composeConfig(testAccAWSEksIdentityProviderConfigConfigBase(rName), fmt.Sprintf(` -resource "aws_eks_identity_provider_config" "test" { - cluster_name = aws_eks_cluster.test.name - - oidc { - client_id = "example.net" - identity_provider_config_name = %[1]q - issuer_url = "https://example.com" - username_claim = %[2]q - username_prefix = %[3]q - } -} -`, rName, usernameClaim, usernamePrefix)) -} - -func testAccAWSEksIdentityProviderConfigConfigRequiredClaims(rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo string) string { - return composeConfig(testAccAWSEksIdentityProviderConfigConfigBase(rName), fmt.Sprintf(` -resource "aws_eks_identity_provider_config" "test" { - cluster_name = aws_eks_cluster.test.name - - oidc { - client_id = "example.net" - identity_provider_config_name = %[1]q - issuer_url = "https://example.com" required_claims = { - %[2]q = %[3]q - %[4]q = %[5]q + keyOne = "valueOne" + keyTwo = "valueTwo" } } } -`, rName, claimsKeyOne, claimsValueOne, claimsKeyTwo, claimsValueTwo)) +`, rName)) } func testAccAWSEksIdentityProviderConfigConfigTags1(rName, tagKey1, tagValue1 string) string { From 2e094957c187c7961cf0af65ee8c0716495803e4 Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Tue, 18 May 2021 20:49:29 +0000 Subject: [PATCH 0976/1208] don't report diff when proposal is gone --- aws/resource_aws_dx_gateway_association_proposal.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index 9716ff0c908e..3c626c4a6d57 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -32,7 +32,12 @@ func resourceAwsDxGatewayAssociationProposal() *schema.Resource { return false } - return proposal != nil && aws.StringValue(proposal.ProposalState) == directconnect.GatewayAssociationProposalStateRequested + if proposal == nil { + // Don't report as a diff when the proposal is gone. + return true + } + + return aws.StringValue(proposal.ProposalState) == directconnect.GatewayAssociationProposalStateRequested }), ), From 8c198a13354167c255af4f53d7c986dacdbcf8fb Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Tue, 18 May 2021 23:28:28 +0000 Subject: [PATCH 0977/1208] Populate proposal state using found association Once the proposal has been accepted and deleted, locate the association, populate the proposal state to prevent recreating the proposal unnecessarily. --- ...rce_aws_dx_gateway_association_proposal.go | 94 +++++++++++++++---- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index 3c626c4a6d57..ae52d5c2a502 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directconnect" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -109,31 +110,52 @@ func resourceAwsDxGatewayAssociationProposalRead(d *schema.ResourceData, meta in } if proposal == nil { - log.Printf("[WARN] Direct Connect Gateway Association Proposal (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } + associatedGatewayId, ok := d.GetOk("associated_gateway_id") - if aws.StringValue(proposal.ProposalState) == directconnect.GatewayAssociationProposalStateDeleted { - log.Printf("[WARN] Direct Connect Gateway Association Proposal (%s) deleted, removing from state", d.Id()) - d.SetId("") - return nil - } + if !ok || associatedGatewayId == nil { + return fmt.Errorf("error reading Direct Connect Associated Gateway Id (%s): %s", d.Id(), err) + } - if proposal.AssociatedGateway == nil { - return fmt.Errorf("error reading Direct Connect Gateway Association Proposal (%s): missing associated gateway information", d.Id()) - } + assocRaw, state, err := getDxGatewayAssociation(conn, associatedGatewayId.(string))() - if err := d.Set("allowed_prefixes", flattenDirectConnectGatewayAssociationProposalAllowedPrefixes(proposal.RequestedAllowedPrefixesToDirectConnectGateway)); err != nil { - return fmt.Errorf("error setting allowed_prefixes: %s", err) - } + if err != nil { + return fmt.Errorf("error reading Direct Connect gateway association (%s): %s", d.Id(), err) + } + + if state == gatewayAssociationStateDeleted { + log.Printf("[WARN] Direct Connect gateway association (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + log.Printf("[INFO] Direct Connect Gateway Association Proposal (%s) has been accepted", d.Id()) + assoc := assocRaw.(*directconnect.GatewayAssociation) + d.Set("associated_gateway_id", assoc.AssociatedGateway.Id) + d.Set("dx_gateway_id", assoc.DirectConnectGatewayId) + d.Set("dx_gateway_owner_account_id", assoc.DirectConnectGatewayOwnerAccount) + } else { + + if aws.StringValue(proposal.ProposalState) == directconnect.GatewayAssociationProposalStateDeleted { + log.Printf("[WARN] Direct Connect Gateway Association Proposal (%s) deleted, removing from state", d.Id()) + d.SetId("") + return nil + } + + if proposal.AssociatedGateway == nil { + return fmt.Errorf("error reading Direct Connect Gateway Association Proposal (%s): missing associated gateway information", d.Id()) + } - d.Set("associated_gateway_id", proposal.AssociatedGateway.Id) - d.Set("associated_gateway_owner_account_id", proposal.AssociatedGateway.OwnerAccount) - d.Set("associated_gateway_type", proposal.AssociatedGateway.Type) - d.Set("dx_gateway_id", proposal.DirectConnectGatewayId) - d.Set("dx_gateway_owner_account_id", proposal.DirectConnectGatewayOwnerAccount) + if err := d.Set("allowed_prefixes", flattenDirectConnectGatewayAssociationProposalAllowedPrefixes(proposal.RequestedAllowedPrefixesToDirectConnectGateway)); err != nil { + return fmt.Errorf("error setting allowed_prefixes: %s", err) + } + + d.Set("associated_gateway_id", proposal.AssociatedGateway.Id) + d.Set("associated_gateway_owner_account_id", proposal.AssociatedGateway.OwnerAccount) + d.Set("associated_gateway_type", proposal.AssociatedGateway.Type) + d.Set("dx_gateway_id", proposal.DirectConnectGatewayId) + d.Set("dx_gateway_owner_account_id", proposal.DirectConnectGatewayOwnerAccount) + } return nil } @@ -228,3 +250,35 @@ func flattenDirectConnectGatewayAssociationProposalAllowedPrefixes(routeFilterPr return allowedPrefixes } + +func getDxGatewayAssociation(conn *directconnect.DirectConnect, associatedGatewayId string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + resp, err := conn.DescribeDirectConnectGatewayAssociations(&directconnect.DescribeDirectConnectGatewayAssociationsInput{ + AssociatedGatewayId: aws.String(associatedGatewayId), + }) + if err != nil { + return nil, "", err + } + + n := len(resp.DirectConnectGatewayAssociations) + switch n { + case 0: + return "", gatewayAssociationStateDeleted, nil + + case 1: + assoc := resp.DirectConnectGatewayAssociations[0] + + if stateChangeError := aws.StringValue(assoc.StateChangeError); stateChangeError != "" { + id := dxGatewayAssociationId( + aws.StringValue(resp.DirectConnectGatewayAssociations[0].DirectConnectGatewayId), + aws.StringValue(resp.DirectConnectGatewayAssociations[0].AssociatedGateway.Id)) + log.Printf("[INFO] Direct Connect gateway association (%s) state change error: %s", id, stateChangeError) + } + + return assoc, aws.StringValue(assoc.AssociationState), nil + + default: + return nil, "", fmt.Errorf("Found %d Direct Connect gateway associations for %s, expected 1", n, associatedGatewayId) + } + } +} From 7f5ae58483e5c737905d66d619d618058792449b Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Mon, 24 May 2021 15:43:38 +0000 Subject: [PATCH 0978/1208] WIP activate debug code path for testing --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 3f721524f186..b33c29c4b924 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,7 @@ import ( func main() { var debugMode bool - flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve") + flag.BoolVar(&debugMode, "debug", true, "set to true to run the provider with support for debuggers like delve") flag.Parse() opts := &plugin.ServeOpts{ProviderFunc: aws.Provider} From 19b40437567ca43132bb66a91bc3473e1a88dfd9 Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Mon, 24 May 2021 15:45:16 +0000 Subject: [PATCH 0979/1208] collect state information from associated gateway to determine if proposal needs to be recreated. --- ...ource_aws_dx_gateway_association_proposal.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index ae52d5c2a502..7764f816f9c5 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -34,7 +34,22 @@ func resourceAwsDxGatewayAssociationProposal() *schema.Resource { } if proposal == nil { - // Don't report as a diff when the proposal is gone. + // Don't report as a diff when the proposal is gone unless the association is gone too. + associatedGatewayId, ok := d.GetOk("associated_gateway_id") + + if !ok || associatedGatewayId == nil { + return false + } + + _, state, err := getDxGatewayAssociation(conn, associatedGatewayId.(string))() + + if err != nil { + return false + } + + if state == gatewayAssociationStateDeleted { + return false + } return true } From 363a76288d2e03a38e4d0aa7bab4d1f5ee34f619 Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Mon, 24 May 2021 18:36:35 +0000 Subject: [PATCH 0980/1208] when associated gateway is not found or errors, assume we need the proposal --- aws/resource_aws_dx_gateway_association_proposal.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index 7764f816f9c5..01596db393df 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -128,12 +128,14 @@ func resourceAwsDxGatewayAssociationProposalRead(d *schema.ResourceData, meta in associatedGatewayId, ok := d.GetOk("associated_gateway_id") if !ok || associatedGatewayId == nil { + d.SetId("") return fmt.Errorf("error reading Direct Connect Associated Gateway Id (%s): %s", d.Id(), err) } assocRaw, state, err := getDxGatewayAssociation(conn, associatedGatewayId.(string))() if err != nil { + d.SetId("") return fmt.Errorf("error reading Direct Connect gateway association (%s): %s", d.Id(), err) } From 76c016d912c830fc8a6f0cda62f3d2e82260c261 Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Wed, 9 Jun 2021 20:38:49 +0000 Subject: [PATCH 0981/1208] provide some commentary for clarity --- aws/resource_aws_dx_gateway_association_proposal.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index 01596db393df..3ccbf3192526 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -145,6 +145,9 @@ func resourceAwsDxGatewayAssociationProposalRead(d *schema.ResourceData, meta in return nil } + // once accepted, AWS will delete the proposal after after some time (days?) + // in this case we don't need to create a new proposal, use metadata from the association + // to artificially populate the missing proposal in state as if it was still there. log.Printf("[INFO] Direct Connect Gateway Association Proposal (%s) has been accepted", d.Id()) assoc := assocRaw.(*directconnect.GatewayAssociation) d.Set("associated_gateway_id", assoc.AssociatedGateway.Id) From 1f410034d67b57c6254b10cf4c45a497eb91232f Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Wed, 9 Jun 2021 20:44:21 +0000 Subject: [PATCH 0982/1208] add test to cover proposal end of life --- ...ws_dx_gateway_association_proposal_test.go | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index bf834a4897af..c53cb4276e42 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -185,6 +185,34 @@ func TestAccAwsDxGatewayAssociationProposal_disappears(t *testing.T) { }) } +func TestAccAwsDxGatewayAssociationProposal_endOfLife(t *testing.T) { + var proposal1 directconnect.GatewayAssociationProposal + var providers []*schema.Provider + rBgpAsn := acctest.RandIntRange(64512, 65534) + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_dx_gateway_association_proposal.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), + ProviderFactories: testAccProviderFactoriesAlternate(&providers), + CheckDestroy: testAccCheckAwsDxGatewayAssociationProposalDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDxGatewayAssociationProposalConfig_endOfLife(rName, rBgpAsn), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal1), + testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName), + testAccCheckAwsDxGatewayAssociationProposalDisappears(&proposal1), + ), + }, + }, + }) +} + func TestAccAwsDxGatewayAssociationProposal_AllowedPrefixes(t *testing.T) { var proposal1, proposal2 directconnect.GatewayAssociationProposal var providers []*schema.Provider @@ -336,6 +364,20 @@ resource "aws_dx_gateway_association_proposal" "test" { ` } +func testAccDxGatewayAssociationProposalConfig_endOfLife(rName string, rBgpAsn int) string { + return testAccDxGatewayAssociationProposalConfig_basicVpnGateway(rName, rBgpAsn) + ` +data "aws_caller_identity" "current" {} + +resource "aws_dx_gateway_association" "test" { +provider = "awsalternate" + +proposal_id = aws_dx_gateway_association_proposal.test.id +dx_gateway_id = aws_dx_gateway.test.id +associated_gateway_owner_account_id = data.aws_caller_identity.current.account_id +} +` +} + func testAccDxGatewayAssociationProposalConfig_basicTransitGateway(rName string, rBgpAsn int) string { return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` resource "aws_dx_gateway" "test" { @@ -385,3 +427,29 @@ resource "aws_dx_gateway_association_proposal" "test" { } ` } + +func testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).dxconn + + proposal, err := describeDirectConnectGatewayAssociationProposal(conn, rs.Primary.ID) + + if err != nil { + return err + } + + if proposal == nil { + return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not found", rs.Primary.ID) + } + + if aws.StringValue(proposal.ProposalState) != "accepted" { + return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not accepted", rs.Primary.ID) + } + return nil + } +} From 69feb2ffbe1c3ed80e3753ab00e4086560b8bc3d Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Wed, 9 Jun 2021 21:55:31 +0000 Subject: [PATCH 0983/1208] reset debug mode default --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index b33c29c4b924..3f721524f186 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,7 @@ import ( func main() { var debugMode bool - flag.BoolVar(&debugMode, "debug", true, "set to true to run the provider with support for debuggers like delve") + flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve") flag.Parse() opts := &plugin.ServeOpts{ProviderFunc: aws.Provider} From 69767a47896686ed1f4c4ed3a729009d0cc11035 Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Mon, 21 Jun 2021 15:12:03 -0700 Subject: [PATCH 0984/1208] allow import dx gateway assoc poroposal after EOL accept an import string composed of the proposal id, dx gateway id, and target associated gateway id when the proposal has been removed by AWS due to it being accepted. --- ...rce_aws_dx_gateway_association_proposal.go | 64 +++++++++++++++- ...ws_dx_gateway_association_proposal_test.go | 75 ++++++++++++------- 2 files changed, 112 insertions(+), 27 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index 3ccbf3192526..18bd1a6184fd 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directconnect" @@ -18,7 +19,7 @@ func resourceAwsDxGatewayAssociationProposal() *schema.Resource { Read: resourceAwsDxGatewayAssociationProposalRead, Delete: resourceAwsDxGatewayAssociationProposalDelete, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: dxGatewayAssociationProposalImport, }, CustomizeDiff: customdiff.Sequence( @@ -271,6 +272,67 @@ func flattenDirectConnectGatewayAssociationProposalAllowedPrefixes(routeFilterPr return allowedPrefixes } +func dxGatewayAssociationProposalImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + // example: c2ede9b4-bbc6-4d33-923c-bc4feEXAMPLE/186c8187-36f4-472e-9268-107aaEXAMPLE/0d95359280EXAMPLE + + errStr := "unexpected format of import string (%q), expected PROPOSALID/DXGATEWAYID/TARGETGATEWAYID]*: %s" + importStr := d.Id() + log.Printf("[DEBUG] Validating import string %s", importStr) + + parts := strings.Split(strings.ToLower(importStr), "/") + if len(parts) < 1 { + return nil, fmt.Errorf(errStr, importStr, "too few parts") + } + var propId, dxgwId, gwId string + propId = parts[0] + + conn := meta.(*AWSClient).dxconn + if propId != "" { + p, err := describeDirectConnectGatewayAssociationProposal(conn, propId) + if err != nil { + return nil, err + } + if p != nil { + // proposal still exists normal import + return schema.ImportStatePassthrough(d, meta) + } + // proposal may not exist, but that's fine + } + d.SetId(propId) + + if len(parts) == 1 { + // requesting just the prop id + return schema.ImportStatePassthrough(d, meta) + } else if len(parts) < 3 { + return nil, fmt.Errorf(errStr, importStr, "too few parts") + } + + dxgwId = parts[1] + gwId = parts[2] + + if gwId != "" && dxgwId != "" { + input := directconnect.DescribeDirectConnectGatewayAssociationsInput{ + AssociatedGatewayId: aws.String(gwId), + DirectConnectGatewayId: aws.String(dxgwId), + } + resp, err := conn.DescribeDirectConnectGatewayAssociations(&input) + if err != nil { + return nil, err + } + + id := dxGatewayAssociationId(dxgwId, gwId) + if n := len(resp.DirectConnectGatewayAssociations); n != 1 { + return nil, fmt.Errorf("Found %d Direct Connect gateway associations for %s, expected 1", n, id) + } + d.Set("associated_gateway_id", gwId) + d.Set("dx_gateway_id", dxgwId) + } else { + return nil, fmt.Errorf(errStr, importStr, "missing parts") + } + + return []*schema.ResourceData{d}, nil +} + func getDxGatewayAssociation(conn *directconnect.DirectConnect, associatedGatewayId string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeDirectConnectGatewayAssociations(&directconnect.DescribeDirectConnectGatewayAssociationsInput{ diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index c53cb4276e42..cc66d2e9e461 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "strings" "testing" "github.com/aws/aws-sdk-go/aws" @@ -209,6 +210,18 @@ func TestAccAwsDxGatewayAssociationProposal_endOfLife(t *testing.T) { testAccCheckAwsDxGatewayAssociationProposalDisappears(&proposal1), ), }, + { + ResourceName: resourceName, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + return strings.Join([]string{ + aws.StringValue(proposal1.ProposalId), + aws.StringValue(proposal1.DirectConnectGatewayId), + aws.StringValue(proposal1.AssociatedGateway.Id), + }, "/"), nil + }, + ImportState: true, + ImportStateVerify: false, // proposal attributes not applicable when it does not exist + }, }, }) } @@ -327,6 +340,42 @@ func testAccCheckAwsDxGatewayAssociationProposalRecreated(i, j *directconnect.Ga } } +func testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).dxconn + + proposal, err := describeDirectConnectGatewayAssociationProposal(conn, rs.Primary.ID) + + if err != nil { + return err + } + + if proposal == nil { + return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not found", rs.Primary.ID) + } + + if aws.StringValue(proposal.ProposalState) != "accepted" { + return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not accepted", rs.Primary.ID) + } + return nil + } +} + +func testAccDxGatewayAssociationProposalImportStateIdFunc(proposal *directconnect.GatewayAssociationProposal) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + return strings.Join([]string{ + aws.StringValue(proposal.ProposalId), + aws.StringValue(proposal.DirectConnectGatewayId), + aws.StringValue(proposal.AssociatedGateway.Id), + }, "/"), nil + } +} + func testAccDxGatewayAssociationProposalConfigBase_vpnGateway(rName string, rBgpAsn int) string { return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` resource "aws_dx_gateway" "test" { @@ -427,29 +476,3 @@ resource "aws_dx_gateway_association_proposal" "test" { } ` } - -func testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[resourceName] - if !ok { - return fmt.Errorf("Not found: %s", resourceName) - } - - conn := testAccProvider.Meta().(*AWSClient).dxconn - - proposal, err := describeDirectConnectGatewayAssociationProposal(conn, rs.Primary.ID) - - if err != nil { - return err - } - - if proposal == nil { - return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not found", rs.Primary.ID) - } - - if aws.StringValue(proposal.ProposalState) != "accepted" { - return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not accepted", rs.Primary.ID) - } - return nil - } -} From 925c9dff1670a049b001a2b2fc322e4c555be0db Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Tue, 22 Jun 2021 15:29:14 -0700 Subject: [PATCH 0985/1208] defer existance checks to Read function move proposal existance logic out of custom diff function and over into the Read function. add more debug logs to track when proposal id values exist --- ...rce_aws_dx_gateway_association_proposal.go | 78 ++++++++++++------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index 18bd1a6184fd..588c5db09cc9 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -26,6 +26,15 @@ func resourceAwsDxGatewayAssociationProposal() *schema.Resource { // Accepting the proposal with overridden prefixes changes the returned RequestedAllowedPrefixesToDirectConnectGateway value (allowed_prefixes attribute). // We only want to force a new resource if this value changes and the current proposal state is "requested". customdiff.ForceNewIf("allowed_prefixes", func(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool { + + log.Printf("[DEBUG] Checking diff for Direct Connect Gateway Association Proposal (%s) allowed_prefixes", d.Id()) + + if len(strings.Join(strings.Fields(d.Id()), "")) < 1 { + log.Printf("[WARN] Direct Connect Gateway Association Proposal Id not available (%s)", d.Id()) + // assume proposal is end-of-life, rely on Read func to test + return false + } + conn := meta.(*AWSClient).dxconn proposal, err := describeDirectConnectGatewayAssociationProposal(conn, d.Id()) @@ -35,23 +44,8 @@ func resourceAwsDxGatewayAssociationProposal() *schema.Resource { } if proposal == nil { - // Don't report as a diff when the proposal is gone unless the association is gone too. - associatedGatewayId, ok := d.GetOk("associated_gateway_id") - - if !ok || associatedGatewayId == nil { - return false - } - - _, state, err := getDxGatewayAssociation(conn, associatedGatewayId.(string))() - - if err != nil { - return false - } - - if state == gatewayAssociationStateDeleted { - return false - } - return true + // proposal maybe end-of-life and removed by AWS, existence checked in Read func + return false } return aws.StringValue(proposal.ProposalState) == directconnect.GatewayAssociationProposalStateRequested @@ -117,27 +111,50 @@ func resourceAwsDxGatewayAssociationProposalCreate(d *schema.ResourceData, meta } func resourceAwsDxGatewayAssociationProposalRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Read Direct Connect Gateway Association Proposal: %s", d.Id()) + + var proposal *directconnect.GatewayAssociationProposal + conn := meta.(*AWSClient).dxconn - proposal, err := describeDirectConnectGatewayAssociationProposal(conn, d.Id()) + trimmedId := strings.Join(strings.Fields(d.Id()), "") + if len(trimmedId) > 0 { + var err error + proposal, err = describeDirectConnectGatewayAssociationProposal(conn, d.Id()) - if err != nil { - return fmt.Errorf("error reading Direct Connect Gateway Association Proposal (%s): %s", d.Id(), err) + if err != nil { + return fmt.Errorf("error reading Direct Connect Gateway Association Proposal (%s): %s", d.Id(), err) + } + } else { + log.Printf("[WARN] Direct Connect Gateway Association Proposal Id not available (%s)", d.Id()) + d.SetId("0xda5e") // placeholder value } - if proposal == nil { - associatedGatewayId, ok := d.GetOk("associated_gateway_id") + if proposal == nil || len(trimmedId) < 1 { + log.Printf("[WARN] Direct Connect Gateway Association Proposal (%s) not found, checking for associated gateway", d.Id()) - if !ok || associatedGatewayId == nil { + var dxGatewayId string + if rawDGId, ok := d.GetOk("dx_gateway_id"); ok { + dxGatewayId = rawDGId.(string) + } else if rawDGId == nil { d.SetId("") - return fmt.Errorf("error reading Direct Connect Associated Gateway Id (%s): %s", d.Id(), err) + return fmt.Errorf("error reading dx_gateway_id (%s) from Proposal state", d.Id()) } - assocRaw, state, err := getDxGatewayAssociation(conn, associatedGatewayId.(string))() + var associatedGatewayId string + if rawAGId, ok := d.GetOk("associated_gateway_id"); ok { + associatedGatewayId = rawAGId.(string) + } else if rawAGId == nil { + d.SetId("") + return fmt.Errorf("error reading associated_gateway_id (%s) from Proposal state", d.Id()) + } + + log.Printf("[DEBUG] looking for Direct Connect Gateway Association using dx_gateway_id (%s) and associated_gateway_id (%s) to validate Proposal state data", dxGatewayId, associatedGatewayId) + assocRaw, state, err := getDxGatewayAssociation(conn, dxGatewayId, associatedGatewayId)() if err != nil { d.SetId("") - return fmt.Errorf("error reading Direct Connect gateway association (%s): %s", d.Id(), err) + return fmt.Errorf("error reading Direct Connect gateway association (%s) from Proposal state: %s", d.Id(), err) } if state == gatewayAssociationStateDeleted { @@ -149,7 +166,7 @@ func resourceAwsDxGatewayAssociationProposalRead(d *schema.ResourceData, meta in // once accepted, AWS will delete the proposal after after some time (days?) // in this case we don't need to create a new proposal, use metadata from the association // to artificially populate the missing proposal in state as if it was still there. - log.Printf("[INFO] Direct Connect Gateway Association Proposal (%s) has been accepted", d.Id()) + log.Printf("[INFO] Direct Connect Gateway Association Proposal (%s) has reached end-of-life and has been removed by AWS.", d.Id()) assoc := assocRaw.(*directconnect.GatewayAssociation) d.Set("associated_gateway_id", assoc.AssociatedGateway.Id) d.Set("dx_gateway_id", assoc.DirectConnectGatewayId) @@ -333,11 +350,14 @@ func dxGatewayAssociationProposalImport(d *schema.ResourceData, meta interface{} return []*schema.ResourceData{d}, nil } -func getDxGatewayAssociation(conn *directconnect.DirectConnect, associatedGatewayId string) resource.StateRefreshFunc { +func getDxGatewayAssociation(conn *directconnect.DirectConnect, dxGatewayId, associatedGatewayId string) resource.StateRefreshFunc { return func() (interface{}, string, error) { + resp, err := conn.DescribeDirectConnectGatewayAssociations(&directconnect.DescribeDirectConnectGatewayAssociationsInput{ - AssociatedGatewayId: aws.String(associatedGatewayId), + AssociatedGatewayId: &associatedGatewayId, + DirectConnectGatewayId: &dxGatewayId, }) + if err != nil { return nil, "", err } From 2710bca6c2c97790632aa87b8b3c6d989314b2dd Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Tue, 22 Jun 2021 15:31:35 -0700 Subject: [PATCH 0986/1208] remove test function no longer needed --- ...esource_aws_dx_gateway_association_proposal_test.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index cc66d2e9e461..ef7e36705e3d 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -366,16 +366,6 @@ func testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName string) re } } -func testAccDxGatewayAssociationProposalImportStateIdFunc(proposal *directconnect.GatewayAssociationProposal) resource.ImportStateIdFunc { - return func(s *terraform.State) (string, error) { - return strings.Join([]string{ - aws.StringValue(proposal.ProposalId), - aws.StringValue(proposal.DirectConnectGatewayId), - aws.StringValue(proposal.AssociatedGateway.Id), - }, "/"), nil - } -} - func testAccDxGatewayAssociationProposalConfigBase_vpnGateway(rName string, rBgpAsn int) string { return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` resource "aws_dx_gateway" "test" { From f7501bea86460ea0200d8760d4336ea8ab1bbbf8 Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Wed, 23 Jun 2021 11:04:01 -0700 Subject: [PATCH 0987/1208] include allowed_prefixes when atrificially populating proposal --- aws/resource_aws_dx_gateway_association_proposal.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index 588c5db09cc9..249ad9ff0bbe 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -31,6 +31,7 @@ func resourceAwsDxGatewayAssociationProposal() *schema.Resource { if len(strings.Join(strings.Fields(d.Id()), "")) < 1 { log.Printf("[WARN] Direct Connect Gateway Association Proposal Id not available (%s)", d.Id()) + log.Printf("[DEBUG] Direct Connect Gateway Association Proposal UpdatedKeys (%s)", strings.Join(d.UpdatedKeys(), "/")) // assume proposal is end-of-life, rely on Read func to test return false } @@ -127,7 +128,6 @@ func resourceAwsDxGatewayAssociationProposalRead(d *schema.ResourceData, meta in } } else { log.Printf("[WARN] Direct Connect Gateway Association Proposal Id not available (%s)", d.Id()) - d.SetId("0xda5e") // placeholder value } if proposal == nil || len(trimmedId) < 1 { @@ -158,7 +158,7 @@ func resourceAwsDxGatewayAssociationProposalRead(d *schema.ResourceData, meta in } if state == gatewayAssociationStateDeleted { - log.Printf("[WARN] Direct Connect gateway association (%s) not found, removing from state", d.Id()) + log.Printf("[WARN] Direct Connect gateway association (%s/%s/%s) not found, removing from state", d.Id(), dxGatewayId, associatedGatewayId) d.SetId("") return nil } @@ -168,10 +168,17 @@ func resourceAwsDxGatewayAssociationProposalRead(d *schema.ResourceData, meta in // to artificially populate the missing proposal in state as if it was still there. log.Printf("[INFO] Direct Connect Gateway Association Proposal (%s) has reached end-of-life and has been removed by AWS.", d.Id()) assoc := assocRaw.(*directconnect.GatewayAssociation) + + err = d.Set("allowed_prefixes", flattenDxRouteFilterPrefixes(assoc.AllowedPrefixesToDirectConnectGateway)) + if err != nil { + return fmt.Errorf("error setting allowed_prefixes: %s", err) + } + d.Set("associated_gateway_id", assoc.AssociatedGateway.Id) d.Set("dx_gateway_id", assoc.DirectConnectGatewayId) d.Set("dx_gateway_owner_account_id", assoc.DirectConnectGatewayOwnerAccount) } else { + log.Printf("[DEBUG] Direct Connect Gateway Association Proposal (%s) found, continuing as normal: %s", d.Id(), proposal.String()) if aws.StringValue(proposal.ProposalState) == directconnect.GatewayAssociationProposalStateDeleted { log.Printf("[WARN] Direct Connect Gateway Association Proposal (%s) deleted, removing from state", d.Id()) @@ -294,7 +301,7 @@ func dxGatewayAssociationProposalImport(d *schema.ResourceData, meta interface{} errStr := "unexpected format of import string (%q), expected PROPOSALID/DXGATEWAYID/TARGETGATEWAYID]*: %s" importStr := d.Id() - log.Printf("[DEBUG] Validating import string %s", importStr) + log.Printf("[DEBUG] Validating import string (%s) for Direct Connect Gateway Association Proposal", importStr) parts := strings.Split(strings.ToLower(importStr), "/") if len(parts) < 1 { From e8b8e03a18686dcfaac58fdafcd0053ce157f872 Mon Sep 17 00:00:00 2001 From: Dave Kujawski Date: Wed, 23 Jun 2021 11:04:19 -0700 Subject: [PATCH 0988/1208] include tgw for acc tests --- ...ws_dx_gateway_association_proposal_test.go | 60 ++++++++++++++++++- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index ef7e36705e3d..3ef3932720cd 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -186,7 +186,7 @@ func TestAccAwsDxGatewayAssociationProposal_disappears(t *testing.T) { }) } -func TestAccAwsDxGatewayAssociationProposal_endOfLife(t *testing.T) { +func TestAccAwsDxGatewayAssociationProposal_endOfLifeVpn(t *testing.T) { var proposal1 directconnect.GatewayAssociationProposal var providers []*schema.Provider rBgpAsn := acctest.RandIntRange(64512, 65534) @@ -203,7 +203,47 @@ func TestAccAwsDxGatewayAssociationProposal_endOfLife(t *testing.T) { CheckDestroy: testAccCheckAwsDxGatewayAssociationProposalDestroy, Steps: []resource.TestStep{ { - Config: testAccDxGatewayAssociationProposalConfig_endOfLife(rName, rBgpAsn), + Config: testAccDxGatewayAssociationProposalConfig_endOfLifeVpn(rName, rBgpAsn), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal1), + testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName), + testAccCheckAwsDxGatewayAssociationProposalDisappears(&proposal1), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + return strings.Join([]string{ + aws.StringValue(proposal1.ProposalId), + aws.StringValue(proposal1.DirectConnectGatewayId), + aws.StringValue(proposal1.AssociatedGateway.Id), + }, "/"), nil + }, + ImportState: true, + ImportStateVerify: false, // proposal attributes not applicable when it does not exist + }, + }, + }) +} + +func TestAccAwsDxGatewayAssociationProposal_endOfLifeTgw(t *testing.T) { + var proposal1 directconnect.GatewayAssociationProposal + var providers []*schema.Provider + rBgpAsn := acctest.RandIntRange(64512, 65534) + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_dx_gateway_association_proposal.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), + ProviderFactories: testAccProviderFactoriesAlternate(&providers), + CheckDestroy: testAccCheckAwsDxGatewayAssociationProposalDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDxGatewayAssociationProposalConfig_endOfLifeTgw(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal1), testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName), @@ -403,7 +443,7 @@ resource "aws_dx_gateway_association_proposal" "test" { ` } -func testAccDxGatewayAssociationProposalConfig_endOfLife(rName string, rBgpAsn int) string { +func testAccDxGatewayAssociationProposalConfig_endOfLifeVpn(rName string, rBgpAsn int) string { return testAccDxGatewayAssociationProposalConfig_basicVpnGateway(rName, rBgpAsn) + ` data "aws_caller_identity" "current" {} @@ -417,6 +457,20 @@ associated_gateway_owner_account_id = data.aws_caller_identity.current.account_i ` } +func testAccDxGatewayAssociationProposalConfig_endOfLifeTgw(rName string, rBgpAsn int) string { + return testAccDxGatewayAssociationProposalConfig_basicTransitGateway(rName, rBgpAsn) + ` +data "aws_caller_identity" "current" {} + +resource "aws_dx_gateway_association" "test" { +provider = "awsalternate" + +proposal_id = aws_dx_gateway_association_proposal.test.id +dx_gateway_id = aws_dx_gateway.test.id +associated_gateway_owner_account_id = data.aws_caller_identity.current.account_id +} +` +} + func testAccDxGatewayAssociationProposalConfig_basicTransitGateway(rName string, rBgpAsn int) string { return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` resource "aws_dx_gateway" "test" { From eab40d6986bfb68b3a94a74ce0d42672262b4e07 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 7 Jul 2021 17:54:08 +0000 Subject: [PATCH 0989/1208] Update CHANGELOG.md for #19986 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index daf1257a6f68..4eade413bc5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ FEATURES: +* **New Resource:** `aws_eks_identity_provider_config` ([#17959](https://github.com/hashicorp/terraform-provider-aws/issues/17959)) * **New Resource:** `aws_rds_cluster_role_association` ([#12370](https://github.com/hashicorp/terraform-provider-aws/issues/12370)) ENHANCEMENTS: @@ -9,6 +10,10 @@ ENHANCEMENTS: * aws_rds_cluster: Set `iam_roles` as Computed to prevent drift when the `aws_rds_cluster_role_association` resource is used ([#12370](https://github.com/hashicorp/terraform-provider-aws/issues/12370)) * resource/aws_transfer_server: Add `security_group_ids` argument to `endpoint_details` configuration block. ([#17539](https://github.com/hashicorp/terraform-provider-aws/issues/17539)) +BUG FIXES: + +* resource/aws_eks_cluster: Don't associate an `encryption_config` if there's already one ([#19986](https://github.com/hashicorp/terraform-provider-aws/issues/19986)) + ## 3.48.0 (July 02, 2021) FEATURES: From 10830b084b3822ff84d301bfe5ac3097c260b84c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 7 Jul 2021 14:11:26 -0400 Subject: [PATCH 0990/1208] Add DirectConnect internal finder and waiter packages. --- .../service/directconnect/finder/finder.go | 44 ++++++++++++ .../service/directconnect/waiter/status.go | 25 +++++++ .../service/directconnect/waiter/waiter.go | 68 +++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 aws/internal/service/directconnect/finder/finder.go create mode 100644 aws/internal/service/directconnect/waiter/status.go create mode 100644 aws/internal/service/directconnect/waiter/waiter.go diff --git a/aws/internal/service/directconnect/finder/finder.go b/aws/internal/service/directconnect/finder/finder.go new file mode 100644 index 000000000000..559ce5ef3ac5 --- /dev/null +++ b/aws/internal/service/directconnect/finder/finder.go @@ -0,0 +1,44 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/directconnect" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func GatewayAssociationByID(conn *directconnect.DirectConnect, id string) (*directconnect.GatewayAssociation, error) { + input := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ + AssociationId: aws.String(id), + } + + output, err := conn.DescribeDirectConnectGatewayAssociations(input) + + if err != nil { + return nil, err + } + + if output == nil || len(output.DirectConnectGatewayAssociations) == 0 || output.DirectConnectGatewayAssociations[0] == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + gatewayAssociation := output.DirectConnectGatewayAssociations[0] + + if state := aws.StringValue(gatewayAssociation.AssociationState); state == directconnect.GatewayAssociationStateDisassociated { + return nil, &resource.NotFoundError{ + Message: state, + LastRequest: input, + } + } + + // Eventual consistency check. + if aws.StringValue(gatewayAssociation.AssociationId) != id { + return nil, &resource.NotFoundError{ + LastRequest: input, + } + } + + return gatewayAssociation, nil +} diff --git a/aws/internal/service/directconnect/waiter/status.go b/aws/internal/service/directconnect/waiter/status.go new file mode 100644 index 000000000000..98e90d4097b4 --- /dev/null +++ b/aws/internal/service/directconnect/waiter/status.go @@ -0,0 +1,25 @@ +package waiter + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/directconnect" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func GatewayAssociationState(conn *directconnect.DirectConnect, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.GatewayAssociationByID(conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.AssociationState), nil + } +} diff --git a/aws/internal/service/directconnect/waiter/waiter.go b/aws/internal/service/directconnect/waiter/waiter.go new file mode 100644 index 000000000000..ab54c49cb62a --- /dev/null +++ b/aws/internal/service/directconnect/waiter/waiter.go @@ -0,0 +1,68 @@ +package waiter + +import ( + "errors" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/directconnect" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func GatewayAssociationCreated(conn *directconnect.DirectConnect, id string, timeout time.Duration) (*directconnect.GatewayAssociation, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{directconnect.GatewayAssociationStateAssociating}, + Target: []string{directconnect.GatewayAssociationStateAssociated}, + Refresh: GatewayAssociationState(conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*directconnect.GatewayAssociation); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StateChangeError))) + + return output, err + } + + return nil, err +} + +func GatewayAssociationUpdated(conn *directconnect.DirectConnect, id string, timeout time.Duration) (*directconnect.GatewayAssociation, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{directconnect.GatewayAssociationStateUpdating}, + Target: []string{directconnect.GatewayAssociationStateAssociated}, + Refresh: GatewayAssociationState(conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*directconnect.GatewayAssociation); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StateChangeError))) + + return output, err + } + + return nil, err +} + +func GatewayAssociationDeleted(conn *directconnect.DirectConnect, id string, timeout time.Duration) (*directconnect.GatewayAssociation, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{directconnect.GatewayAssociationStateDisassociating}, + Target: []string{}, + Refresh: GatewayAssociationState(conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*directconnect.GatewayAssociation); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StateChangeError))) + + return output, err + } + + return nil, err +} From c28188296fde0f2e8cf0c5985822296573899985 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 7 Jul 2021 14:49:07 -0400 Subject: [PATCH 0991/1208] Use finder package in aws_dx_gateway_association & aws_dx_gateway_association_proposal acceptance tests. --- .../service/directconnect/finder/finder.go | 48 +++++++++++++++++-- ...ws_dx_gateway_association_proposal_test.go | 26 +++++----- ...esource_aws_dx_gateway_association_test.go | 37 +++++++------- 3 files changed, 79 insertions(+), 32 deletions(-) diff --git a/aws/internal/service/directconnect/finder/finder.go b/aws/internal/service/directconnect/finder/finder.go index 559ce5ef3ac5..f8af3c5a4bd5 100644 --- a/aws/internal/service/directconnect/finder/finder.go +++ b/aws/internal/service/directconnect/finder/finder.go @@ -11,6 +11,19 @@ func GatewayAssociationByID(conn *directconnect.DirectConnect, id string) (*dire AssociationId: aws.String(id), } + return GatewayAssociation(conn, input) +} + +func GatewayAssociationByAssociatedGatewayIDAndDirectConnectGatewayID(conn *directconnect.DirectConnect, associatedGatewayID, directConnectGatewayID string) (*directconnect.GatewayAssociation, error) { + input := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ + AssociatedGatewayId: aws.String(associatedGatewayID), + DirectConnectGatewayId: aws.String(directConnectGatewayID), + } + + return GatewayAssociation(conn, input) +} + +func GatewayAssociation(conn *directconnect.DirectConnect, input *directconnect.DescribeDirectConnectGatewayAssociationsInput) (*directconnect.GatewayAssociation, error) { output, err := conn.DescribeDirectConnectGatewayAssociations(input) if err != nil { @@ -24,6 +37,9 @@ func GatewayAssociationByID(conn *directconnect.DirectConnect, id string) (*dire } } + // TODO Check for multiple results. + // TODO https://github.com/hashicorp/terraform-provider-aws/pull/17613. + gatewayAssociation := output.DirectConnectGatewayAssociations[0] if state := aws.StringValue(gatewayAssociation.AssociationState); state == directconnect.GatewayAssociationStateDisassociated { @@ -33,12 +49,38 @@ func GatewayAssociationByID(conn *directconnect.DirectConnect, id string) (*dire } } - // Eventual consistency check. - if aws.StringValue(gatewayAssociation.AssociationId) != id { + return gatewayAssociation, nil +} + +func GatewayAssociationProposalByID(conn *directconnect.DirectConnect, id string) (*directconnect.GatewayAssociationProposal, error) { + input := &directconnect.DescribeDirectConnectGatewayAssociationProposalsInput{ + ProposalId: aws.String(id), + } + + output, err := conn.DescribeDirectConnectGatewayAssociationProposals(input) + + if err != nil { + return nil, err + } + + if output == nil || len(output.DirectConnectGatewayAssociationProposals) == 0 || output.DirectConnectGatewayAssociationProposals[0] == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + // TODO Check for multiple results. + // TODO https://github.com/hashicorp/terraform-provider-aws/pull/17613. + + proposal := output.DirectConnectGatewayAssociationProposals[0] + + if state := aws.StringValue(proposal.ProposalState); state == directconnect.GatewayAssociationProposalStateDeleted { return nil, &resource.NotFoundError{ + Message: state, LastRequest: input, } } - return gatewayAssociation, nil + return proposal, nil } diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index 3ef3932720cd..2368ef63528e 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -12,6 +12,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -315,17 +317,17 @@ func testAccCheckAwsDxGatewayAssociationProposalDestroy(s *terraform.State) erro continue } - proposal, err := describeDirectConnectGatewayAssociationProposal(conn, rs.Primary.ID) + _, err := finder.GatewayAssociationProposalByID(conn, rs.Primary.ID) - if err != nil { - return err + if tfresource.NotFound(err) { + continue } - if proposal == nil { - continue + if err != nil { + return err } - return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) still exists", rs.Primary.ID) + return fmt.Errorf("Direct Connect Gateway Association Proposal %s still exists", rs.Primary.ID) } return nil @@ -338,19 +340,19 @@ func testAccCheckAwsDxGatewayAssociationProposalExists(resourceName string, gate return fmt.Errorf("Not found: %s", resourceName) } + if rs.Primary.ID == "" { + return fmt.Errorf("No Direct Connect Gateway Association Proposal ID is set") + } + conn := testAccProvider.Meta().(*AWSClient).dxconn - proposal, err := describeDirectConnectGatewayAssociationProposal(conn, rs.Primary.ID) + output, err := finder.GatewayAssociationProposalByID(conn, rs.Primary.ID) if err != nil { return err } - if proposal == nil { - return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not found", rs.Primary.ID) - } - - *gatewayAssociationProposal = *proposal + *gatewayAssociationProposal = *output return nil } diff --git a/aws/resource_aws_dx_gateway_association_test.go b/aws/resource_aws_dx_gateway_association_test.go index 0a4355f702a2..22be438e4109 100644 --- a/aws/resource_aws_dx_gateway_association_test.go +++ b/aws/resource_aws_dx_gateway_association_test.go @@ -14,6 +14,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -543,18 +545,17 @@ func testAccCheckAwsDxGatewayAssociationDestroy(s *terraform.State) error { continue } - resp, err := conn.DescribeDirectConnectGatewayAssociations(&directconnect.DescribeDirectConnectGatewayAssociationsInput{ - AssociationId: aws.String(rs.Primary.Attributes["dx_gateway_association_id"]), - }) + _, err := finder.GatewayAssociationByID(conn, rs.Primary.Attributes["dx_gateway_association_id"]) + + if tfresource.NotFound(err) { + continue + } + if err != nil { return err } - if len(resp.DirectConnectGatewayAssociations) > 0 { - return fmt.Errorf("Direct Connect Gateway (%s) is not dissociated from GW %s", - aws.StringValue(resp.DirectConnectGatewayAssociations[0].DirectConnectGatewayId), - aws.StringValue(resp.DirectConnectGatewayAssociations[0].AssociatedGateway.Id)) - } + return fmt.Errorf("Direct Connect Gateway Association %s still exists", rs.Primary.ID) } return nil } @@ -565,29 +566,31 @@ func testAccCheckAwsDxGatewayAssociationExists(name string, ga *directconnect.Ga if !ok { return fmt.Errorf("Not found: %s", name) } - if rs.Primary.ID == "" { - return fmt.Errorf("No ID is set") + + if rs.Primary.Attributes["dx_gateway_association_id"] == "" { + return fmt.Errorf("No Direct Connect Gateway Association ID is set") } conn := testAccProvider.Meta().(*AWSClient).dxconn - resp, err := conn.DescribeDirectConnectGatewayAssociations(&directconnect.DescribeDirectConnectGatewayAssociationsInput{ - AssociationId: aws.String(rs.Primary.Attributes["dx_gateway_association_id"]), - }) + + output, err := finder.GatewayAssociationByID(conn, rs.Primary.Attributes["dx_gateway_association_id"]) + if err != nil { return err } - *ga = *resp.DirectConnectGatewayAssociations[0] + if proposalID := rs.Primary.Attributes["proposal_id"]; proposalID != "" { + output, err := finder.GatewayAssociationProposalByID(conn, proposalID) - if proposalId := rs.Primary.Attributes["proposal_id"]; proposalId != "" && gap != nil { - v, err := describeDirectConnectGatewayAssociationProposal(conn, proposalId) if err != nil { return err } - *gap = *v + *gap = *output } + *ga = *output + return nil } } From 9a5b53ce89fc6fd9a107ba1d1a65646a08fe1f13 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 7 Jul 2021 15:31:11 -0400 Subject: [PATCH 0992/1208] Add DirectConnect internal lister package and use in (some) test sweepers. --- aws/internal/service/directconnect/id.go | 9 ++ .../service/directconnect/lister/list.go | 3 + .../directconnect/lister/list_pages_gen.go | 73 +++++++++ ...ws_dx_gateway_association_proposal_test.go | 67 ++++---- ...esource_aws_dx_gateway_association_test.go | 144 ++++++++---------- 5 files changed, 181 insertions(+), 115 deletions(-) create mode 100644 aws/internal/service/directconnect/id.go create mode 100644 aws/internal/service/directconnect/lister/list.go create mode 100644 aws/internal/service/directconnect/lister/list_pages_gen.go diff --git a/aws/internal/service/directconnect/id.go b/aws/internal/service/directconnect/id.go new file mode 100644 index 000000000000..d1cfd0dd0618 --- /dev/null +++ b/aws/internal/service/directconnect/id.go @@ -0,0 +1,9 @@ +package directconnect + +import ( + "fmt" +) + +func GatewayAssociationCreateResourceID(directConnectGatewayID, associatedGatewayID string) string { + return fmt.Sprintf("ga-%s%s", directConnectGatewayID, associatedGatewayID) +} diff --git a/aws/internal/service/directconnect/lister/list.go b/aws/internal/service/directconnect/lister/list.go new file mode 100644 index 000000000000..5fa5e04b3413 --- /dev/null +++ b/aws/internal/service/directconnect/lister/list.go @@ -0,0 +1,3 @@ +//go:generate go run ../../../generators/listpages/main.go -function=DescribeDirectConnectGateways,DescribeDirectConnectGatewayAssociations,DescribeDirectConnectGatewayAssociationProposals -paginator=NextToken github.com/aws/aws-sdk-go/service/directconnect + +package lister diff --git a/aws/internal/service/directconnect/lister/list_pages_gen.go b/aws/internal/service/directconnect/lister/list_pages_gen.go new file mode 100644 index 000000000000..e28a109e6c22 --- /dev/null +++ b/aws/internal/service/directconnect/lister/list_pages_gen.go @@ -0,0 +1,73 @@ +// Code generated by "aws/internal/generators/listpages/main.go -function=DescribeDirectConnectGateways,DescribeDirectConnectGatewayAssociations,DescribeDirectConnectGatewayAssociationProposals -paginator=NextToken github.com/aws/aws-sdk-go/service/directconnect"; DO NOT EDIT. + +package lister + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/directconnect" +) + +func DescribeDirectConnectGatewayAssociationProposalsPages(conn *directconnect.DirectConnect, input *directconnect.DescribeDirectConnectGatewayAssociationProposalsInput, fn func(*directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput, bool) bool) error { + return DescribeDirectConnectGatewayAssociationProposalsPagesWithContext(context.Background(), conn, input, fn) +} + +func DescribeDirectConnectGatewayAssociationProposalsPagesWithContext(ctx context.Context, conn *directconnect.DirectConnect, input *directconnect.DescribeDirectConnectGatewayAssociationProposalsInput, fn func(*directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput, bool) bool) error { + for { + output, err := conn.DescribeDirectConnectGatewayAssociationProposalsWithContext(ctx, input) + if err != nil { + return err + } + + lastPage := aws.StringValue(output.NextToken) == "" + if !fn(output, lastPage) || lastPage { + break + } + + input.NextToken = output.NextToken + } + return nil +} + +func DescribeDirectConnectGatewayAssociationsPages(conn *directconnect.DirectConnect, input *directconnect.DescribeDirectConnectGatewayAssociationsInput, fn func(*directconnect.DescribeDirectConnectGatewayAssociationsOutput, bool) bool) error { + return DescribeDirectConnectGatewayAssociationsPagesWithContext(context.Background(), conn, input, fn) +} + +func DescribeDirectConnectGatewayAssociationsPagesWithContext(ctx context.Context, conn *directconnect.DirectConnect, input *directconnect.DescribeDirectConnectGatewayAssociationsInput, fn func(*directconnect.DescribeDirectConnectGatewayAssociationsOutput, bool) bool) error { + for { + output, err := conn.DescribeDirectConnectGatewayAssociationsWithContext(ctx, input) + if err != nil { + return err + } + + lastPage := aws.StringValue(output.NextToken) == "" + if !fn(output, lastPage) || lastPage { + break + } + + input.NextToken = output.NextToken + } + return nil +} + +func DescribeDirectConnectGatewaysPages(conn *directconnect.DirectConnect, input *directconnect.DescribeDirectConnectGatewaysInput, fn func(*directconnect.DescribeDirectConnectGatewaysOutput, bool) bool) error { + return DescribeDirectConnectGatewaysPagesWithContext(context.Background(), conn, input, fn) +} + +func DescribeDirectConnectGatewaysPagesWithContext(ctx context.Context, conn *directconnect.DirectConnect, input *directconnect.DescribeDirectConnectGatewaysInput, fn func(*directconnect.DescribeDirectConnectGatewaysOutput, bool) bool) error { + for { + output, err := conn.DescribeDirectConnectGatewaysWithContext(ctx, input) + if err != nil { + return err + } + + lastPage := aws.StringValue(output.NextToken) == "" + if !fn(output, lastPage) || lastPage { + break + } + + input.NextToken = output.NextToken + } + return nil +} diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index 2368ef63528e..2f30084a2c01 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -8,11 +8,13 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directconnect" + multierror "github.com/hashicorp/go-multierror" "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/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/lister" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -25,59 +27,58 @@ func init() { func testSweepDirectConnectGatewayAssociationProposals(region string) error { client, err := sharedClientForRegion(region) - if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } - conn := client.(*AWSClient).dxconn input := &directconnect.DescribeDirectConnectGatewayAssociationProposalsInput{} + var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) - for { - output, err := conn.DescribeDirectConnectGatewayAssociationProposals(input) - - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping Direct Connect Gateway sweep for %s: %s", region, err) - return nil - } - - if err != nil { - return fmt.Errorf("error retrieving Direct Connect Gateway Association Proposals: %s", err) + lister.DescribeDirectConnectGatewayAssociationProposalsPages(conn, input, func(page *directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - for _, gatewayAssociationProposal := range output.DirectConnectGatewayAssociationProposals { - proposalID := aws.StringValue(gatewayAssociationProposal.ProposalId) + for _, proposal := range page.DirectConnectGatewayAssociationProposals { + proposalID := aws.StringValue(proposal.ProposalId) - if aws.StringValue(gatewayAssociationProposal.AssociatedGateway.Region) != region { - log.Printf("[INFO] Skipping Direct Connect Gateway Association Proposal (%s) in different home region: %s", proposalID, aws.StringValue(gatewayAssociationProposal.AssociatedGateway.Region)) + if proposalRegion := aws.StringValue(proposal.AssociatedGateway.Region); proposalRegion != region { + log.Printf("[INFO] Skipping Direct Connect Gateway Association Proposal (%s) in different home region: %s", proposalID, proposalRegion) continue } - if aws.StringValue(gatewayAssociationProposal.ProposalState) != directconnect.GatewayAssociationProposalStateAccepted { - log.Printf("[INFO] Skipping Direct Connect Gateway Association Proposal (%s) in non-accepted (%s) state", proposalID, aws.StringValue(gatewayAssociationProposal.ProposalState)) + if state := aws.StringValue(proposal.ProposalState); state != directconnect.GatewayAssociationProposalStateAccepted { + log.Printf("[INFO] Skipping Direct Connect Gateway Association Proposal (%s) in non-accepted (%s) state", proposalID, state) continue } - input := &directconnect.DeleteDirectConnectGatewayAssociationProposalInput{ - ProposalId: gatewayAssociationProposal.ProposalId, - } - - log.Printf("[INFO] Deleting Direct Connect Gateway Association Proposal: %s", proposalID) - _, err := conn.DeleteDirectConnectGatewayAssociationProposal(input) + r := resourceAwsDxGatewayAssociationProposal() + d := r.Data(nil) + d.SetId(proposalID) - if err != nil { - return fmt.Errorf("error deleting Direct Connect Gateway Association Proposal (%s): %s", proposalID, err) - } + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - if aws.StringValue(output.NextToken) == "" { - break - } + return !lastPage + }) - input.NextToken = output.NextToken + if testSweepSkipSweepError(err) { + log.Print(fmt.Errorf("[WARN] Skipping Direct Connect Gateway Association Proposal sweep for %s: %w", region, err)) + return sweeperErrs // In case we have completed some pages, but had errors } - return nil + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Direct Connect Gateway Association Proposals (%s): %w", region, err)) + } + + err = testSweepResourceOrchestrator(sweepResources) + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping Direct Connect Gateway Association Proposals (%s): %w", region, err)) + } + + return sweeperErrs.ErrorOrNil() } func TestAccAwsDxGatewayAssociationProposal_basicVpnGateway(t *testing.T) { diff --git a/aws/resource_aws_dx_gateway_association_test.go b/aws/resource_aws_dx_gateway_association_test.go index 22be438e4109..d85ed68d5bab 100644 --- a/aws/resource_aws_dx_gateway_association_test.go +++ b/aws/resource_aws_dx_gateway_association_test.go @@ -5,16 +5,18 @@ import ( "fmt" "log" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directconnect" "github.com/aws/aws-sdk-go/service/ec2" + multierror "github.com/hashicorp/go-multierror" "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/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + tfdirectconnect "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/lister" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -31,38 +33,31 @@ func init() { func testSweepDirectConnectGatewayAssociations(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } conn := client.(*AWSClient).dxconn - gatewayInput := &directconnect.DescribeDirectConnectGatewaysInput{} + input := &directconnect.DescribeDirectConnectGatewaysInput{} + var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) - for { - gatewayOutput, err := conn.DescribeDirectConnectGateways(gatewayInput) - - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping Direct Connect Gateway sweep for %s: %s", region, err) - return nil - } - - if err != nil { - return fmt.Errorf("error retrieving Direct Connect Gateways: %s", err) + lister.DescribeDirectConnectGatewaysPages(conn, input, func(page *directconnect.DescribeDirectConnectGatewaysOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - for _, gateway := range gatewayOutput.DirectConnectGateways { + for _, gateway := range page.DirectConnectGateways { directConnectGatewayID := aws.StringValue(gateway.DirectConnectGatewayId) - associationInput := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ - DirectConnectGatewayId: gateway.DirectConnectGatewayId, + input := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ + DirectConnectGatewayId: aws.String(directConnectGatewayID), } - for { - associationOutput, err := conn.DescribeDirectConnectGatewayAssociations(associationInput) - - if err != nil { - return fmt.Errorf("error retrieving Direct Connect Gateway (%s) Associations: %s", directConnectGatewayID, err) + err := lister.DescribeDirectConnectGatewayAssociationsPages(conn, input, func(page *directconnect.DescribeDirectConnectGatewayAssociationsOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - for _, association := range associationOutput.DirectConnectGatewayAssociations { + for _, association := range page.DirectConnectGatewayAssociations { gatewayID := aws.StringValue(association.AssociatedGateway.Id) if aws.StringValue(association.AssociatedGateway.Region) != region { @@ -70,44 +65,36 @@ func testSweepDirectConnectGatewayAssociations(region string) error { continue } - if aws.StringValue(association.AssociationState) != directconnect.GatewayAssociationStateAssociated { - log.Printf("[INFO] Skipping Direct Connect Gateway (%s) Association in non-available (%s) state: %s", directConnectGatewayID, aws.StringValue(association.AssociationState), gatewayID) + if state := aws.StringValue(association.AssociationState); state != directconnect.GatewayAssociationStateAssociated { + log.Printf("[INFO] Skipping Direct Connect Gateway (%s) Association in non-available (%s) state: %s", directConnectGatewayID, state, gatewayID) continue } - input := &directconnect.DeleteDirectConnectGatewayAssociationInput{ - AssociationId: association.AssociationId, - } - - log.Printf("[INFO] Deleting Direct Connect Gateway (%s) Association: %s", directConnectGatewayID, gatewayID) - _, err := conn.DeleteDirectConnectGatewayAssociation(input) + r := resourceAwsDxGatewayAssociation() + d := r.Data(nil) + d.SetId(tfdirectconnect.GatewayAssociationCreateResourceID(directConnectGatewayID, gatewayID)) - if isAWSErr(err, directconnect.ErrCodeClientException, "No association exists") { - continue - } - - if err != nil { - return fmt.Errorf("error deleting Direct Connect Gateway (%s) Association (%s): %s", directConnectGatewayID, gatewayID, err) - } - - if err := waitForDirectConnectGatewayAssociationDeletion(conn, aws.StringValue(association.AssociationId), 20*time.Minute); err != nil { - return fmt.Errorf("error waiting for Direct Connect Gateway (%s) Association (%s) to be deleted: %s", directConnectGatewayID, gatewayID, err) - } + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - if aws.StringValue(associationOutput.NextToken) == "" { - break - } + return !lastPage + }) - associationInput.NextToken = associationOutput.NextToken + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Direct Connect Gateway Associations (%s): %w", region, err)) } } - if aws.StringValue(gatewayOutput.NextToken) == "" { - break - } + return !lastPage + }) - gatewayInput.NextToken = gatewayOutput.NextToken + if testSweepSkipSweepError(err) { + log.Print(fmt.Errorf("[WARN] Skipping Direct Connect Gateway Association sweep for %s: %w", region, err)) + return sweeperErrs // In case we have completed some pages, but had errors + } + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Direct Connect Gateways (%s): %w", region, err)) } // Handle cross-account EC2 Transit Gateway associations. @@ -127,61 +114,54 @@ func testSweepDirectConnectGatewayAssociations(region string) error { continue } - associationInput := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ - AssociatedGatewayId: transitGateway.TransitGatewayId, - } transitGatewayID := aws.StringValue(transitGateway.TransitGatewayId) - associationOutput, err := conn.DescribeDirectConnectGatewayAssociations(associationInput) - - if err != nil { - log.Printf("[ERROR] error retrieving EC2 Transit Gateway (%s) Direct Connect Gateway Associations: %s", transitGatewayID, err) - continue + input := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ + AssociatedGatewayId: aws.String(transitGatewayID), } - for _, association := range associationOutput.DirectConnectGatewayAssociations { - associationID := aws.StringValue(association.AssociationId) - - if aws.StringValue(association.AssociationState) != directconnect.GatewayAssociationStateAssociated { - log.Printf("[INFO] Skipping EC2 Transit Gateway (%s) Direct Connect Gateway Association (%s) in non-available state: %s", transitGatewayID, associationID, aws.StringValue(association.AssociationState)) - continue + err := lister.DescribeDirectConnectGatewayAssociationsPages(conn, input, func(page *directconnect.DescribeDirectConnectGatewayAssociationsOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - input := &directconnect.DeleteDirectConnectGatewayAssociationInput{ - AssociationId: association.AssociationId, - } + for _, association := range page.DirectConnectGatewayAssociations { + directConnectGatewayID := aws.StringValue(association.DirectConnectGatewayId) + + if state := aws.StringValue(association.AssociationState); state != directconnect.GatewayAssociationStateAssociated { + log.Printf("[INFO] Skipping Direct Connect Gateway (%s) Association in non-available (%s) state: %s", directConnectGatewayID, state, transitGatewayID) + continue + } - log.Printf("[INFO] Deleting EC2 Transit Gateway (%s) Direct Connect Gateway Association: %s", transitGatewayID, associationID) - _, err := conn.DeleteDirectConnectGatewayAssociation(input) + r := resourceAwsDxGatewayAssociation() + d := r.Data(nil) + d.SetId(tfdirectconnect.GatewayAssociationCreateResourceID(directConnectGatewayID, transitGatewayID)) - if isAWSErr(err, directconnect.ErrCodeClientException, "No association exists") { - continue + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - if err != nil { - log.Printf("[ERROR] error deleting EC2 Transit Gateway (%s) Direct Connect Gateway Association (%s): %s", transitGatewayID, associationID, err) - continue - } + return !lastPage + }) - if err := waitForDirectConnectGatewayAssociationDeletion(conn, associationID, 30*time.Minute); err != nil { - log.Printf("[ERROR] error waiting for EC2 Transit Gateway (%s) Direct Connect Gateway Association (%s) to be deleted: %s", transitGatewayID, associationID, err) - } + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Direct Connect Gateway Associations (%s): %w", region, err)) } } return !lastPage }) - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping EC2 Transit Gateway Direct Connect Gateway Association sweep for %s: %s", region, err) - return nil + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing EC2 Transit Gateways (%s): %w", region, err)) } + err = testSweepResourceOrchestrator(sweepResources) + if err != nil { - return fmt.Errorf("error retrieving EC2 Transit Gateways: %s", err) + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping Direct Connect Gateway Associations (%s): %w", region, err)) } - return nil + return sweeperErrs.ErrorOrNil() } // V0 state upgrade testing must be done via acceptance testing due to API call From 5d7606d0149d13d45156a7c574b88332e822f6fb Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 7 Jul 2021 16:53:43 -0400 Subject: [PATCH 0993/1208] r/aws_dx_gateway_association_proposal: Document alternate resource import format. --- .../service/directconnect/finder/finder.go | 2 +- ...rce_aws_dx_gateway_association_proposal.go | 87 +++++++++---------- ...gateway_association_proposal.html.markdown | 11 ++- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/aws/internal/service/directconnect/finder/finder.go b/aws/internal/service/directconnect/finder/finder.go index f8af3c5a4bd5..9bcf768f73e2 100644 --- a/aws/internal/service/directconnect/finder/finder.go +++ b/aws/internal/service/directconnect/finder/finder.go @@ -14,7 +14,7 @@ func GatewayAssociationByID(conn *directconnect.DirectConnect, id string) (*dire return GatewayAssociation(conn, input) } -func GatewayAssociationByAssociatedGatewayIDAndDirectConnectGatewayID(conn *directconnect.DirectConnect, associatedGatewayID, directConnectGatewayID string) (*directconnect.GatewayAssociation, error) { +func GatewayAssociationByDirectConnectGatewayIDAndAssociatedGatewayID(conn *directconnect.DirectConnect, directConnectGatewayID, associatedGatewayID string) (*directconnect.GatewayAssociation, error) { input := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ AssociatedGatewayId: aws.String(associatedGatewayID), DirectConnectGatewayId: aws.String(directConnectGatewayID), diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index 249ad9ff0bbe..6218cde43ea0 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -11,6 +11,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsDxGatewayAssociationProposal() *schema.Resource { @@ -18,8 +20,9 @@ func resourceAwsDxGatewayAssociationProposal() *schema.Resource { Create: resourceAwsDxGatewayAssociationProposalCreate, Read: resourceAwsDxGatewayAssociationProposalRead, Delete: resourceAwsDxGatewayAssociationProposalDelete, + Importer: &schema.ResourceImporter{ - State: dxGatewayAssociationProposalImport, + State: resourceAwsDxGatewayAssociationProposalImport, }, CustomizeDiff: customdiff.Sequence( @@ -296,64 +299,56 @@ func flattenDirectConnectGatewayAssociationProposalAllowedPrefixes(routeFilterPr return allowedPrefixes } -func dxGatewayAssociationProposalImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - // example: c2ede9b4-bbc6-4d33-923c-bc4feEXAMPLE/186c8187-36f4-472e-9268-107aaEXAMPLE/0d95359280EXAMPLE +func resourceAwsDxGatewayAssociationProposalImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(strings.ToLower(d.Id()), "/") - errStr := "unexpected format of import string (%q), expected PROPOSALID/DXGATEWAYID/TARGETGATEWAYID]*: %s" - importStr := d.Id() - log.Printf("[DEBUG] Validating import string (%s) for Direct Connect Gateway Association Proposal", importStr) + var proposalID, directConnectGatewayID, associatedGatewayID string + switch n := len(parts); n { + case 1: + return []*schema.ResourceData{d}, nil - parts := strings.Split(strings.ToLower(importStr), "/") - if len(parts) < 1 { - return nil, fmt.Errorf(errStr, importStr, "too few parts") - } - var propId, dxgwId, gwId string - propId = parts[0] + case 3: + proposalID = parts[0] + directConnectGatewayID = parts[1] + associatedGatewayID = parts[2] - conn := meta.(*AWSClient).dxconn - if propId != "" { - p, err := describeDirectConnectGatewayAssociationProposal(conn, propId) - if err != nil { - return nil, err + if directConnectGatewayID == "" || associatedGatewayID == "" { + return nil, fmt.Errorf("Incorrect resource ID format: %q. DXGATEWAYID and TARGETGATEWAYID must not be empty strings", d.Id()) } - if p != nil { - // proposal still exists normal import - return schema.ImportStatePassthrough(d, meta) - } - // proposal may not exist, but that's fine - } - d.SetId(propId) - if len(parts) == 1 { - // requesting just the prop id - return schema.ImportStatePassthrough(d, meta) - } else if len(parts) < 3 { - return nil, fmt.Errorf(errStr, importStr, "too few parts") + break + + default: + return nil, fmt.Errorf("Incorrect resource ID format: %q. Expected PROPOSALID or PROPOSALID/DXGATEWAYID/TARGETGATEWAYID", d.Id()) } - dxgwId = parts[1] - gwId = parts[2] + conn := meta.(*AWSClient).dxconn - if gwId != "" && dxgwId != "" { - input := directconnect.DescribeDirectConnectGatewayAssociationsInput{ - AssociatedGatewayId: aws.String(gwId), - DirectConnectGatewayId: aws.String(dxgwId), - } - resp, err := conn.DescribeDirectConnectGatewayAssociations(&input) - if err != nil { + if proposalID != "" { + _, err := finder.GatewayAssociationProposalByID(conn, proposalID) + + if tfresource.NotFound(err) { + // Proposal not found. + } else if err != nil { return nil, err - } + } else { + // Proposal still exists. + d.SetId(proposalID) - id := dxGatewayAssociationId(dxgwId, gwId) - if n := len(resp.DirectConnectGatewayAssociations); n != 1 { - return nil, fmt.Errorf("Found %d Direct Connect gateway associations for %s, expected 1", n, id) + return []*schema.ResourceData{d}, nil } - d.Set("associated_gateway_id", gwId) - d.Set("dx_gateway_id", dxgwId) - } else { - return nil, fmt.Errorf(errStr, importStr, "missing parts") } + _, err := finder.GatewayAssociationByDirectConnectGatewayIDAndAssociatedGatewayID(conn, directConnectGatewayID, associatedGatewayID) + + if err != nil { + return nil, err + } + + d.SetId(proposalID) + d.Set("associated_gateway_id", associatedGatewayID) + d.Set("dx_gateway_id", directConnectGatewayID) + return []*schema.ResourceData{d}, nil } diff --git a/website/docs/r/dx_gateway_association_proposal.html.markdown b/website/docs/r/dx_gateway_association_proposal.html.markdown index a64c7e4608f6..5701772d2b41 100644 --- a/website/docs/r/dx_gateway_association_proposal.html.markdown +++ b/website/docs/r/dx_gateway_association_proposal.html.markdown @@ -41,8 +41,17 @@ In addition to all arguments above, the following attributes are exported: ## Import -Direct Connect Gateway Association Proposals can be imported using the proposal ID, e.g. +Direct Connect Gateway Association Proposals can be imported using either a proposal ID or proposal ID, Direct Connect Gateway ID and associated gateway ID separated by `/`, e.g. ``` $ terraform import aws_dx_gateway_association_proposal.example ac90e981-b718-4364-872d-65478c84fafe ``` + +or + +``` +$ terraform import aws_dx_gateway_association_proposal.example ac90e981-b718-4364-872d-65478c84fafe/abcd1234-dcba-5678-be23-cdef9876ab45/vgw-12345678 +``` + +The latter case is useful when a previous proposal has been accepted and deleted by AWS. +The `aws_dx_gateway_association_proposal` resource will then represent a pseudo-proposal for the same Direct Connect Gateway and associated gateway. From a86577a1a686a023e6c958295aa00eeabbf22d10 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 7 Jul 2021 17:09:32 -0700 Subject: [PATCH 0994/1208] Allows specifying replica count for secondary members of a global cluster --- ...asticache_global_replication_group_test.go | 97 ++++-- ...ource_aws_elasticache_replication_group.go | 35 ++- ..._aws_elasticache_replication_group_test.go | 295 ++++++++++++++---- ...lasticache_replication_group.html.markdown | 6 +- 4 files changed, 325 insertions(+), 108 deletions(-) diff --git a/aws/resource_aws_elasticache_global_replication_group_test.go b/aws/resource_aws_elasticache_global_replication_group_test.go index 12836f6667c3..a3f630399f57 100644 --- a/aws/resource_aws_elasticache_global_replication_group_test.go +++ b/aws/resource_aws_elasticache_global_replication_group_test.go @@ -281,6 +281,38 @@ func TestAccAWSElasticacheGlobalReplicationGroup_ReplaceSecondary_DifferentRegio }) } +func TestAccAWSElasticacheGlobalReplicationGroup_ClusterMode(t *testing.T) { + var globalReplicationGroup elasticache.GlobalReplicationGroup + var primaryReplicationGroup elasticache.ReplicationGroup + + rName := acctest.RandomWithPrefix("tf-acc-test") + + resourceName := "aws_elasticache_global_replication_group.test" + primaryReplicationGroupResourceName := "aws_elasticache_replication_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSElasticacheGlobalReplicationGroup(t) }, + ErrorCheck: testAccErrorCheck(t, elasticache.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSElasticacheGlobalReplicationGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSElasticacheGlobalReplicationGroupConfig_ClusterMode(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSElasticacheGlobalReplicationGroupExists(resourceName, &globalReplicationGroup), + testAccCheckAWSElasticacheReplicationGroupExists(primaryReplicationGroupResourceName, &primaryReplicationGroup), + resource.TestCheckResourceAttr(resourceName, "cluster_enabled", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAWSElasticacheGlobalReplicationGroupExists(resourceName string, v *elasticache.GlobalReplicationGroup) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -388,9 +420,9 @@ resource "aws_elasticache_replication_group" "test" { func testAccAWSElasticacheGlobalReplicationGroupConfig_MultipleSecondaries(rName string) string { return composeConfig( testAccMultipleRegionProviderConfig(3), - testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAws), - testAccElasticacheVpcBaseWithProvider(rName, "alternate", ProviderNameAwsAlternate), - testAccElasticacheVpcBaseWithProvider(rName, "third", ProviderNameAwsThird), + testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAws, 1), + testAccElasticacheVpcBaseWithProvider(rName, "alternate", ProviderNameAwsAlternate, 1), + testAccElasticacheVpcBaseWithProvider(rName, "third", ProviderNameAwsThird, 1), fmt.Sprintf(` resource "aws_elasticache_global_replication_group" "test" { provider = aws @@ -443,9 +475,9 @@ resource "aws_elasticache_replication_group" "third" { func testAccAWSElasticacheReplicationGroupConfig_ReplaceSecondary_DifferentRegion_Setup(rName string) string { return composeConfig( testAccMultipleRegionProviderConfig(3), - testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAws), - testAccElasticacheVpcBaseWithProvider(rName, "secondary", ProviderNameAwsAlternate), - testAccElasticacheVpcBaseWithProvider(rName, "third", ProviderNameAwsThird), + testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAws, 1), + testAccElasticacheVpcBaseWithProvider(rName, "secondary", ProviderNameAwsAlternate, 1), + testAccElasticacheVpcBaseWithProvider(rName, "third", ProviderNameAwsThird, 1), fmt.Sprintf(` resource "aws_elasticache_global_replication_group" "test" { provider = aws @@ -486,9 +518,9 @@ resource "aws_elasticache_replication_group" "secondary" { func testAccAWSElasticacheReplicationGroupConfig_ReplaceSecondary_DifferentRegion_Move(rName string) string { return composeConfig( testAccMultipleRegionProviderConfig(3), - testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAws), - testAccElasticacheVpcBaseWithProvider(rName, "secondary", ProviderNameAwsAlternate), - testAccElasticacheVpcBaseWithProvider(rName, "third", ProviderNameAwsThird), + testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAws, 1), + testAccElasticacheVpcBaseWithProvider(rName, "secondary", ProviderNameAwsAlternate, 1), + testAccElasticacheVpcBaseWithProvider(rName, "third", ProviderNameAwsThird, 1), fmt.Sprintf(` resource "aws_elasticache_global_replication_group" "test" { provider = aws @@ -526,7 +558,32 @@ resource "aws_elasticache_replication_group" "third" { `, rName)) } -func testAccElasticacheVpcBaseWithProvider(rName, name, provider string) string { +func testAccAWSElasticacheGlobalReplicationGroupConfig_ClusterMode(rName string) string { + return fmt.Sprintf(` +resource "aws_elasticache_global_replication_group" "test" { + global_replication_group_id_suffix = %[1]q + primary_replication_group_id = aws_elasticache_replication_group.test.id +} + +resource "aws_elasticache_replication_group" "test" { + replication_group_id = %[1]q + replication_group_description = "test" + + engine = "redis" + engine_version = "6.x" + node_type = "cache.m5.large" + + parameter_group_name = "default.redis6.x.cluster.on" + automatic_failover_enabled = true + cluster_mode { + num_node_groups = 2 + replicas_per_node_group = 1 + } +} +`, rName) +} + +func testAccElasticacheVpcBaseWithProvider(rName, name, provider string, subnetCount int) string { return composeConfig( testAccAvailableAZsNoOptInConfigWithProvider(name, provider), fmt.Sprintf(` @@ -538,27 +595,21 @@ resource "aws_vpc" "%[1]s" { resource "aws_subnet" "%[1]s" { provider = %[2]s + + count = %[4]d vpc_id = aws_vpc.%[1]s.id - cidr_block = "192.168.0.0/20" - availability_zone = data.aws_availability_zones.%[1]s.names[0] - - tags = { - Name = "tf-acc-elasticache-replication-group-at-rest-encryption" - } + cidr_block = "192.168.${count.index}.0/24" + availability_zone = data.aws_availability_zones.%[1]s.names[count.index] } resource "aws_elasticache_subnet_group" "%[1]s" { provider = %[2]s - name = %[3]q - description = "tf-test-cache-subnet-group-descr" - - subnet_ids = [ - aws_subnet.%[1]s.id, - ] + name = %[3]q + subnet_ids = aws_subnet.%[1]s[*].id } -`, name, provider, rName), +`, name, provider, rName, subnetCount), ) } diff --git a/aws/resource_aws_elasticache_replication_group.go b/aws/resource_aws_elasticache_replication_group.go index ebcade4f5410..831ec9bfd308 100644 --- a/aws/resource_aws_elasticache_replication_group.go +++ b/aws/resource_aws_elasticache_replication_group.go @@ -81,18 +81,19 @@ func resourceAwsElasticacheReplicationGroup() *schema.Resource { Computed: true, }, "cluster_mode": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, - ExactlyOneOf: []string{"cluster_mode", "number_cache_clusters"}, + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "replicas_per_node_group": { - Type: schema.TypeInt, - Required: true, - }, "num_node_groups": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ConflictsWith: []string{"number_cache_clusters", "global_replication_group_id"}, + }, + "replicas_per_node_group": { Type: schema.TypeInt, Required: true, }, @@ -126,8 +127,7 @@ func resourceAwsElasticacheReplicationGroup() *schema.Resource { ForceNew: true, Computed: true, ConflictsWith: []string{ - "automatic_failover_enabled", - "cluster_mode", // should/will be "num_node_groups" + "cluster_mode.0.num_node_groups", // should/will be top-level "num_node_groups" "parameter_group_name", "engine", "engine_version", @@ -171,15 +171,18 @@ func resourceAwsElasticacheReplicationGroup() *schema.Resource { ValidateFunc: validateArn, }, "number_cache_clusters": { - Type: schema.TypeInt, - Computed: true, - Optional: true, - ExactlyOneOf: []string{"cluster_mode", "number_cache_clusters"}, + Type: schema.TypeInt, + Computed: true, + Optional: true, + ConflictsWith: []string{"cluster_mode.0.num_node_groups"}, }, "parameter_group_name": { Type: schema.TypeString, Optional: true, Computed: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return strings.HasPrefix(old, "global-datastore-") + }, }, "port": { Type: schema.TypeInt, @@ -412,7 +415,7 @@ func resourceAwsElasticacheReplicationGroupCreate(d *schema.ResourceData, meta i clusterModeList := clusterMode.([]interface{}) attributes := clusterModeList[0].(map[string]interface{}) - if v, ok := attributes["num_node_groups"]; ok { + if v, ok := attributes["num_node_groups"]; ok && v != 0 { params.NumNodeGroups = aws.Int64(int64(v.(int))) } diff --git a/aws/resource_aws_elasticache_replication_group_test.go b/aws/resource_aws_elasticache_replication_group_test.go index 398a5acb3c5f..5822a2db70dc 100644 --- a/aws/resource_aws_elasticache_replication_group_test.go +++ b/aws/resource_aws_elasticache_replication_group_test.go @@ -95,19 +95,19 @@ func TestAccAWSElasticacheReplicationGroup_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSElasticacheReplicationGroupConfig(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), resource.TestCheckResourceAttr(resourceName, "engine", "redis"), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "elasticache", fmt.Sprintf("replicationgroup:%s", rName)), - resource.TestCheckResourceAttr(resourceName, "number_cache_clusters", "2"), + resource.TestCheckResourceAttr(resourceName, "number_cache_clusters", "1"), resource.TestCheckResourceAttr(resourceName, "multi_az_enabled", "false"), resource.TestCheckResourceAttr(resourceName, "automatic_failover_enabled", "false"), - resource.TestCheckResourceAttr(resourceName, "member_clusters.#", "2"), + resource.TestCheckResourceAttr(resourceName, "member_clusters.#", "1"), resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "false"), resource.TestCheckResourceAttr(resourceName, "parameter_group_name", "default.redis6.x"), resource.TestCheckResourceAttr(resourceName, "cluster_mode.#", "1"), - resource.TestCheckResourceAttr(resourceName, "cluster_mode.0.replicas_per_node_group", "1"), resource.TestCheckResourceAttr(resourceName, "cluster_mode.0.num_node_groups", "1"), + resource.TestCheckResourceAttr(resourceName, "cluster_mode.0.replicas_per_node_group", "0"), resource.TestCheckResourceAttr(resourceName, "cluster_enabled", "false"), resource.TestCheckResourceAttr(resourceName, "engine_version", "6.x"), resource.TestMatchResourceAttr(resourceName, "engine_version_actual", regexp.MustCompile(`^6\.[[:digit:]]+\.[[:digit:]]+$`)), @@ -138,8 +138,7 @@ func TestAccAWSElasticacheReplicationGroup_Uppercase(t *testing.T) { Config: testAccAWSElasticacheReplicationGroupConfig_Uppercase(strings.ToUpper(rName)), Check: resource.ComposeTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), - resource.TestCheckResourceAttr( - resourceName, "replication_group_id", rName), + resource.TestCheckResourceAttr(resourceName, "replication_group_id", rName), ), }, { @@ -230,7 +229,7 @@ func TestAccAWSElasticacheReplicationGroup_disappears(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSElasticacheReplicationGroupConfig(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), testAccCheckResourceDisappears(testAccProvider, resourceAwsElasticacheReplicationGroup(), resourceName), ), @@ -253,14 +252,11 @@ func TestAccAWSElasticacheReplicationGroup_updateDescription(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSElasticacheReplicationGroupConfig(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), - resource.TestCheckResourceAttr( - resourceName, "number_cache_clusters", "2"), - resource.TestCheckResourceAttr( - resourceName, "replication_group_description", "test description"), - resource.TestCheckResourceAttr( - resourceName, "auto_minor_version_upgrade", "false"), + resource.TestCheckResourceAttr(resourceName, "number_cache_clusters", "1"), + resource.TestCheckResourceAttr(resourceName, "replication_group_description", "test description"), + resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "false"), ), }, { @@ -271,14 +267,11 @@ func TestAccAWSElasticacheReplicationGroup_updateDescription(t *testing.T) { }, { Config: testAccAWSElasticacheReplicationGroupConfigUpdatedDescription(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), - resource.TestCheckResourceAttr( - resourceName, "number_cache_clusters", "2"), - resource.TestCheckResourceAttr( - resourceName, "replication_group_description", "updated description"), - resource.TestCheckResourceAttr( - resourceName, "auto_minor_version_upgrade", "true"), + resource.TestCheckResourceAttr(resourceName, "number_cache_clusters", "1"), + resource.TestCheckResourceAttr(resourceName, "replication_group_description", "updated description"), + resource.TestCheckResourceAttr(resourceName, "auto_minor_version_upgrade", "true"), ), }, }, @@ -298,10 +291,9 @@ func TestAccAWSElasticacheReplicationGroup_updateMaintenanceWindow(t *testing.T) Steps: []resource.TestStep{ { Config: testAccAWSElasticacheReplicationGroupConfig(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), - resource.TestCheckResourceAttr( - resourceName, "maintenance_window", "tue:06:30-tue:07:30"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window", "tue:06:30-tue:07:30"), ), }, { @@ -312,10 +304,9 @@ func TestAccAWSElasticacheReplicationGroup_updateMaintenanceWindow(t *testing.T) }, { Config: testAccAWSElasticacheReplicationGroupConfigUpdatedMaintenanceWindow(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), - resource.TestCheckResourceAttr( - resourceName, "maintenance_window", "wed:03:00-wed:06:00"), + resource.TestCheckResourceAttr(resourceName, "maintenance_window", "wed:03:00-wed:06:00"), ), }, }, @@ -335,12 +326,10 @@ func TestAccAWSElasticacheReplicationGroup_updateNodeSize(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSElasticacheReplicationGroupConfig(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), - resource.TestCheckResourceAttr( - resourceName, "number_cache_clusters", "2"), - resource.TestCheckResourceAttr( - resourceName, "node_type", "cache.t3.small"), + resource.TestCheckResourceAttr(resourceName, "number_cache_clusters", "1"), + resource.TestCheckResourceAttr(resourceName, "node_type", "cache.t3.small"), ), }, { @@ -351,12 +340,10 @@ func TestAccAWSElasticacheReplicationGroup_updateNodeSize(t *testing.T) { }, { Config: testAccAWSElasticacheReplicationGroupConfigUpdatedNodeSize(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), - resource.TestCheckResourceAttr( - resourceName, "number_cache_clusters", "2"), - resource.TestCheckResourceAttr( - resourceName, "node_type", "cache.t3.medium"), + resource.TestCheckResourceAttr(resourceName, "number_cache_clusters", "1"), + resource.TestCheckResourceAttr(resourceName, "node_type", "cache.t3.medium"), ), }, }, @@ -910,7 +897,7 @@ func TestAccAWSElasticacheReplicationGroup_clusteringAndCacheNodesCausesError(t Steps: []resource.TestStep{ { Config: testAccAWSElasticacheReplicationGroupNativeRedisClusterErrorConfig(rInt, rName), - ExpectError: regexp.MustCompile("only one of `cluster_mode,number_cache_clusters` can be\\s+specified, but `cluster_mode,number_cache_clusters` were specified."), + ExpectError: regexp.MustCompile(`"cluster_mode.0.num_node_groups": conflicts with number_cache_clusters`), }, }, }) @@ -929,7 +916,7 @@ func TestAccAWSElasticacheReplicationGroup_enableSnapshotting(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSElasticacheReplicationGroupConfig(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), resource.TestCheckResourceAttr(resourceName, "snapshot_retention_limit", "0"), ), @@ -942,7 +929,7 @@ func TestAccAWSElasticacheReplicationGroup_enableSnapshotting(t *testing.T) { }, { Config: testAccAWSElasticacheReplicationGroupConfigEnableSnapshotting(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), resource.TestCheckResourceAttr(resourceName, "snapshot_retention_limit", "2"), ), @@ -1557,13 +1544,13 @@ func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_Basic(t *tes Steps: []resource.TestStep{ { Config: testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Basic(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), resource.TestCheckResourceAttrPair(resourceName, "global_replication_group_id", "aws_elasticache_global_replication_group.test", "global_replication_group_id"), resource.TestCheckResourceAttrPair(resourceName, "node_type", primaryGroupResourceName, "node_type"), resource.TestCheckResourceAttrPair(resourceName, "engine", primaryGroupResourceName, "engine"), resource.TestCheckResourceAttrPair(resourceName, "engine_version", primaryGroupResourceName, "engine_version"), - resource.TestCheckResourceAttrPair(resourceName, "parameter_group_name", primaryGroupResourceName, "parameter_group_name"), + resource.TestMatchResourceAttr(resourceName, "parameter_group_name", regexp.MustCompile(fmt.Sprintf("^global-datastore-%s-", rName))), ), }, { @@ -1595,13 +1582,17 @@ func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_Full(t *test Steps: []resource.TestStep{ { Config: testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Full(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), resource.TestCheckResourceAttrPair(resourceName, "global_replication_group_id", "aws_elasticache_global_replication_group.test", "global_replication_group_id"), resource.TestCheckResourceAttrPair(resourceName, "node_type", primaryGroupResourceName, "node_type"), resource.TestCheckResourceAttrPair(resourceName, "engine", primaryGroupResourceName, "engine"), resource.TestCheckResourceAttrPair(resourceName, "engine_version", primaryGroupResourceName, "engine_version"), - resource.TestCheckResourceAttrPair(resourceName, "parameter_group_name", primaryGroupResourceName, "parameter_group_name"), + resource.TestMatchResourceAttr(resourceName, "parameter_group_name", regexp.MustCompile(fmt.Sprintf("^global-datastore-%s-", rName))), + + resource.TestCheckResourceAttrPair(resourceName, "number_cache_clusters", primaryGroupResourceName, "number_cache_clusters"), + resource.TestCheckResourceAttrPair(resourceName, "multi_az_enabled", primaryGroupResourceName, "multi_az_enabled"), + resource.TestCheckResourceAttrPair(resourceName, "automatic_failover_enabled", primaryGroupResourceName, "automatic_failover_enabled"), resource.TestCheckResourceAttr(resourceName, "port", "16379"), @@ -1620,6 +1611,61 @@ func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_Full(t *test }) } +func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_ClusterMode_Basic(t *testing.T) { + var providers []*schema.Provider + var rg1, rg2 elasticache.ReplicationGroup + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_elasticache_replication_group.test" + primaryGroupResourceName := "aws_elasticache_replication_group.primary" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccMultipleRegionPreCheck(t, 2) + }, + ErrorCheck: testAccErrorCheck(t, elasticache.EndpointsID), + ProviderFactories: testAccProviderFactoriesMultipleRegion(&providers, 2), + CheckDestroy: testAccCheckAWSElasticacheReplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_ClusterMode(rName, 2, 1), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg1), + resource.TestCheckResourceAttr(resourceName, "cluster_mode.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cluster_mode.0.num_node_groups", "2"), + resource.TestCheckResourceAttr(resourceName, "cluster_mode.0.replicas_per_node_group", "1"), + resource.TestCheckResourceAttr(resourceName, "automatic_failover_enabled", "true"), + resource.TestMatchResourceAttr(resourceName, "parameter_group_name", regexp.MustCompile(fmt.Sprintf("^global-datastore-%s-", rName))), + + resource.TestCheckResourceAttr(primaryGroupResourceName, "cluster_mode.#", "1"), + resource.TestCheckResourceAttr(primaryGroupResourceName, "cluster_mode.0.num_node_groups", "2"), + resource.TestCheckResourceAttr(primaryGroupResourceName, "cluster_mode.0.replicas_per_node_group", "2"), + ), + }, + { + Config: testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Basic(rName), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"apply_immediately"}, + }, + { + Config: testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_ClusterMode(rName, 1, 3), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg2), + resource.TestCheckResourceAttr(resourceName, "cluster_mode.#", "1"), + resource.TestCheckResourceAttr(resourceName, "cluster_mode.0.num_node_groups", "2"), + resource.TestCheckResourceAttr(resourceName, "cluster_mode.0.replicas_per_node_group", "3"), + + resource.TestCheckResourceAttr(primaryGroupResourceName, "cluster_mode.#", "1"), + resource.TestCheckResourceAttr(primaryGroupResourceName, "cluster_mode.0.num_node_groups", "2"), + resource.TestCheckResourceAttr(primaryGroupResourceName, "cluster_mode.0.replicas_per_node_group", "1"), + ), + }, + }, + }) +} + // Test for out-of-band deletion // Naming to allow grouping all TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_* tests func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_disappears(t *testing.T) { // nosemgrep: acceptance-test-naming-parent-disappears @@ -1639,7 +1685,7 @@ func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_disappears(t Steps: []resource.TestStep{ { Config: testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Basic(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), testAccCheckResourceDisappears(testAccProvider, resourceAwsElasticacheReplicationGroup(), resourceName), ), @@ -1649,6 +1695,27 @@ func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_disappears(t }) } +func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_ClusterMode_Validation_NumNodeGroupsOnSecondary(t *testing.T) { + var providers []*schema.Provider + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccMultipleRegionPreCheck(t, 2) + }, + ErrorCheck: testAccErrorCheck(t, elasticache.EndpointsID), + ProviderFactories: testAccProviderFactoriesMultipleRegion(&providers, 2), + CheckDestroy: testAccCheckAWSElasticacheReplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_ClusterMode_NumNodeGroupsOnSecondary(rName), + ExpectError: regexp.MustCompile(`"global_replication_group_id": conflicts with cluster_mode.0.num_node_groups`), + }, + }, + }) +} + func testAccCheckAWSElasticacheReplicationGroupExists(n string, v *elasticache.ReplicationGroup) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -1758,7 +1825,6 @@ resource "aws_elasticache_replication_group" "test" { replication_group_id = %[1]q replication_group_description = "test description" node_type = "cache.t3.small" - number_cache_clusters = 2 port = 6379 apply_immediately = true auto_minor_version_upgrade = false @@ -1838,7 +1904,6 @@ resource "aws_elasticache_replication_group" "test" { replication_group_id = %[1]q replication_group_description = "test description" node_type = "cache.t3.small" - number_cache_clusters = 2 port = 6379 apply_immediately = true auto_minor_version_upgrade = false @@ -1883,7 +1948,6 @@ resource "aws_elasticache_replication_group" "test" { replication_group_id = %[1]q replication_group_description = "updated description" node_type = "cache.t3.small" - number_cache_clusters = 2 port = 6379 apply_immediately = true auto_minor_version_upgrade = true @@ -1897,7 +1961,6 @@ resource "aws_elasticache_replication_group" "test" { replication_group_id = %[1]q replication_group_description = "updated description" node_type = "cache.t3.small" - number_cache_clusters = 2 port = 6379 apply_immediately = true auto_minor_version_upgrade = true @@ -1913,7 +1976,6 @@ resource "aws_elasticache_replication_group" "test" { replication_group_id = %[1]q replication_group_description = "updated description" node_type = "cache.t3.medium" - number_cache_clusters = 2 port = 6379 apply_immediately = true } @@ -2227,7 +2289,7 @@ resource "aws_subnet" "test2" { } resource "aws_elasticache_subnet_group" "test" { - name = "tf-test-cache-subnet-%03d" + name = "tf-test-cache-subnet-%03[1]d" description = "tf-test-cache-subnet-group-descr" subnet_ids = [ @@ -2237,7 +2299,7 @@ resource "aws_elasticache_subnet_group" "test" { } resource "aws_security_group" "test" { - name = "tf-test-security-group-%03d" + name = "tf-test-security-group-%03[1]d" description = "tf-test-security-group-descr" vpc_id = aws_vpc.test.id @@ -2250,7 +2312,7 @@ resource "aws_security_group" "test" { } resource "aws_elasticache_replication_group" "test" { - replication_group_id = "tf-%s" + replication_group_id = %[2]q replication_group_description = "test description" node_type = "cache.t2.micro" port = 6379 @@ -2265,7 +2327,7 @@ resource "aws_elasticache_replication_group" "test" { number_cache_clusters = 3 } -`, rInt, rInt, rName) +`, rInt, rName) } func testAccAWSElasticacheReplicationGroupNativeRedisClusterConfig(rName string, numNodeGroups, replicasPerNodeGroup int) string { @@ -2754,8 +2816,8 @@ resource "aws_elasticache_replication_group" "test" { func testAccAWSElasticacheReplicationGroupConfig_Validation_GlobalReplicationGroupIdAndNodeType(rName string) string { return composeConfig( testAccMultipleRegionProviderConfig(2), - testAccElasticacheVpcBaseWithProvider(rName, "test", ProviderNameAws), - testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAwsAlternate), + testAccElasticacheVpcBaseWithProvider(rName, "test", ProviderNameAws, 1), + testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAwsAlternate, 1), fmt.Sprintf(` resource "aws_elasticache_replication_group" "test" { provider = aws @@ -2798,8 +2860,8 @@ resource "aws_elasticache_replication_group" "primary" { func testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Basic(rName string) string { return composeConfig( testAccMultipleRegionProviderConfig(2), - testAccElasticacheVpcBaseWithProvider(rName, "test", ProviderNameAws), - testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAwsAlternate), + testAccElasticacheVpcBaseWithProvider(rName, "test", ProviderNameAws, 1), + testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAwsAlternate, 1), fmt.Sprintf(` resource "aws_elasticache_replication_group" "test" { replication_group_id = "%[1]s-s" @@ -2807,8 +2869,6 @@ resource "aws_elasticache_replication_group" "test" { global_replication_group_id = aws_elasticache_global_replication_group.test.global_replication_group_id subnet_group_name = aws_elasticache_subnet_group.test.name - - number_cache_clusters = 1 } resource "aws_elasticache_global_replication_group" "test" { @@ -2838,8 +2898,8 @@ resource "aws_elasticache_replication_group" "primary" { func testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Full(rName string) string { return composeConfig( testAccMultipleRegionProviderConfig(2), - testAccElasticacheVpcBaseWithProvider(rName, "test", ProviderNameAws), - testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAwsAlternate), + testAccElasticacheVpcBaseWithProvider(rName, "test", ProviderNameAws, 2), + testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAwsAlternate, 2), fmt.Sprintf(` resource "aws_elasticache_replication_group" "test" { replication_group_id = "%[1]s-s" @@ -2848,7 +2908,9 @@ resource "aws_elasticache_replication_group" "test" { subnet_group_name = aws_elasticache_subnet_group.test.name - number_cache_clusters = 1 + number_cache_clusters = 2 + automatic_failover_enabled = true + multi_az_enabled = true port = 16379 } @@ -2870,9 +2932,11 @@ resource "aws_elasticache_replication_group" "primary" { node_type = "cache.m5.large" - engine = "redis" - engine_version = "5.0.6" - number_cache_clusters = 1 + engine = "redis" + engine_version = "5.0.6" + number_cache_clusters = 2 + automatic_failover_enabled = true + multi_az_enabled = true port = 6379 @@ -2882,6 +2946,105 @@ resource "aws_elasticache_replication_group" "primary" { `, rName)) } +func testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_ClusterMode(rName string, primaryReplicaCount, secondaryReplicaCount int) string { + return composeConfig( + testAccMultipleRegionProviderConfig(2), + testAccElasticacheVpcBaseWithProvider(rName, "test", ProviderNameAws, 2), + testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAwsAlternate, 2), + fmt.Sprintf(` +resource "aws_elasticache_replication_group" "test" { + replication_group_id = "%[1]s-s" + replication_group_description = "secondary" + global_replication_group_id = aws_elasticache_global_replication_group.test.global_replication_group_id + + subnet_group_name = aws_elasticache_subnet_group.test.name + + automatic_failover_enabled = true + cluster_mode { + replicas_per_node_group = %[3]d + } +} + +resource "aws_elasticache_global_replication_group" "test" { + provider = awsalternate + + global_replication_group_id_suffix = %[1]q + primary_replication_group_id = aws_elasticache_replication_group.primary.id +} + +resource "aws_elasticache_replication_group" "primary" { + provider = awsalternate + + replication_group_id = "%[1]s-p" + replication_group_description = "primary" + + subnet_group_name = aws_elasticache_subnet_group.primary.name + + engine = "redis" + engine_version = "6.x" + node_type = "cache.m5.large" + + parameter_group_name = "default.redis6.x.cluster.on" + + automatic_failover_enabled = true + cluster_mode { + num_node_groups = 2 + replicas_per_node_group = %[2]d + } +} +`, rName, primaryReplicaCount, secondaryReplicaCount)) +} + +func testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_ClusterMode_NumNodeGroupsOnSecondary(rName string) string { + return composeConfig( + testAccMultipleRegionProviderConfig(2), + testAccElasticacheVpcBaseWithProvider(rName, "test", ProviderNameAws, 2), + testAccElasticacheVpcBaseWithProvider(rName, "primary", ProviderNameAwsAlternate, 2), + fmt.Sprintf(` +resource "aws_elasticache_replication_group" "test" { + replication_group_id = "%[1]s-s" + replication_group_description = "secondary" + global_replication_group_id = aws_elasticache_global_replication_group.test.global_replication_group_id + + subnet_group_name = aws_elasticache_subnet_group.test.name + + automatic_failover_enabled = true + cluster_mode { + num_node_groups = 2 + replicas_per_node_group = 1 + } +} + +resource "aws_elasticache_global_replication_group" "test" { + provider = awsalternate + + global_replication_group_id_suffix = %[1]q + primary_replication_group_id = aws_elasticache_replication_group.primary.id +} + +resource "aws_elasticache_replication_group" "primary" { + provider = awsalternate + + replication_group_id = "%[1]s-p" + replication_group_description = "primary" + + subnet_group_name = aws_elasticache_subnet_group.primary.name + + engine = "redis" + engine_version = "6.x" + node_type = "cache.m5.large" + + parameter_group_name = "default.redis6.x.cluster.on" + + automatic_failover_enabled = true + cluster_mode { + num_node_groups = 2 + replicas_per_node_group = 1 + } +} +`, rName)) +} + func resourceAwsElasticacheReplicationGroupDisableAutomaticFailover(conn *elasticache.ElastiCache, replicationGroupID string, timeout time.Duration) error { return resourceAwsElasticacheReplicationGroupModify(conn, timeout, &elasticache.ModifyReplicationGroupInput{ ReplicationGroupId: aws.String(replicationGroupID), diff --git a/website/docs/r/elasticache_replication_group.html.markdown b/website/docs/r/elasticache_replication_group.html.markdown index 4ad29149a353..b41ac354c233 100644 --- a/website/docs/r/elasticache_replication_group.html.markdown +++ b/website/docs/r/elasticache_replication_group.html.markdown @@ -152,11 +152,11 @@ The following arguments are optional: * `auto_minor_version_upgrade` - (Optional) Specifies whether a minor engine upgrades will be applied automatically to the underlying Cache Cluster instances during the maintenance window. This parameter is currently not supported by the AWS API. Defaults to `true`. * `automatic_failover_enabled` - (Optional) Specifies whether a read-only replica will be automatically promoted to read/write primary if the existing primary fails. If enabled, `number_cache_clusters` must be greater than 1. Must be enabled for Redis (cluster mode enabled) replication groups. Defaults to `false`. * `availability_zones` - (Optional) A list of EC2 availability zones in which the replication group's cache clusters will be created. The order of the availability zones in the list is not important. -* `cluster_mode` - (Optional) Create a native Redis cluster. `automatic_failover_enabled` must be set to true. Cluster Mode documented below. Only 1 `cluster_mode` block is allowed. One of `number_cache_clusters` or `cluster_mode` is required. Note that configuring this block does not enable cluster mode, i.e. data sharding, this requires using a parameter group that has the parameter `cluster-enabled` set to true. +* `cluster_mode` - (Optional) Create a native Redis cluster. `automatic_failover_enabled` must be set to true. Cluster Mode documented below. Only 1 `cluster_mode` block is allowed. Note that configuring this block does not enable cluster mode, i.e. data sharding, this requires using a parameter group that has the parameter `cluster-enabled` set to true. * `engine` - (Optional) The name of the cache engine to be used for the clusters in this replication group. The only valid value is `redis`. * `engine_version` - (Optional) The version number of the cache engine to be used for the cache clusters in this replication group. If the version is 6 or higher, only the major version can be set, e.g. `6.x`, otherwise, specify the full version desired, e.g. `5.0.6`. The actual engine version used is returned in the attribute `engine_version_actual`, [defined below](#engine_version_actual). * `final_snapshot_identifier` - (Optional) The name of your final node group (shard) snapshot. ElastiCache creates the snapshot from the primary node in the cluster. If omitted, no final snapshot will be made. -* `global_replication_group_id` - (Optional) The ID of the global replication group to which this replication group should belong. If this parameter is specified, the replication group is added to the specified global replication group as a secondary replication group; otherwise, the replication group is not part of any global replication group. +* `global_replication_group_id` - (Optional) The ID of the global replication group to which this replication group should belong. If this parameter is specified, the replication group is added to the specified global replication group as a secondary replication group; otherwise, the replication group is not part of any global replication group. If `global_replication_group_id` is set, the `num_node_groups` parameter of the `cluster_mode` block cannot be set. * `kms_key_id` - (Optional) The ARN of the key that you wish to use if encrypting at rest. If not supplied, uses service managed encryption. Can be specified only if `at_rest_encryption_enabled = true`. * `maintenance_window` – (Optional) Specifies the weekly time range for when maintenance on the cache cluster is performed. The format is `ddd:hh24:mi-ddd:hh24:mi` (24H Clock UTC). The minimum maintenance window is a 60 minute period. Example: `sun:05:00-sun:09:00` * `multi_az_enabled` - (Optional) Specifies whether to enable Multi-AZ Support for the replication group. If `true`, `automatic_failover_enabled` must also be enabled. Defaults to `false`. @@ -177,7 +177,7 @@ The following arguments are optional: ### cluster_mode -* `num_node_groups` - (Required) Number of node groups (shards) for this Redis replication group. Changing this number will trigger an online resizing operation before other settings modifications. +* `num_node_groups` - (Optional) Number of node groups (shards) for this Redis replication group. Changing this number will trigger an online resizing operation before other settings modifications. Required unless `global_replication_group_id` is set. * `replicas_per_node_group` - (Required) Number of replica nodes in each node group. Valid values are 0 to 5. Changing this number will trigger an online resizing operation before other settings modifications. ## Attributes Reference From f5674848e0381f26796d32b5ea25df8798107dc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 06:10:24 +0000 Subject: [PATCH 0995/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.39.0 to 1.39.2 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.39.0 to 1.39.2. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.39.0...v1.39.2) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 0bdea89223d0..f8902716b7cf 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect - github.com/aws/aws-sdk-go v1.39.0 + github.com/aws/aws-sdk-go v1.39.2 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index 009b6a2c58dd..d87b7997d6f8 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo= -github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.39.2 h1:t+n2j0QfAmGqSQVb1VIGulhSMjfaZ/RqSGlcRKGED9Y= +github.com/aws/aws-sdk-go v1.39.2/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= @@ -411,10 +411,10 @@ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -460,10 +460,10 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 h1:RX8C8PRZc2hTIod4ds8ij+/4RQX3AqhYj3uOHmyaz4E= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= @@ -473,8 +473,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 0e1a17e22d3cbc1e1931e02072a4662791afe7c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 06:10:43 +0000 Subject: [PATCH 0996/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.39.0 to 1.39.2. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.39.0...v1.39.2) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 11 +- .../aws/aws-sdk-go/aws/endpoints/defaults.go | 7 + .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- .../aws/aws-sdk-go/service/sts/api.go | 632 +++++++++--------- .../aws/aws-sdk-go/service/sts/doc.go | 10 +- .../aws/aws-sdk-go/service/sts/errors.go | 18 +- .../golang.org/x/net/http/httpguts/httplex.go | 10 +- .../vendor/golang.org/x/net/http2/Dockerfile | 2 +- .../vendor/golang.org/x/net/http2/ascii.go | 53 ++ .../x/net/http2/client_conn_pool.go | 79 ++- .../vendor/golang.org/x/net/http2/go115.go | 27 + .../golang.org/x/net/http2/headermap.go | 7 +- .../golang.org/x/net/http2/not_go115.go | 31 + .../vendor/golang.org/x/net/http2/server.go | 38 +- .../golang.org/x/net/http2/transport.go | 165 +++-- .../vendor/golang.org/x/net/http2/write.go | 7 +- .../golang.org/x/net/idna/idna10.0.0.go | 113 ++-- .../vendor/golang.org/x/net/idna/idna9.0.0.go | 93 ++- .../x/text/secure/bidirule/bidirule10.0.0.go | 1 + .../x/text/secure/bidirule/bidirule9.0.0.go | 1 + .../x/text/unicode/bidi/tables10.0.0.go | 1 + .../x/text/unicode/bidi/tables11.0.0.go | 1 + .../x/text/unicode/bidi/tables12.0.0.go | 1 + .../x/text/unicode/bidi/tables13.0.0.go | 1 + .../x/text/unicode/bidi/tables9.0.0.go | 1 + .../x/text/unicode/norm/tables10.0.0.go | 1 + .../x/text/unicode/norm/tables11.0.0.go | 1 + .../x/text/unicode/norm/tables12.0.0.go | 1 + .../x/text/unicode/norm/tables13.0.0.go | 1 + .../x/text/unicode/norm/tables9.0.0.go | 1 + awsproviderlint/vendor/modules.txt | 6 +- 32 files changed, 796 insertions(+), 529 deletions(-) create mode 100644 awsproviderlint/vendor/golang.org/x/net/http2/ascii.go create mode 100644 awsproviderlint/vendor/golang.org/x/net/http2/go115.go create mode 100644 awsproviderlint/vendor/golang.org/x/net/http2/not_go115.go diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index fca5bc82fc91..bdd8e8498288 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.39.0 + github.com/aws/aws-sdk-go v1.39.2 github.com/bflad/tfproviderlint v0.27.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index cc485a97a227..834e806f661f 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -70,8 +70,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo= -github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.39.2 h1:t+n2j0QfAmGqSQVb1VIGulhSMjfaZ/RqSGlcRKGED9Y= +github.com/aws/aws-sdk-go v1.39.2/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.27.0 h1:KXF+dYaWJ/OSVyWIrk2NIYgQBMDDSOC4VQB/P+P5nhI= @@ -452,8 +452,9 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -507,6 +508,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 h1:RX8C8PRZc2hTIod4ds8ij+/4RQX3AqhYj3uOHmyaz4E= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -515,8 +517,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index 27797a72e982..ec4a25cd3f32 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -862,6 +862,7 @@ var awsPartition = partition{ "ap-southeast-2": endpoint{}, "eu-central-1": endpoint{}, "eu-west-1": endpoint{}, + "eu-west-2": endpoint{}, "fips": endpoint{ Hostname: "appstream2-fips.us-west-2.amazonaws.com", CredentialScope: credentialScope{ @@ -4813,6 +4814,12 @@ var awsPartition = partition{ Region: "eu-west-2", }, }, + "eu-west-3": endpoint{ + Hostname: "oidc.eu-west-3.amazonaws.com", + CredentialScope: credentialScope{ + Region: "eu-west-3", + }, + }, "us-east-1": endpoint{ Hostname: "oidc.us-east-1.amazonaws.com", CredentialScope: credentialScope{ diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index 62fbbf774048..3fb3be1d54d9 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.39.0" +const SDKVersion = "1.39.2" diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/api.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/api.go index 17c46378899f..3cffd533d91b 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/api.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/api.go @@ -57,19 +57,20 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o // AssumeRole API operation for AWS Security Token Service. // // Returns a set of temporary security credentials that you can use to access -// AWS resources that you might not normally have access to. These temporary -// credentials consist of an access key ID, a secret access key, and a security -// token. Typically, you use AssumeRole within your account or for cross-account -// access. For a comparison of AssumeRole with other API operations that produce -// temporary credentials, see Requesting Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the AWS STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) +// Amazon Web Services resources that you might not normally have access to. +// These temporary credentials consist of an access key ID, a secret access +// key, and a security token. Typically, you use AssumeRole within your account +// or for cross-account access. For a comparison of AssumeRole with other API +// operations that produce temporary credentials, see Requesting Temporary Security +// Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) +// and Comparing the STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // in the IAM User Guide. // // Permissions // // The temporary security credentials created by AssumeRole can be used to make -// API calls to any AWS service with the following exception: You cannot call -// the AWS STS GetFederationToken or GetSessionToken API operations. +// API calls to any Amazon Web Services service with the following exception: +// You cannot call the STS GetFederationToken or GetSessionToken API operations. // // (Optional) You can pass inline or managed session policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // to this operation. You can pass a single JSON policy document to use as an @@ -79,15 +80,15 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o // to this operation returns new temporary credentials. The resulting session's // permissions are the intersection of the role's identity-based policy and // the session policies. You can use the role's temporary credentials in subsequent -// AWS API calls to access resources in the account that owns the role. You -// cannot use session policies to grant more permissions than those allowed -// by the identity-based policy of the role that is being assumed. For more -// information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) +// Amazon Web Services API calls to access resources in the account that owns +// the role. You cannot use session policies to grant more permissions than +// those allowed by the identity-based policy of the role that is being assumed. +// For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // in the IAM User Guide. // -// To assume a role from a different account, your AWS account must be trusted -// by the role. The trust relationship is defined in the role's trust policy -// when the role is created. That trust policy states which accounts are allowed +// To assume a role from a different account, your account must be trusted by +// the role. The trust relationship is defined in the role's trust policy when +// the role is created. That trust policy states which accounts are allowed // to delegate that access to users in the account. // // A user who wants to access a role in a different account must also have permissions @@ -129,12 +130,12 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o // // (Optional) You can include multi-factor authentication (MFA) information // when you call AssumeRole. This is useful for cross-account scenarios to ensure -// that the user that assumes the role has been authenticated with an AWS MFA -// device. In that scenario, the trust policy of the role being assumed includes -// a condition that tests for MFA authentication. If the caller does not include -// valid MFA information, the request to assume the role is denied. The condition -// in a trust policy that tests for MFA authentication might look like the following -// example. +// that the user that assumes the role has been authenticated with an Amazon +// Web Services MFA device. In that scenario, the trust policy of the role being +// assumed includes a condition that tests for MFA authentication. If the caller +// does not include valid MFA information, the request to assume the role is +// denied. The condition in a trust policy that tests for MFA authentication +// might look like the following example. // // "Condition": {"Bool": {"aws:MultiFactorAuthPresent": true}} // @@ -160,11 +161,11 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o // // * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" // The request was rejected because the total packed size of the session policies -// and session tags combined was too large. An AWS conversion compresses the -// session policy document, session policy ARNs, and session tags into a packed -// binary format that has a separate limit. The error message indicates by percentage -// how close the policies and tags are to the upper size limit. For more information, -// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) +// and session tags combined was too large. An Amazon Web Services conversion +// compresses the session policy document, session policy ARNs, and session +// tags into a packed binary format that has a separate limit. The error message +// indicates by percentage how close the policies and tags are to the upper +// size limit. For more information, see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) // in the IAM User Guide. // // You could receive this error even though you meet other defined session policy @@ -176,7 +177,8 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o // STS is not activated in the requested region for the account that is being // asked to generate credentials. The account administrator must use the IAM // console to activate STS in that region. For more information, see Activating -// and Deactivating AWS STS in an AWS Region (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) +// and Deactivating Amazon Web Services STS in an Amazon Web Services Region +// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // // * ErrCodeExpiredTokenException "ExpiredTokenException" @@ -252,16 +254,17 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re // // Returns a set of temporary security credentials for users who have been authenticated // via a SAML authentication response. This operation provides a mechanism for -// tying an enterprise identity store or directory to role-based AWS access -// without user-specific credentials or configuration. For a comparison of AssumeRoleWithSAML -// with the other API operations that produce temporary credentials, see Requesting -// Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the AWS STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) +// tying an enterprise identity store or directory to role-based Amazon Web +// Services access without user-specific credentials or configuration. For a +// comparison of AssumeRoleWithSAML with the other API operations that produce +// temporary credentials, see Requesting Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) +// and Comparing the STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // in the IAM User Guide. // // The temporary security credentials returned by this operation consist of // an access key ID, a secret access key, and a security token. Applications -// can use these temporary security credentials to sign calls to AWS services. +// can use these temporary security credentials to sign calls to Amazon Web +// Services services. // // Session Duration // @@ -281,19 +284,19 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re // in the IAM User Guide. // // Role chaining (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-chaining) -// limits your AWS CLI or AWS API role session to a maximum of one hour. When -// you use the AssumeRole API operation to assume a role, you can specify the -// duration of your role session with the DurationSeconds parameter. You can -// specify a parameter value of up to 43200 seconds (12 hours), depending on -// the maximum session duration setting for your role. However, if you assume +// limits your CLI or Amazon Web Services API role session to a maximum of one +// hour. When you use the AssumeRole API operation to assume a role, you can +// specify the duration of your role session with the DurationSeconds parameter. +// You can specify a parameter value of up to 43200 seconds (12 hours), depending +// on the maximum session duration setting for your role. However, if you assume // a role using role chaining and provide a DurationSeconds parameter value // greater than one hour, the operation fails. // // Permissions // // The temporary security credentials created by AssumeRoleWithSAML can be used -// to make API calls to any AWS service with the following exception: you cannot -// call the STS GetFederationToken or GetSessionToken API operations. +// to make API calls to any Amazon Web Services service with the following exception: +// you cannot call the STS GetFederationToken or GetSessionToken API operations. // // (Optional) You can pass inline or managed session policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // to this operation. You can pass a single JSON policy document to use as an @@ -303,18 +306,19 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re // to this operation returns new temporary credentials. The resulting session's // permissions are the intersection of the role's identity-based policy and // the session policies. You can use the role's temporary credentials in subsequent -// AWS API calls to access resources in the account that owns the role. You -// cannot use session policies to grant more permissions than those allowed -// by the identity-based policy of the role that is being assumed. For more -// information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) +// Amazon Web Services API calls to access resources in the account that owns +// the role. You cannot use session policies to grant more permissions than +// those allowed by the identity-based policy of the role that is being assumed. +// For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // in the IAM User Guide. // -// Calling AssumeRoleWithSAML does not require the use of AWS security credentials. -// The identity of the caller is validated by using keys in the metadata document -// that is uploaded for the SAML provider entity for your identity provider. +// Calling AssumeRoleWithSAML does not require the use of Amazon Web Services +// security credentials. The identity of the caller is validated by using keys +// in the metadata document that is uploaded for the SAML provider entity for +// your identity provider. // -// Calling AssumeRoleWithSAML can result in an entry in your AWS CloudTrail -// logs. The entry includes the value in the NameID element of the SAML assertion. +// Calling AssumeRoleWithSAML can result in an entry in your CloudTrail logs. +// The entry includes the value in the NameID element of the SAML assertion. // We recommend that you use a NameIDType that is not associated with any personally // identifiable information (PII). For example, you could instead use the persistent // identifier (urn:oasis:names:tc:SAML:2.0:nameid-format:persistent). @@ -332,11 +336,11 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re // and additional limits, see IAM and STS Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length) // in the IAM User Guide. // -// An AWS conversion compresses the passed session policies and session tags -// into a packed binary format that has a separate limit. Your request can fail -// for this limit even if your plaintext meets the other requirements. The PackedPolicySize -// response element indicates by percentage how close the policies and tags -// for your request are to the upper size limit. +// An Amazon Web Services conversion compresses the passed session policies +// and session tags into a packed binary format that has a separate limit. Your +// request can fail for this limit even if your plaintext meets the other requirements. +// The PackedPolicySize response element indicates by percentage how close the +// policies and tags for your request are to the upper size limit. // // You can pass a session tag with the same key as a tag that is attached to // the role. When you do, session tags override the role's tags with the same @@ -356,10 +360,11 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re // SAML Configuration // // Before your application can call AssumeRoleWithSAML, you must configure your -// SAML identity provider (IdP) to issue the claims required by AWS. Additionally, -// you must use AWS Identity and Access Management (IAM) to create a SAML provider -// entity in your AWS account that represents your identity provider. You must -// also create an IAM role that specifies this SAML provider in its trust policy. +// SAML identity provider (IdP) to issue the claims required by Amazon Web Services. +// Additionally, you must use Identity and Access Management (IAM) to create +// a SAML provider entity in your Amazon Web Services account that represents +// your identity provider. You must also create an IAM role that specifies this +// SAML provider in its trust policy. // // For more information, see the following resources: // @@ -389,11 +394,11 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re // // * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" // The request was rejected because the total packed size of the session policies -// and session tags combined was too large. An AWS conversion compresses the -// session policy document, session policy ARNs, and session tags into a packed -// binary format that has a separate limit. The error message indicates by percentage -// how close the policies and tags are to the upper size limit. For more information, -// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) +// and session tags combined was too large. An Amazon Web Services conversion +// compresses the session policy document, session policy ARNs, and session +// tags into a packed binary format that has a separate limit. The error message +// indicates by percentage how close the policies and tags are to the upper +// size limit. For more information, see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) // in the IAM User Guide. // // You could receive this error even though you meet other defined session policy @@ -409,8 +414,9 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re // can also mean that the claim has expired or has been explicitly revoked. // // * ErrCodeInvalidIdentityTokenException "InvalidIdentityToken" -// The web identity token that was passed could not be validated by AWS. Get -// a new identity token from the identity provider and then retry the request. +// The web identity token that was passed could not be validated by Amazon Web +// Services. Get a new identity token from the identity provider and then retry +// the request. // // * ErrCodeExpiredTokenException "ExpiredTokenException" // The web identity token that was passed is expired or is not valid. Get a @@ -420,7 +426,8 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re // STS is not activated in the requested region for the account that is being // asked to generate credentials. The account administrator must use the IAM // console to activate STS in that region. For more information, see Activating -// and Deactivating AWS STS in an AWS Region (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) +// and Deactivating Amazon Web Services STS in an Amazon Web Services Region +// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithSAML @@ -496,30 +503,33 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI // Connect-compatible identity provider. // // For mobile applications, we recommend that you use Amazon Cognito. You can -// use Amazon Cognito with the AWS SDK for iOS Developer Guide (http://aws.amazon.com/sdkforios/) -// and the AWS SDK for Android Developer Guide (http://aws.amazon.com/sdkforandroid/) -// to uniquely identify a user. You can also supply the user with a consistent -// identity throughout the lifetime of an application. +// use Amazon Cognito with the Amazon Web Services SDK for iOS Developer Guide +// (http://aws.amazon.com/sdkforios/) and the Amazon Web Services SDK for Android +// Developer Guide (http://aws.amazon.com/sdkforandroid/) to uniquely identify +// a user. You can also supply the user with a consistent identity throughout +// the lifetime of an application. // // To learn more about Amazon Cognito, see Amazon Cognito Overview (https://docs.aws.amazon.com/mobile/sdkforandroid/developerguide/cognito-auth.html#d0e840) -// in AWS SDK for Android Developer Guide and Amazon Cognito Overview (https://docs.aws.amazon.com/mobile/sdkforios/developerguide/cognito-auth.html#d0e664) -// in the AWS SDK for iOS Developer Guide. -// -// Calling AssumeRoleWithWebIdentity does not require the use of AWS security -// credentials. Therefore, you can distribute an application (for example, on -// mobile devices) that requests temporary security credentials without including -// long-term AWS credentials in the application. You also don't need to deploy -// server-based proxy services that use long-term AWS credentials. Instead, -// the identity of the caller is validated by using a token from the web identity -// provider. For a comparison of AssumeRoleWithWebIdentity with the other API -// operations that produce temporary credentials, see Requesting Temporary Security -// Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the AWS STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) +// in Amazon Web Services SDK for Android Developer Guide and Amazon Cognito +// Overview (https://docs.aws.amazon.com/mobile/sdkforios/developerguide/cognito-auth.html#d0e664) +// in the Amazon Web Services SDK for iOS Developer Guide. +// +// Calling AssumeRoleWithWebIdentity does not require the use of Amazon Web +// Services security credentials. Therefore, you can distribute an application +// (for example, on mobile devices) that requests temporary security credentials +// without including long-term Amazon Web Services credentials in the application. +// You also don't need to deploy server-based proxy services that use long-term +// Amazon Web Services credentials. Instead, the identity of the caller is validated +// by using a token from the web identity provider. For a comparison of AssumeRoleWithWebIdentity +// with the other API operations that produce temporary credentials, see Requesting +// Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) +// and Comparing the STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // in the IAM User Guide. // // The temporary security credentials returned by this API consist of an access // key ID, a secret access key, and a security token. Applications can use these -// temporary security credentials to sign calls to AWS service API operations. +// temporary security credentials to sign calls to Amazon Web Services service +// API operations. // // Session Duration // @@ -539,8 +549,9 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI // Permissions // // The temporary security credentials created by AssumeRoleWithWebIdentity can -// be used to make API calls to any AWS service with the following exception: -// you cannot call the STS GetFederationToken or GetSessionToken API operations. +// be used to make API calls to any Amazon Web Services service with the following +// exception: you cannot call the STS GetFederationToken or GetSessionToken +// API operations. // // (Optional) You can pass inline or managed session policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // to this operation. You can pass a single JSON policy document to use as an @@ -550,10 +561,10 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI // to this operation returns new temporary credentials. The resulting session's // permissions are the intersection of the role's identity-based policy and // the session policies. You can use the role's temporary credentials in subsequent -// AWS API calls to access resources in the account that owns the role. You -// cannot use session policies to grant more permissions than those allowed -// by the identity-based policy of the role that is being assumed. For more -// information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) +// Amazon Web Services API calls to access resources in the account that owns +// the role. You cannot use session policies to grant more permissions than +// those allowed by the identity-based policy of the role that is being assumed. +// For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // in the IAM User Guide. // // Tags @@ -569,11 +580,11 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI // and additional limits, see IAM and STS Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length) // in the IAM User Guide. // -// An AWS conversion compresses the passed session policies and session tags -// into a packed binary format that has a separate limit. Your request can fail -// for this limit even if your plaintext meets the other requirements. The PackedPolicySize -// response element indicates by percentage how close the policies and tags -// for your request are to the upper size limit. +// An Amazon Web Services conversion compresses the passed session policies +// and session tags into a packed binary format that has a separate limit. Your +// request can fail for this limit even if your plaintext meets the other requirements. +// The PackedPolicySize response element indicates by percentage how close the +// policies and tags for your request are to the upper size limit. // // You can pass a session tag with the same key as a tag that is attached to // the role. When you do, the session tag overrides the role tag with the same @@ -598,7 +609,7 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI // the identity provider that is associated with the identity token. In other // words, the identity provider must be specified in the role's trust policy. // -// Calling AssumeRoleWithWebIdentity can result in an entry in your AWS CloudTrail +// Calling AssumeRoleWithWebIdentity can result in an entry in your CloudTrail // logs. The entry includes the Subject (http://openid.net/specs/openid-connect-core-1_0.html#Claims) // of the provided web identity token. We recommend that you avoid using any // personally identifiable information (PII) in this field. For example, you @@ -614,10 +625,10 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI // * Web Identity Federation Playground (https://aws.amazon.com/blogs/aws/the-aws-web-identity-federation-playground/). // Walk through the process of authenticating through Login with Amazon, // Facebook, or Google, getting temporary security credentials, and then -// using those credentials to make a request to AWS. +// using those credentials to make a request to Amazon Web Services. // -// * AWS SDK for iOS Developer Guide (http://aws.amazon.com/sdkforios/) and -// AWS SDK for Android Developer Guide (http://aws.amazon.com/sdkforandroid/). +// * Amazon Web Services SDK for iOS Developer Guide (http://aws.amazon.com/sdkforios/) +// and Amazon Web Services SDK for Android Developer Guide (http://aws.amazon.com/sdkforandroid/). // These toolkits contain sample apps that show how to invoke the identity // providers. The toolkits then show how to use the information from these // providers to get and use temporary security credentials. @@ -641,11 +652,11 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI // // * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" // The request was rejected because the total packed size of the session policies -// and session tags combined was too large. An AWS conversion compresses the -// session policy document, session policy ARNs, and session tags into a packed -// binary format that has a separate limit. The error message indicates by percentage -// how close the policies and tags are to the upper size limit. For more information, -// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) +// and session tags combined was too large. An Amazon Web Services conversion +// compresses the session policy document, session policy ARNs, and session +// tags into a packed binary format that has a separate limit. The error message +// indicates by percentage how close the policies and tags are to the upper +// size limit. For more information, see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) // in the IAM User Guide. // // You could receive this error even though you meet other defined session policy @@ -668,8 +679,9 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI // error persists, the identity provider might be down or not responding. // // * ErrCodeInvalidIdentityTokenException "InvalidIdentityToken" -// The web identity token that was passed could not be validated by AWS. Get -// a new identity token from the identity provider and then retry the request. +// The web identity token that was passed could not be validated by Amazon Web +// Services. Get a new identity token from the identity provider and then retry +// the request. // // * ErrCodeExpiredTokenException "ExpiredTokenException" // The web identity token that was passed is expired or is not valid. Get a @@ -679,7 +691,8 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI // STS is not activated in the requested region for the account that is being // asked to generate credentials. The account administrator must use the IAM // console to activate STS in that region. For more information, see Activating -// and Deactivating AWS STS in an AWS Region (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) +// and Deactivating Amazon Web Services STS in an Amazon Web Services Region +// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumeRoleWithWebIdentity @@ -749,16 +762,18 @@ func (c *STS) DecodeAuthorizationMessageRequest(input *DecodeAuthorizationMessag // DecodeAuthorizationMessage API operation for AWS Security Token Service. // // Decodes additional information about the authorization status of a request -// from an encoded message returned in response to an AWS request. +// from an encoded message returned in response to an Amazon Web Services request. // // For example, if a user is not authorized to perform an operation that he // or she has requested, the request returns a Client.UnauthorizedOperation -// response (an HTTP 403 response). Some AWS operations additionally return -// an encoded message that can provide details about this authorization failure. +// response (an HTTP 403 response). Some Amazon Web Services operations additionally +// return an encoded message that can provide details about this authorization +// failure. // -// Only certain AWS operations return an encoded authorization message. The -// documentation for an individual operation indicates whether that operation -// returns an encoded message in addition to returning an HTTP code. +// Only certain Amazon Web Services operations return an encoded authorization +// message. The documentation for an individual operation indicates whether +// that operation returns an encoded message in addition to returning an HTTP +// code. // // The message is encoded because the details of the authorization status can // constitute privileged information that the user who requested the operation @@ -869,12 +884,12 @@ func (c *STS) GetAccessKeyInfoRequest(input *GetAccessKeyInfoInput) (req *reques // in the IAM User Guide. // // When you pass an access key ID to this operation, it returns the ID of the -// AWS account to which the keys belong. Access key IDs beginning with AKIA -// are long-term credentials for an IAM user or the AWS account root user. Access -// key IDs beginning with ASIA are temporary credentials that are created using -// STS operations. If the account in the response belongs to you, you can sign -// in as the root user and review your root user access keys. Then, you can -// pull a credentials report (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html) +// Amazon Web Services account to which the keys belong. Access key IDs beginning +// with AKIA are long-term credentials for an IAM user or the Amazon Web Services +// account root user. Access key IDs beginning with ASIA are temporary credentials +// that are created using STS operations. If the account in the response belongs +// to you, you can sign in as the root user and review your root user access +// keys. Then, you can pull a credentials report (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html) // to learn which IAM user owns the keys. To learn who requested the temporary // credentials for an ASIA access key, view the STS events in your CloudTrail // logs (https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html) @@ -1050,7 +1065,7 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re // For a comparison of GetFederationToken with the other API operations that // produce temporary credentials, see Requesting Temporary Security Credentials // (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the AWS STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) +// and Comparing the STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // in the IAM User Guide. // // You can create a mobile-based or browser-based app that can authenticate @@ -1062,11 +1077,11 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re // in the IAM User Guide. // // You can also call GetFederationToken using the security credentials of an -// AWS account root user, but we do not recommend it. Instead, we recommend -// that you create an IAM user for the purpose of the proxy application. Then -// attach a policy to the IAM user that limits federated users to only the actions -// and resources that they need to access. For more information, see IAM Best -// Practices (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) +// Amazon Web Services account root user, but we do not recommend it. Instead, +// we recommend that you create an IAM user for the purpose of the proxy application. +// Then attach a policy to the IAM user that limits federated users to only +// the actions and resources that they need to access. For more information, +// see IAM Best Practices (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) // in the IAM User Guide. // // Session duration @@ -1074,15 +1089,16 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re // The temporary credentials are valid for the specified duration, from 900 // seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours). The default // session duration is 43,200 seconds (12 hours). Temporary credentials that -// are obtained by using AWS account root user credentials have a maximum duration -// of 3,600 seconds (1 hour). +// are obtained by using Amazon Web Services account root user credentials have +// a maximum duration of 3,600 seconds (1 hour). // // Permissions // // You can use the temporary credentials created by GetFederationToken in any -// AWS service except the following: +// Amazon Web Services service except the following: // -// * You cannot call any IAM operations using the AWS CLI or the AWS API. +// * You cannot call any IAM operations using the CLI or the Amazon Web Services +// API. // // * You cannot call any STS operations except GetCallerIdentity. // @@ -1126,11 +1142,11 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re // in the IAM User Guide. // // You can also call GetFederationToken using the security credentials of an -// AWS account root user, but we do not recommend it. Instead, we recommend -// that you create an IAM user for the purpose of the proxy application. Then -// attach a policy to the IAM user that limits federated users to only the actions -// and resources that they need to access. For more information, see IAM Best -// Practices (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) +// Amazon Web Services account root user, but we do not recommend it. Instead, +// we recommend that you create an IAM user for the purpose of the proxy application. +// Then attach a policy to the IAM user that limits federated users to only +// the actions and resources that they need to access. For more information, +// see IAM Best Practices (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) // in the IAM User Guide. // // Session duration @@ -1138,15 +1154,16 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re // The temporary credentials are valid for the specified duration, from 900 // seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours). The default // session duration is 43,200 seconds (12 hours). Temporary credentials that -// are obtained by using AWS account root user credentials have a maximum duration -// of 3,600 seconds (1 hour). +// are obtained by using Amazon Web Services account root user credentials have +// a maximum duration of 3,600 seconds (1 hour). // // Permissions // // You can use the temporary credentials created by GetFederationToken in any -// AWS service except the following: +// Amazon Web Services service except the following: // -// * You cannot call any IAM operations using the AWS CLI or the AWS API. +// * You cannot call any IAM operations using the CLI or the Amazon Web Services +// API. // // * You cannot call any STS operations except GetCallerIdentity. // @@ -1208,11 +1225,11 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re // // * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge" // The request was rejected because the total packed size of the session policies -// and session tags combined was too large. An AWS conversion compresses the -// session policy document, session policy ARNs, and session tags into a packed -// binary format that has a separate limit. The error message indicates by percentage -// how close the policies and tags are to the upper size limit. For more information, -// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) +// and session tags combined was too large. An Amazon Web Services conversion +// compresses the session policy document, session policy ARNs, and session +// tags into a packed binary format that has a separate limit. The error message +// indicates by percentage how close the policies and tags are to the upper +// size limit. For more information, see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) // in the IAM User Guide. // // You could receive this error even though you meet other defined session policy @@ -1224,7 +1241,8 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re // STS is not activated in the requested region for the account that is being // asked to generate credentials. The account administrator must use the IAM // console to activate STS in that region. For more information, see Activating -// and Deactivating AWS STS in an AWS Region (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) +// and Deactivating Amazon Web Services STS in an Amazon Web Services Region +// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetFederationToken @@ -1293,51 +1311,53 @@ func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request. // GetSessionToken API operation for AWS Security Token Service. // -// Returns a set of temporary credentials for an AWS account or IAM user. The -// credentials consist of an access key ID, a secret access key, and a security -// token. Typically, you use GetSessionToken if you want to use MFA to protect -// programmatic calls to specific AWS API operations like Amazon EC2 StopInstances. -// MFA-enabled IAM users would need to call GetSessionToken and submit an MFA -// code that is associated with their MFA device. Using the temporary security -// credentials that are returned from the call, IAM users can then make programmatic -// calls to API operations that require MFA authentication. If you do not supply -// a correct MFA code, then the API returns an access denied error. For a comparison -// of GetSessionToken with the other API operations that produce temporary credentials, -// see Requesting Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the AWS STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) +// Returns a set of temporary credentials for an Amazon Web Services account +// or IAM user. The credentials consist of an access key ID, a secret access +// key, and a security token. Typically, you use GetSessionToken if you want +// to use MFA to protect programmatic calls to specific Amazon Web Services +// API operations like Amazon EC2 StopInstances. MFA-enabled IAM users would +// need to call GetSessionToken and submit an MFA code that is associated with +// their MFA device. Using the temporary security credentials that are returned +// from the call, IAM users can then make programmatic calls to API operations +// that require MFA authentication. If you do not supply a correct MFA code, +// then the API returns an access denied error. For a comparison of GetSessionToken +// with the other API operations that produce temporary credentials, see Requesting +// Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) +// and Comparing the STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) // in the IAM User Guide. // // Session Duration // -// The GetSessionToken operation must be called by using the long-term AWS security -// credentials of the AWS account root user or an IAM user. Credentials that -// are created by IAM users are valid for the duration that you specify. This -// duration can range from 900 seconds (15 minutes) up to a maximum of 129,600 -// seconds (36 hours), with a default of 43,200 seconds (12 hours). Credentials -// based on account credentials can range from 900 seconds (15 minutes) up to -// 3,600 seconds (1 hour), with a default of 1 hour. +// The GetSessionToken operation must be called by using the long-term Amazon +// Web Services security credentials of the Amazon Web Services account root +// user or an IAM user. Credentials that are created by IAM users are valid +// for the duration that you specify. This duration can range from 900 seconds +// (15 minutes) up to a maximum of 129,600 seconds (36 hours), with a default +// of 43,200 seconds (12 hours). Credentials based on account credentials can +// range from 900 seconds (15 minutes) up to 3,600 seconds (1 hour), with a +// default of 1 hour. // // Permissions // // The temporary security credentials created by GetSessionToken can be used -// to make API calls to any AWS service with the following exceptions: +// to make API calls to any Amazon Web Services service with the following exceptions: // // * You cannot call any IAM API operations unless MFA authentication information // is included in the request. // // * You cannot call any STS API except AssumeRole or GetCallerIdentity. // -// We recommend that you do not call GetSessionToken with AWS account root user -// credentials. Instead, follow our best practices (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users) +// We recommend that you do not call GetSessionToken with Amazon Web Services +// account root user credentials. Instead, follow our best practices (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users) // by creating one or more IAM users, giving them the necessary permissions, -// and using IAM users for everyday interaction with AWS. +// and using IAM users for everyday interaction with Amazon Web Services. // // The credentials that are returned by GetSessionToken are based on permissions // associated with the user whose credentials were used to call the operation. -// If GetSessionToken is called using AWS account root user credentials, the -// temporary credentials have root user permissions. Similarly, if GetSessionToken -// is called using the credentials of an IAM user, the temporary credentials -// have the same permissions as the IAM user. +// If GetSessionToken is called using Amazon Web Services account root user +// credentials, the temporary credentials have root user permissions. Similarly, +// if GetSessionToken is called using the credentials of an IAM user, the temporary +// credentials have the same permissions as the IAM user. // // For more information about using GetSessionToken to create temporary credentials, // go to Temporary Credentials for Users in Untrusted Environments (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getsessiontoken) @@ -1355,7 +1375,8 @@ func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request. // STS is not activated in the requested region for the account that is being // asked to generate credentials. The account administrator must use the IAM // console to activate STS in that region. For more information, see Activating -// and Deactivating AWS STS in an AWS Region (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) +// and Deactivating Amazon Web Services STS in an Amazon Web Services Region +// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. // // See also, https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/GetSessionToken @@ -1401,7 +1422,7 @@ type AssumeRoleInput struct { // to the federation endpoint for a console sign-in token takes a SessionDuration // parameter that specifies the maximum length of the console session. For more // information, see Creating a URL that Enables Federated Users to Access the - // AWS Management Console (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) + // Management Console (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) // in the IAM User Guide. DurationSeconds *int64 `min:"900" type:"integer"` @@ -1413,8 +1434,8 @@ type AssumeRoleInput struct { // of the trusting account might send an external ID to the administrator of // the trusted account. That way, only someone with the ID can assume the role, // rather than everyone in the account. For more information about the external - // ID, see How to Use an External ID When Granting Access to Your AWS Resources - // to a Third Party (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) + // ID, see How to Use an External ID When Granting Access to Your Amazon Web + // Services Resources to a Third Party (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) // in the IAM User Guide. // // The regex used to validate this parameter is a string of characters consisting @@ -1427,10 +1448,11 @@ type AssumeRoleInput struct { // This parameter is optional. Passing policies to this operation returns new // temporary credentials. The resulting session's permissions are the intersection // of the role's identity-based policy and the session policies. You can use - // the role's temporary credentials in subsequent AWS API calls to access resources - // in the account that owns the role. You cannot use session policies to grant - // more permissions than those allowed by the identity-based policy of the role - // that is being assumed. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) + // the role's temporary credentials in subsequent Amazon Web Services API calls + // to access resources in the account that owns the role. You cannot use session + // policies to grant more permissions than those allowed by the identity-based + // policy of the role that is being assumed. For more information, see Session + // Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // in the IAM User Guide. // // The plaintext that you use for both inline and managed session policies can't @@ -1439,11 +1461,11 @@ type AssumeRoleInput struct { // \u00FF). It can also include the tab (\u0009), linefeed (\u000A), and carriage // return (\u000D) characters. // - // An AWS conversion compresses the passed session policies and session tags - // into a packed binary format that has a separate limit. Your request can fail - // for this limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags - // for your request are to the upper size limit. + // An Amazon Web Services conversion compresses the passed session policies + // and session tags into a packed binary format that has a separate limit. Your + // request can fail for this limit even if your plaintext meets the other requirements. + // The PackedPolicySize response element indicates by percentage how close the + // policies and tags for your request are to the upper size limit. Policy *string `min:"1" type:"string"` // The Amazon Resource Names (ARNs) of the IAM managed policies that you want @@ -1453,22 +1475,22 @@ type AssumeRoleInput struct { // This parameter is optional. You can provide up to 10 managed policy ARNs. // However, the plaintext that you use for both inline and managed session policies // can't exceed 2,048 characters. For more information about ARNs, see Amazon - // Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // in the AWS General Reference. + // Resource Names (ARNs) and Amazon Web Services Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) + // in the Amazon Web Services General Reference. // - // An AWS conversion compresses the passed session policies and session tags - // into a packed binary format that has a separate limit. Your request can fail - // for this limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags - // for your request are to the upper size limit. + // An Amazon Web Services conversion compresses the passed session policies + // and session tags into a packed binary format that has a separate limit. Your + // request can fail for this limit even if your plaintext meets the other requirements. + // The PackedPolicySize response element indicates by percentage how close the + // policies and tags for your request are to the upper size limit. // // Passing policies to this operation returns new temporary credentials. The // resulting session's permissions are the intersection of the role's identity-based // policy and the session policies. You can use the role's temporary credentials - // in subsequent AWS API calls to access resources in the account that owns - // the role. You cannot use session policies to grant more permissions than - // those allowed by the identity-based policy of the role that is being assumed. - // For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) + // in subsequent Amazon Web Services API calls to access resources in the account + // that owns the role. You cannot use session policies to grant more permissions + // than those allowed by the identity-based policy of the role that is being + // assumed. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // in the IAM User Guide. PolicyArns []*PolicyDescriptorType `type:"list"` @@ -1485,7 +1507,7 @@ type AssumeRoleInput struct { // account that owns the role. The role session name is also used in the ARN // of the assumed role principal. This means that subsequent cross-account API // requests that use the temporary security credentials will expose the role - // session name to the external account in their AWS CloudTrail logs. + // session name to the external account in their CloudTrail logs. // // The regex used to validate this parameter is a string of characters consisting // of upper- and lower-case alphanumeric characters with no spaces. You can @@ -1510,23 +1532,23 @@ type AssumeRoleInput struct { // // You can require users to specify a source identity when they assume a role. // You do this by using the sts:SourceIdentity condition key in a role trust - // policy. You can use source identity information in AWS CloudTrail logs to - // determine who took actions with a role. You can use the aws:SourceIdentity - // condition key to further control access to AWS resources based on the value - // of source identity. For more information about using source identity, see - // Monitor and control actions taken with assumed roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html) + // policy. You can use source identity information in CloudTrail logs to determine + // who took actions with a role. You can use the aws:SourceIdentity condition + // key to further control access to Amazon Web Services resources based on the + // value of source identity. For more information about using source identity, + // see Monitor and control actions taken with assumed roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html) // in the IAM User Guide. // // The regex used to validate this parameter is a string of characters consisting // of upper- and lower-case alphanumeric characters with no spaces. You can // also include underscores or any of the following characters: =,.@-. You cannot - // use a value that begins with the text aws:. This prefix is reserved for AWS - // internal use. + // use a value that begins with the text aws:. This prefix is reserved for Amazon + // Web Services internal use. SourceIdentity *string `min:"2" type:"string"` // A list of session tags that you want to pass. Each session tag consists of // a key name and an associated value. For more information about session tags, - // see Tagging AWS STS Sessions (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) + // see Tagging STS Sessions (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) // in the IAM User Guide. // // This parameter is optional. You can pass up to 50 session tags. The plaintext @@ -1535,11 +1557,11 @@ type AssumeRoleInput struct { // Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length) // in the IAM User Guide. // - // An AWS conversion compresses the passed session policies and session tags - // into a packed binary format that has a separate limit. Your request can fail - // for this limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags - // for your request are to the upper size limit. + // An Amazon Web Services conversion compresses the passed session policies + // and session tags into a packed binary format that has a separate limit. Your + // request can fail for this limit even if your plaintext meets the other requirements. + // The PackedPolicySize response element indicates by percentage how close the + // policies and tags for your request are to the upper size limit. // // You can pass a session tag with the same key as a tag that is already attached // to the role. When you do, session tags override a role tag with the same @@ -1554,7 +1576,7 @@ type AssumeRoleInput struct { // Additionally, if you used temporary credentials to perform this operation, // the new session inherits any transitive session tags from the calling session. // If you pass a session tag with the same key as an inherited tag, the operation - // fails. To view the inherited tags for a session, see the AWS CloudTrail logs. + // fails. To view the inherited tags for a session, see the CloudTrail logs. // For more information, see Viewing Session Tags in CloudTrail (https://docs.aws.amazon.com/IAM/latest/UserGuide/session-tags.html#id_session-tags_ctlogs) // in the IAM User Guide. Tags []*Tag `type:"list"` @@ -1720,7 +1742,8 @@ func (s *AssumeRoleInput) SetTransitiveTagKeys(v []*string) *AssumeRoleInput { } // Contains the response to a successful AssumeRole request, including temporary -// AWS credentials that can be used to make AWS requests. +// Amazon Web Services credentials that can be used to make Amazon Web Services +// requests. type AssumeRoleOutput struct { _ struct{} `type:"structure"` @@ -1749,11 +1772,11 @@ type AssumeRoleOutput struct { // // You can require users to specify a source identity when they assume a role. // You do this by using the sts:SourceIdentity condition key in a role trust - // policy. You can use source identity information in AWS CloudTrail logs to - // determine who took actions with a role. You can use the aws:SourceIdentity - // condition key to further control access to AWS resources based on the value - // of source identity. For more information about using source identity, see - // Monitor and control actions taken with assumed roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html) + // policy. You can use source identity information in CloudTrail logs to determine + // who took actions with a role. You can use the aws:SourceIdentity condition + // key to further control access to Amazon Web Services resources based on the + // value of source identity. For more information about using source identity, + // see Monitor and control actions taken with assumed roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html) // in the IAM User Guide. // // The regex used to validate this parameter is a string of characters consisting @@ -1819,7 +1842,7 @@ type AssumeRoleWithSAMLInput struct { // to the federation endpoint for a console sign-in token takes a SessionDuration // parameter that specifies the maximum length of the console session. For more // information, see Creating a URL that Enables Federated Users to Access the - // AWS Management Console (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) + // Management Console (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) // in the IAM User Guide. DurationSeconds *int64 `min:"900" type:"integer"` @@ -1828,10 +1851,11 @@ type AssumeRoleWithSAMLInput struct { // This parameter is optional. Passing policies to this operation returns new // temporary credentials. The resulting session's permissions are the intersection // of the role's identity-based policy and the session policies. You can use - // the role's temporary credentials in subsequent AWS API calls to access resources - // in the account that owns the role. You cannot use session policies to grant - // more permissions than those allowed by the identity-based policy of the role - // that is being assumed. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) + // the role's temporary credentials in subsequent Amazon Web Services API calls + // to access resources in the account that owns the role. You cannot use session + // policies to grant more permissions than those allowed by the identity-based + // policy of the role that is being assumed. For more information, see Session + // Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // in the IAM User Guide. // // The plaintext that you use for both inline and managed session policies can't @@ -1840,11 +1864,11 @@ type AssumeRoleWithSAMLInput struct { // \u00FF). It can also include the tab (\u0009), linefeed (\u000A), and carriage // return (\u000D) characters. // - // An AWS conversion compresses the passed session policies and session tags - // into a packed binary format that has a separate limit. Your request can fail - // for this limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags - // for your request are to the upper size limit. + // An Amazon Web Services conversion compresses the passed session policies + // and session tags into a packed binary format that has a separate limit. Your + // request can fail for this limit even if your plaintext meets the other requirements. + // The PackedPolicySize response element indicates by percentage how close the + // policies and tags for your request are to the upper size limit. Policy *string `min:"1" type:"string"` // The Amazon Resource Names (ARNs) of the IAM managed policies that you want @@ -1854,22 +1878,22 @@ type AssumeRoleWithSAMLInput struct { // This parameter is optional. You can provide up to 10 managed policy ARNs. // However, the plaintext that you use for both inline and managed session policies // can't exceed 2,048 characters. For more information about ARNs, see Amazon - // Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // in the AWS General Reference. + // Resource Names (ARNs) and Amazon Web Services Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) + // in the Amazon Web Services General Reference. // - // An AWS conversion compresses the passed session policies and session tags - // into a packed binary format that has a separate limit. Your request can fail - // for this limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags - // for your request are to the upper size limit. + // An Amazon Web Services conversion compresses the passed session policies + // and session tags into a packed binary format that has a separate limit. Your + // request can fail for this limit even if your plaintext meets the other requirements. + // The PackedPolicySize response element indicates by percentage how close the + // policies and tags for your request are to the upper size limit. // // Passing policies to this operation returns new temporary credentials. The // resulting session's permissions are the intersection of the role's identity-based // policy and the session policies. You can use the role's temporary credentials - // in subsequent AWS API calls to access resources in the account that owns - // the role. You cannot use session policies to grant more permissions than - // those allowed by the identity-based policy of the role that is being assumed. - // For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) + // in subsequent Amazon Web Services API calls to access resources in the account + // that owns the role. You cannot use session policies to grant more permissions + // than those allowed by the identity-based policy of the role that is being + // assumed. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // in the IAM User Guide. PolicyArns []*PolicyDescriptorType `type:"list"` @@ -1984,7 +2008,8 @@ func (s *AssumeRoleWithSAMLInput) SetSAMLAssertion(v string) *AssumeRoleWithSAML } // Contains the response to a successful AssumeRoleWithSAML request, including -// temporary AWS credentials that can be used to make AWS requests. +// temporary Amazon Web Services credentials that can be used to make Amazon +// Web Services requests. type AssumeRoleWithSAMLOutput struct { _ struct{} `type:"structure"` @@ -2010,7 +2035,7 @@ type AssumeRoleWithSAMLOutput struct { // // * The Issuer response value. // - // * The AWS account ID. + // * The Amazon Web Services account ID. // // * The friendly name (the last part of the ARN) of the SAML provider in // IAM. @@ -2148,7 +2173,7 @@ type AssumeRoleWithWebIdentityInput struct { // to the federation endpoint for a console sign-in token takes a SessionDuration // parameter that specifies the maximum length of the console session. For more // information, see Creating a URL that Enables Federated Users to Access the - // AWS Management Console (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) + // Management Console (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) // in the IAM User Guide. DurationSeconds *int64 `min:"900" type:"integer"` @@ -2157,10 +2182,11 @@ type AssumeRoleWithWebIdentityInput struct { // This parameter is optional. Passing policies to this operation returns new // temporary credentials. The resulting session's permissions are the intersection // of the role's identity-based policy and the session policies. You can use - // the role's temporary credentials in subsequent AWS API calls to access resources - // in the account that owns the role. You cannot use session policies to grant - // more permissions than those allowed by the identity-based policy of the role - // that is being assumed. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) + // the role's temporary credentials in subsequent Amazon Web Services API calls + // to access resources in the account that owns the role. You cannot use session + // policies to grant more permissions than those allowed by the identity-based + // policy of the role that is being assumed. For more information, see Session + // Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // in the IAM User Guide. // // The plaintext that you use for both inline and managed session policies can't @@ -2169,11 +2195,11 @@ type AssumeRoleWithWebIdentityInput struct { // \u00FF). It can also include the tab (\u0009), linefeed (\u000A), and carriage // return (\u000D) characters. // - // An AWS conversion compresses the passed session policies and session tags - // into a packed binary format that has a separate limit. Your request can fail - // for this limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags - // for your request are to the upper size limit. + // An Amazon Web Services conversion compresses the passed session policies + // and session tags into a packed binary format that has a separate limit. Your + // request can fail for this limit even if your plaintext meets the other requirements. + // The PackedPolicySize response element indicates by percentage how close the + // policies and tags for your request are to the upper size limit. Policy *string `min:"1" type:"string"` // The Amazon Resource Names (ARNs) of the IAM managed policies that you want @@ -2183,22 +2209,22 @@ type AssumeRoleWithWebIdentityInput struct { // This parameter is optional. You can provide up to 10 managed policy ARNs. // However, the plaintext that you use for both inline and managed session policies // can't exceed 2,048 characters. For more information about ARNs, see Amazon - // Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // in the AWS General Reference. + // Resource Names (ARNs) and Amazon Web Services Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) + // in the Amazon Web Services General Reference. // - // An AWS conversion compresses the passed session policies and session tags - // into a packed binary format that has a separate limit. Your request can fail - // for this limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags - // for your request are to the upper size limit. + // An Amazon Web Services conversion compresses the passed session policies + // and session tags into a packed binary format that has a separate limit. Your + // request can fail for this limit even if your plaintext meets the other requirements. + // The PackedPolicySize response element indicates by percentage how close the + // policies and tags for your request are to the upper size limit. // // Passing policies to this operation returns new temporary credentials. The // resulting session's permissions are the intersection of the role's identity-based // policy and the session policies. You can use the role's temporary credentials - // in subsequent AWS API calls to access resources in the account that owns - // the role. You cannot use session policies to grant more permissions than - // those allowed by the identity-based policy of the role that is being assumed. - // For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) + // in subsequent Amazon Web Services API calls to access resources in the account + // that owns the role. You cannot use session policies to grant more permissions + // than those allowed by the identity-based policy of the role that is being + // assumed. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) // in the IAM User Guide. PolicyArns []*PolicyDescriptorType `type:"list"` @@ -2338,7 +2364,8 @@ func (s *AssumeRoleWithWebIdentityInput) SetWebIdentityToken(v string) *AssumeRo } // Contains the response to a successful AssumeRoleWithWebIdentity request, -// including temporary AWS credentials that can be used to make AWS requests. +// including temporary Amazon Web Services credentials that can be used to make +// Amazon Web Services requests. type AssumeRoleWithWebIdentityOutput struct { _ struct{} `type:"structure"` @@ -2471,8 +2498,8 @@ type AssumedRoleUser struct { Arn *string `min:"20" type:"string" required:"true"` // A unique identifier that contains the role ID and the role session name of - // the role that is being assumed. The role ID is generated by AWS when the - // role is created. + // the role that is being assumed. The role ID is generated by Amazon Web Services + // when the role is created. // // AssumedRoleId is a required field AssumedRoleId *string `min:"2" type:"string" required:"true"` @@ -2500,7 +2527,7 @@ func (s *AssumedRoleUser) SetAssumedRoleId(v string) *AssumedRoleUser { return s } -// AWS credentials for API authentication. +// Amazon Web Services credentials for API authentication. type Credentials struct { _ struct{} `type:"structure"` @@ -2601,8 +2628,8 @@ func (s *DecodeAuthorizationMessageInput) SetEncodedMessage(v string) *DecodeAut } // A document that contains additional information about the authorization status -// of a request from an encoded message that is returned in response to an AWS -// request. +// of a request from an encoded message that is returned in response to an Amazon +// Web Services request. type DecodeAuthorizationMessageOutput struct { _ struct{} `type:"structure"` @@ -2714,7 +2741,7 @@ func (s *GetAccessKeyInfoInput) SetAccessKeyId(v string) *GetAccessKeyInfoInput type GetAccessKeyInfoOutput struct { _ struct{} `type:"structure"` - // The number used to identify the AWS account. + // The number used to identify the Amazon Web Services account. Account *string `type:"string"` } @@ -2753,11 +2780,11 @@ func (s GetCallerIdentityInput) GoString() string { type GetCallerIdentityOutput struct { _ struct{} `type:"structure"` - // The AWS account ID number of the account that owns or contains the calling - // entity. + // The Amazon Web Services account ID number of the account that owns or contains + // the calling entity. Account *string `type:"string"` - // The AWS ARN associated with the calling entity. + // The Amazon Web Services ARN associated with the calling entity. Arn *string `min:"20" type:"string"` // The unique identifier of the calling entity. The exact value depends on the @@ -2801,9 +2828,10 @@ type GetFederationTokenInput struct { // The duration, in seconds, that the session should last. Acceptable durations // for federation sessions range from 900 seconds (15 minutes) to 129,600 seconds // (36 hours), with 43,200 seconds (12 hours) as the default. Sessions obtained - // using AWS account root user credentials are restricted to a maximum of 3,600 - // seconds (one hour). If the specified duration is longer than one hour, the - // session obtained by using root user credentials defaults to one hour. + // using Amazon Web Services account root user credentials are restricted to + // a maximum of 3,600 seconds (one hour). If the specified duration is longer + // than one hour, the session obtained by using root user credentials defaults + // to one hour. DurationSeconds *int64 `min:"900" type:"integer"` // The name of the federated user. The name is used as an identifier for the @@ -2848,11 +2876,11 @@ type GetFederationTokenInput struct { // \u00FF). It can also include the tab (\u0009), linefeed (\u000A), and carriage // return (\u000D) characters. // - // An AWS conversion compresses the passed session policies and session tags - // into a packed binary format that has a separate limit. Your request can fail - // for this limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags - // for your request are to the upper size limit. + // An Amazon Web Services conversion compresses the passed session policies + // and session tags into a packed binary format that has a separate limit. Your + // request can fail for this limit even if your plaintext meets the other requirements. + // The PackedPolicySize response element indicates by percentage how close the + // policies and tags for your request are to the upper size limit. Policy *string `min:"1" type:"string"` // The Amazon Resource Names (ARNs) of the IAM managed policies that you want @@ -2865,8 +2893,8 @@ type GetFederationTokenInput struct { // use as managed session policies. The plaintext that you use for both inline // and managed session policies can't exceed 2,048 characters. You can provide // up to 10 managed policy ARNs. For more information about ARNs, see Amazon - // Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // in the AWS General Reference. + // Resource Names (ARNs) and Amazon Web Services Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) + // in the Amazon Web Services General Reference. // // This parameter is optional. However, if you do not pass any session policies, // then the resulting federated user session has no permissions. @@ -2885,11 +2913,11 @@ type GetFederationTokenInput struct { // by the policy. These permissions are granted in addition to the permissions // that are granted by the session policies. // - // An AWS conversion compresses the passed session policies and session tags - // into a packed binary format that has a separate limit. Your request can fail - // for this limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags - // for your request are to the upper size limit. + // An Amazon Web Services conversion compresses the passed session policies + // and session tags into a packed binary format that has a separate limit. Your + // request can fail for this limit even if your plaintext meets the other requirements. + // The PackedPolicySize response element indicates by percentage how close the + // policies and tags for your request are to the upper size limit. PolicyArns []*PolicyDescriptorType `type:"list"` // A list of session tags. Each session tag consists of a key name and an associated @@ -2903,11 +2931,11 @@ type GetFederationTokenInput struct { // Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length) // in the IAM User Guide. // - // An AWS conversion compresses the passed session policies and session tags - // into a packed binary format that has a separate limit. Your request can fail - // for this limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags - // for your request are to the upper size limit. + // An Amazon Web Services conversion compresses the passed session policies + // and session tags into a packed binary format that has a separate limit. Your + // request can fail for this limit even if your plaintext meets the other requirements. + // The PackedPolicySize response element indicates by percentage how close the + // policies and tags for your request are to the upper size limit. // // You can pass a session tag with the same key as a tag that is already attached // to the user you are federating. When you do, session tags override a user @@ -3004,7 +3032,8 @@ func (s *GetFederationTokenInput) SetTags(v []*Tag) *GetFederationTokenInput { } // Contains the response to a successful GetFederationToken request, including -// temporary AWS credentials that can be used to make AWS requests. +// temporary Amazon Web Services credentials that can be used to make Amazon +// Web Services requests. type GetFederationTokenOutput struct { _ struct{} `type:"structure"` @@ -3062,9 +3091,9 @@ type GetSessionTokenInput struct { // The duration, in seconds, that the credentials should remain valid. Acceptable // durations for IAM user sessions range from 900 seconds (15 minutes) to 129,600 // seconds (36 hours), with 43,200 seconds (12 hours) as the default. Sessions - // for AWS account owners are restricted to a maximum of 3,600 seconds (one - // hour). If the duration is longer than one hour, the session for AWS account - // owners defaults to one hour. + // for Amazon Web Services account owners are restricted to a maximum of 3,600 + // seconds (one hour). If the duration is longer than one hour, the session + // for Amazon Web Services account owners defaults to one hour. DurationSeconds *int64 `min:"900" type:"integer"` // The identification number of the MFA device that is associated with the IAM @@ -3072,7 +3101,7 @@ type GetSessionTokenInput struct { // user has a policy that requires MFA authentication. The value is either the // serial number for a hardware device (such as GAHT12345678) or an Amazon Resource // Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user). - // You can find the device for an IAM user by going to the AWS Management Console + // You can find the device for an IAM user by going to the Management Console // and viewing the user's security credentials. // // The regex used to validate this parameter is a string of characters consisting @@ -3139,7 +3168,8 @@ func (s *GetSessionTokenInput) SetTokenCode(v string) *GetSessionTokenInput { } // Contains the response to a successful GetSessionToken request, including -// temporary AWS credentials that can be used to make AWS requests. +// temporary Amazon Web Services credentials that can be used to make Amazon +// Web Services requests. type GetSessionTokenOutput struct { _ struct{} `type:"structure"` @@ -3174,8 +3204,8 @@ type PolicyDescriptorType struct { // The Amazon Resource Name (ARN) of the IAM managed policy to use as a session // policy for the role. For more information about ARNs, see Amazon Resource - // Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // in the AWS General Reference. + // Names (ARNs) and Amazon Web Services Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) + // in the Amazon Web Services General Reference. Arn *string `locationName:"arn" min:"20" type:"string"` } @@ -3210,9 +3240,9 @@ func (s *PolicyDescriptorType) SetArn(v string) *PolicyDescriptorType { // You can pass custom key-value pair attributes when you assume a role or federate // a user. These are called session tags. You can then use the session tags -// to control access to resources. For more information, see Tagging AWS STS -// Sessions (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) -// in the IAM User Guide. +// to control access to resources. For more information, see Tagging STS Sessions +// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) in +// the IAM User Guide. type Tag struct { _ struct{} `type:"structure"` diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go index cb1debbaa45c..2d98d92353a6 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/doc.go @@ -3,11 +3,11 @@ // Package sts provides the client and types for making API // requests to AWS Security Token Service. // -// AWS Security Token Service (STS) enables you to request temporary, limited-privilege -// credentials for AWS Identity and Access Management (IAM) users or for users -// that you authenticate (federated users). This guide provides descriptions -// of the STS API. For more information about using this service, see Temporary -// Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html). +// Security Token Service (STS) enables you to request temporary, limited-privilege +// credentials for Identity and Access Management (IAM) users or for users that +// you authenticate (federated users). This guide provides descriptions of the +// STS API. For more information about using this service, see Temporary Security +// Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html). // // See https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15 for more information on this service. // diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/errors.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/errors.go index a233f542ef29..7897d70c87ae 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/errors.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/service/sts/errors.go @@ -42,8 +42,9 @@ const ( // ErrCodeInvalidIdentityTokenException for service response error code // "InvalidIdentityToken". // - // The web identity token that was passed could not be validated by AWS. Get - // a new identity token from the identity provider and then retry the request. + // The web identity token that was passed could not be validated by Amazon Web + // Services. Get a new identity token from the identity provider and then retry + // the request. ErrCodeInvalidIdentityTokenException = "InvalidIdentityToken" // ErrCodeMalformedPolicyDocumentException for service response error code @@ -57,11 +58,11 @@ const ( // "PackedPolicyTooLarge". // // The request was rejected because the total packed size of the session policies - // and session tags combined was too large. An AWS conversion compresses the - // session policy document, session policy ARNs, and session tags into a packed - // binary format that has a separate limit. The error message indicates by percentage - // how close the policies and tags are to the upper size limit. For more information, - // see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) + // and session tags combined was too large. An Amazon Web Services conversion + // compresses the session policy document, session policy ARNs, and session + // tags into a packed binary format that has a separate limit. The error message + // indicates by percentage how close the policies and tags are to the upper + // size limit. For more information, see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) // in the IAM User Guide. // // You could receive this error even though you meet other defined session policy @@ -76,7 +77,8 @@ const ( // STS is not activated in the requested region for the account that is being // asked to generate credentials. The account administrator must use the IAM // console to activate STS in that region. For more information, see Activating - // and Deactivating AWS STS in an AWS Region (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) + // and Deactivating Amazon Web Services STS in an Amazon Web Services Region + // (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) // in the IAM User Guide. ErrCodeRegionDisabledException = "RegionDisabledException" ) diff --git a/awsproviderlint/vendor/golang.org/x/net/http/httpguts/httplex.go b/awsproviderlint/vendor/golang.org/x/net/http/httpguts/httplex.go index e7de24ee64ef..c79aa73f28bb 100644 --- a/awsproviderlint/vendor/golang.org/x/net/http/httpguts/httplex.go +++ b/awsproviderlint/vendor/golang.org/x/net/http/httpguts/httplex.go @@ -137,11 +137,13 @@ func trimOWS(x string) string { // contains token amongst its comma-separated tokens, ASCII // case-insensitively. func headerValueContainsToken(v string, token string) bool { - v = trimOWS(v) - if comma := strings.IndexByte(v, ','); comma != -1 { - return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token) + for comma := strings.IndexByte(v, ','); comma != -1; comma = strings.IndexByte(v, ',') { + if tokenEqual(trimOWS(v[:comma]), token) { + return true + } + v = v[comma+1:] } - return tokenEqual(v, token) + return tokenEqual(trimOWS(v), token) } // lowerASCII returns the ASCII lowercase version of b. diff --git a/awsproviderlint/vendor/golang.org/x/net/http2/Dockerfile b/awsproviderlint/vendor/golang.org/x/net/http2/Dockerfile index 53fc52579744..8512245952be 100644 --- a/awsproviderlint/vendor/golang.org/x/net/http2/Dockerfile +++ b/awsproviderlint/vendor/golang.org/x/net/http2/Dockerfile @@ -38,7 +38,7 @@ RUN make RUN make install WORKDIR /root -RUN wget http://curl.haxx.se/download/curl-7.45.0.tar.gz +RUN wget https://curl.se/download/curl-7.45.0.tar.gz RUN tar -zxvf curl-7.45.0.tar.gz WORKDIR /root/curl-7.45.0 RUN ./configure --with-ssl --with-nghttp2=/usr/local diff --git a/awsproviderlint/vendor/golang.org/x/net/http2/ascii.go b/awsproviderlint/vendor/golang.org/x/net/http2/ascii.go new file mode 100644 index 000000000000..17caa205869f --- /dev/null +++ b/awsproviderlint/vendor/golang.org/x/net/http2/ascii.go @@ -0,0 +1,53 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import "strings" + +// The HTTP protocols are defined in terms of ASCII, not Unicode. This file +// contains helper functions which may use Unicode-aware functions which would +// otherwise be unsafe and could introduce vulnerabilities if used improperly. + +// asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t +// are equal, ASCII-case-insensitively. +func asciiEqualFold(s, t string) bool { + if len(s) != len(t) { + return false + } + for i := 0; i < len(s); i++ { + if lower(s[i]) != lower(t[i]) { + return false + } + } + return true +} + +// lower returns the ASCII lowercase version of b. +func lower(b byte) byte { + if 'A' <= b && b <= 'Z' { + return b + ('a' - 'A') + } + return b +} + +// isASCIIPrint returns whether s is ASCII and printable according to +// https://tools.ietf.org/html/rfc20#section-4.2. +func isASCIIPrint(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] < ' ' || s[i] > '~' { + return false + } + } + return true +} + +// asciiToLower returns the lowercase version of s if s is ASCII and printable, +// and whether or not it was. +func asciiToLower(s string) (lower string, ok bool) { + if !isASCIIPrint(s) { + return "", false + } + return strings.ToLower(s), true +} diff --git a/awsproviderlint/vendor/golang.org/x/net/http2/client_conn_pool.go b/awsproviderlint/vendor/golang.org/x/net/http2/client_conn_pool.go index 3a67636fe252..652bc11a029b 100644 --- a/awsproviderlint/vendor/golang.org/x/net/http2/client_conn_pool.go +++ b/awsproviderlint/vendor/golang.org/x/net/http2/client_conn_pool.go @@ -7,7 +7,9 @@ package http2 import ( + "context" "crypto/tls" + "errors" "net/http" "sync" ) @@ -78,61 +80,69 @@ func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMis // It gets its own connection. traceGetConn(req, addr) const singleUse = true - cc, err := p.t.dialClientConn(addr, singleUse) + cc, err := p.t.dialClientConn(req.Context(), addr, singleUse) if err != nil { return nil, err } return cc, nil } - p.mu.Lock() - for _, cc := range p.conns[addr] { - if st := cc.idleState(); st.canTakeNewRequest { - if p.shouldTraceGetConn(st) { - traceGetConn(req, addr) + for { + p.mu.Lock() + for _, cc := range p.conns[addr] { + if st := cc.idleState(); st.canTakeNewRequest { + if p.shouldTraceGetConn(st) { + traceGetConn(req, addr) + } + p.mu.Unlock() + return cc, nil } + } + if !dialOnMiss { p.mu.Unlock() - return cc, nil + return nil, ErrNoCachedConn } - } - if !dialOnMiss { + traceGetConn(req, addr) + call := p.getStartDialLocked(req.Context(), addr) p.mu.Unlock() - return nil, ErrNoCachedConn + <-call.done + if shouldRetryDial(call, req) { + continue + } + return call.res, call.err } - traceGetConn(req, addr) - call := p.getStartDialLocked(addr) - p.mu.Unlock() - <-call.done - return call.res, call.err } // dialCall is an in-flight Transport dial call to a host. type dialCall struct { - _ incomparable - p *clientConnPool + _ incomparable + p *clientConnPool + // the context associated with the request + // that created this dialCall + ctx context.Context done chan struct{} // closed when done res *ClientConn // valid after done is closed err error // valid after done is closed } // requires p.mu is held. -func (p *clientConnPool) getStartDialLocked(addr string) *dialCall { +func (p *clientConnPool) getStartDialLocked(ctx context.Context, addr string) *dialCall { if call, ok := p.dialing[addr]; ok { // A dial is already in-flight. Don't start another. return call } - call := &dialCall{p: p, done: make(chan struct{})} + call := &dialCall{p: p, done: make(chan struct{}), ctx: ctx} if p.dialing == nil { p.dialing = make(map[string]*dialCall) } p.dialing[addr] = call - go call.dial(addr) + go call.dial(call.ctx, addr) return call } // run in its own goroutine. -func (c *dialCall) dial(addr string) { +func (c *dialCall) dial(ctx context.Context, addr string) { const singleUse = false // shared conn - c.res, c.err = c.p.t.dialClientConn(addr, singleUse) + c.res, c.err = c.p.t.dialClientConn(ctx, addr, singleUse) close(c.done) c.p.mu.Lock() @@ -276,3 +286,28 @@ type noDialClientConnPool struct{ *clientConnPool } func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) { return p.getClientConn(req, addr, noDialOnMiss) } + +// shouldRetryDial reports whether the current request should +// retry dialing after the call finished unsuccessfully, for example +// if the dial was canceled because of a context cancellation or +// deadline expiry. +func shouldRetryDial(call *dialCall, req *http.Request) bool { + if call.err == nil { + // No error, no need to retry + return false + } + if call.ctx == req.Context() { + // If the call has the same context as the request, the dial + // should not be retried, since any cancellation will have come + // from this request. + return false + } + if !errors.Is(call.err, context.Canceled) && !errors.Is(call.err, context.DeadlineExceeded) { + // If the call error is not because of a context cancellation or a deadline expiry, + // the dial should not be retried. + return false + } + // Only retry if the error is a context cancellation error or deadline expiry + // and the context associated with the call was canceled or expired. + return call.ctx.Err() != nil +} diff --git a/awsproviderlint/vendor/golang.org/x/net/http2/go115.go b/awsproviderlint/vendor/golang.org/x/net/http2/go115.go new file mode 100644 index 000000000000..908af1ab93c5 --- /dev/null +++ b/awsproviderlint/vendor/golang.org/x/net/http2/go115.go @@ -0,0 +1,27 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.15 +// +build go1.15 + +package http2 + +import ( + "context" + "crypto/tls" +) + +// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS +// connection. +func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) { + dialer := &tls.Dialer{ + Config: cfg, + } + cn, err := dialer.DialContext(ctx, network, addr) + if err != nil { + return nil, err + } + tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed + return tlsCn, nil +} diff --git a/awsproviderlint/vendor/golang.org/x/net/http2/headermap.go b/awsproviderlint/vendor/golang.org/x/net/http2/headermap.go index c3ff3fa1c78c..9e12941da4c3 100644 --- a/awsproviderlint/vendor/golang.org/x/net/http2/headermap.go +++ b/awsproviderlint/vendor/golang.org/x/net/http2/headermap.go @@ -6,7 +6,6 @@ package http2 import ( "net/http" - "strings" "sync" ) @@ -79,10 +78,10 @@ func buildCommonHeaderMaps() { } } -func lowerHeader(v string) string { +func lowerHeader(v string) (lower string, ascii bool) { buildCommonHeaderMapsOnce() if s, ok := commonLowerHeader[v]; ok { - return s + return s, true } - return strings.ToLower(v) + return asciiToLower(v) } diff --git a/awsproviderlint/vendor/golang.org/x/net/http2/not_go115.go b/awsproviderlint/vendor/golang.org/x/net/http2/not_go115.go new file mode 100644 index 000000000000..e6c04cf7ac75 --- /dev/null +++ b/awsproviderlint/vendor/golang.org/x/net/http2/not_go115.go @@ -0,0 +1,31 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.15 +// +build !go1.15 + +package http2 + +import ( + "context" + "crypto/tls" +) + +// dialTLSWithContext opens a TLS connection. +func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) { + cn, err := tls.Dial(network, addr, cfg) + if err != nil { + return nil, err + } + if err := cn.Handshake(); err != nil { + return nil, err + } + if cfg.InsecureSkipVerify { + return cn, nil + } + if err := cn.VerifyHostname(cfg.ServerName); err != nil { + return nil, err + } + return cn, nil +} diff --git a/awsproviderlint/vendor/golang.org/x/net/http2/server.go b/awsproviderlint/vendor/golang.org/x/net/http2/server.go index e125bbd2a264..0ccbe9b4c2bf 100644 --- a/awsproviderlint/vendor/golang.org/x/net/http2/server.go +++ b/awsproviderlint/vendor/golang.org/x/net/http2/server.go @@ -231,13 +231,12 @@ func ConfigureServer(s *http.Server, conf *Server) error { if s.TLSConfig == nil { s.TLSConfig = new(tls.Config) - } else if s.TLSConfig.CipherSuites != nil { - // If they already provided a CipherSuite list, return - // an error if it has a bad order or is missing - // ECDHE_RSA_WITH_AES_128_GCM_SHA256 or ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. + } else if s.TLSConfig.CipherSuites != nil && s.TLSConfig.MinVersion < tls.VersionTLS13 { + // If they already provided a TLS 1.0–1.2 CipherSuite list, return an + // error if it is missing ECDHE_RSA_WITH_AES_128_GCM_SHA256 or + // ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. haveRequired := false - sawBad := false - for i, cs := range s.TLSConfig.CipherSuites { + for _, cs := range s.TLSConfig.CipherSuites { switch cs { case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // Alternative MTI cipher to not discourage ECDSA-only servers. @@ -245,14 +244,9 @@ func ConfigureServer(s *http.Server, conf *Server) error { tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: haveRequired = true } - if isBadCipher(cs) { - sawBad = true - } else if sawBad { - return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs) - } } if !haveRequired { - return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).") + return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)") } } @@ -265,16 +259,12 @@ func ConfigureServer(s *http.Server, conf *Server) error { s.TLSConfig.PreferServerCipherSuites = true - haveNPN := false - for _, p := range s.TLSConfig.NextProtos { - if p == NextProtoTLS { - haveNPN = true - break - } - } - if !haveNPN { + if !strSliceContains(s.TLSConfig.NextProtos, NextProtoTLS) { s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, NextProtoTLS) } + if !strSliceContains(s.TLSConfig.NextProtos, "http/1.1") { + s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "http/1.1") + } if s.TLSNextProto == nil { s.TLSNextProto = map[string]func(*http.Server, *tls.Conn, http.Handler){} @@ -2789,8 +2779,12 @@ func (w *responseWriter) Push(target string, opts *http.PushOptions) error { // but PUSH_PROMISE requests cannot have a body. // http://tools.ietf.org/html/rfc7540#section-8.2 // Also disallow Host, since the promised URL must be absolute. - switch strings.ToLower(k) { - case "content-length", "content-encoding", "trailer", "te", "expect", "host": + if asciiEqualFold(k, "content-length") || + asciiEqualFold(k, "content-encoding") || + asciiEqualFold(k, "trailer") || + asciiEqualFold(k, "te") || + asciiEqualFold(k, "expect") || + asciiEqualFold(k, "host") { return fmt.Errorf("promised request headers cannot include %q", k) } } diff --git a/awsproviderlint/vendor/golang.org/x/net/http2/transport.go b/awsproviderlint/vendor/golang.org/x/net/http2/transport.go index 7688d72c3960..b97adff7d0f1 100644 --- a/awsproviderlint/vendor/golang.org/x/net/http2/transport.go +++ b/awsproviderlint/vendor/golang.org/x/net/http2/transport.go @@ -264,9 +264,8 @@ type ClientConn struct { peerMaxHeaderListSize uint64 initialWindowSize uint32 - hbuf bytes.Buffer // HPACK encoder writes into this - henc *hpack.Encoder - freeBuf [][]byte + hbuf bytes.Buffer // HPACK encoder writes into this + henc *hpack.Encoder wmu sync.Mutex // held while writing; acquire AFTER mu if holding both werr error // first write error that has occurred @@ -564,12 +563,12 @@ func canRetryError(err error) bool { return false } -func (t *Transport) dialClientConn(addr string, singleUse bool) (*ClientConn, error) { +func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) { host, _, err := net.SplitHostPort(addr) if err != nil { return nil, err } - tconn, err := t.dialTLS()("tcp", addr, t.newTLSConfig(host)) + tconn, err := t.dialTLS(ctx)("tcp", addr, t.newTLSConfig(host)) if err != nil { return nil, err } @@ -590,34 +589,24 @@ func (t *Transport) newTLSConfig(host string) *tls.Config { return cfg } -func (t *Transport) dialTLS() func(string, string, *tls.Config) (net.Conn, error) { +func (t *Transport) dialTLS(ctx context.Context) func(string, string, *tls.Config) (net.Conn, error) { if t.DialTLS != nil { return t.DialTLS } - return t.dialTLSDefault -} - -func (t *Transport) dialTLSDefault(network, addr string, cfg *tls.Config) (net.Conn, error) { - cn, err := tls.Dial(network, addr, cfg) - if err != nil { - return nil, err - } - if err := cn.Handshake(); err != nil { - return nil, err - } - if !cfg.InsecureSkipVerify { - if err := cn.VerifyHostname(cfg.ServerName); err != nil { + return func(network, addr string, cfg *tls.Config) (net.Conn, error) { + tlsCn, err := t.dialTLSWithContext(ctx, network, addr, cfg) + if err != nil { return nil, err } + state := tlsCn.ConnectionState() + if p := state.NegotiatedProtocol; p != NextProtoTLS { + return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, NextProtoTLS) + } + if !state.NegotiatedProtocolIsMutual { + return nil, errors.New("http2: could not negotiate protocol mutually") + } + return tlsCn, nil } - state := cn.ConnectionState() - if p := state.NegotiatedProtocol; p != NextProtoTLS { - return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, NextProtoTLS) - } - if !state.NegotiatedProtocolIsMutual { - return nil, errors.New("http2: could not negotiate protocol mutually") - } - return cn, nil } // disableKeepAlives reports whether connections should be closed as @@ -923,46 +912,6 @@ func (cc *ClientConn) closeForLostPing() error { return cc.closeForError(err) } -const maxAllocFrameSize = 512 << 10 - -// frameBuffer returns a scratch buffer suitable for writing DATA frames. -// They're capped at the min of the peer's max frame size or 512KB -// (kinda arbitrarily), but definitely capped so we don't allocate 4GB -// bufers. -func (cc *ClientConn) frameScratchBuffer() []byte { - cc.mu.Lock() - size := cc.maxFrameSize - if size > maxAllocFrameSize { - size = maxAllocFrameSize - } - for i, buf := range cc.freeBuf { - if len(buf) >= int(size) { - cc.freeBuf[i] = nil - cc.mu.Unlock() - return buf[:size] - } - } - cc.mu.Unlock() - return make([]byte, size) -} - -func (cc *ClientConn) putFrameScratchBuffer(buf []byte) { - cc.mu.Lock() - defer cc.mu.Unlock() - const maxBufs = 4 // arbitrary; 4 concurrent requests per conn? investigate. - if len(cc.freeBuf) < maxBufs { - cc.freeBuf = append(cc.freeBuf, buf) - return - } - for i, old := range cc.freeBuf { - if old == nil { - cc.freeBuf[i] = buf - return - } - } - // forget about it. -} - // errRequestCanceled is a copy of net/http's errRequestCanceled because it's not // exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests. var errRequestCanceled = errors.New("net/http: request canceled") @@ -1005,7 +954,7 @@ func checkConnHeaders(req *http.Request) error { if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") { return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv) } - if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !strings.EqualFold(vv[0], "close") && !strings.EqualFold(vv[0], "keep-alive")) { + if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !asciiEqualFold(vv[0], "close") && !asciiEqualFold(vv[0], "keep-alive")) { return fmt.Errorf("http2: invalid Connection request header: %q", vv) } return nil @@ -1305,11 +1254,35 @@ var ( errReqBodyTooLong = errors.New("http2: request body larger than specified content length") ) +// frameScratchBufferLen returns the length of a buffer to use for +// outgoing request bodies to read/write to/from. +// +// It returns max(1, min(peer's advertised max frame size, +// Request.ContentLength+1, 512KB)). +func (cs *clientStream) frameScratchBufferLen(maxFrameSize int) int { + const max = 512 << 10 + n := int64(maxFrameSize) + if n > max { + n = max + } + if cl := actualContentLength(cs.req); cl != -1 && cl+1 < n { + // Add an extra byte past the declared content-length to + // give the caller's Request.Body io.Reader a chance to + // give us more bytes than they declared, so we can catch it + // early. + n = cl + 1 + } + if n < 1 { + return 1 + } + return int(n) // doesn't truncate; max is 512K +} + +var bufPool sync.Pool // of *[]byte + func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (err error) { cc := cs.cc sentEnd := false // whether we sent the final DATA frame w/ END_STREAM - buf := cc.frameScratchBuffer() - defer cc.putFrameScratchBuffer(buf) defer func() { traceWroteRequest(cs.trace, err) @@ -1328,9 +1301,24 @@ func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) ( remainLen := actualContentLength(req) hasContentLen := remainLen != -1 + cc.mu.Lock() + maxFrameSize := int(cc.maxFrameSize) + cc.mu.Unlock() + + // Scratch buffer for reading into & writing from. + scratchLen := cs.frameScratchBufferLen(maxFrameSize) + var buf []byte + if bp, ok := bufPool.Get().(*[]byte); ok && len(*bp) >= scratchLen { + defer bufPool.Put(bp) + buf = *bp + } else { + buf = make([]byte, scratchLen) + defer bufPool.Put(&buf) + } + var sawEOF bool for !sawEOF { - n, err := body.Read(buf[:len(buf)-1]) + n, err := body.Read(buf[:len(buf)]) if hasContentLen { remainLen -= int64(n) if remainLen == 0 && err == nil { @@ -1341,8 +1329,9 @@ func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) ( // to send the END_STREAM bit early, double-check that we're actually // at EOF. Subsequent reads should return (0, EOF) at this point. // If either value is different, we return an error in one of two ways below. + var scratch [1]byte var n1 int - n1, err = body.Read(buf[n:]) + n1, err = body.Read(scratch[:]) remainLen -= int64(n1) } if remainLen < 0 { @@ -1412,10 +1401,6 @@ func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) ( } } - cc.mu.Lock() - maxFrameSize := int(cc.maxFrameSize) - cc.mu.Unlock() - cc.wmu.Lock() defer cc.wmu.Unlock() @@ -1531,19 +1516,21 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail var didUA bool for k, vv := range req.Header { - if strings.EqualFold(k, "host") || strings.EqualFold(k, "content-length") { + if asciiEqualFold(k, "host") || asciiEqualFold(k, "content-length") { // Host is :authority, already sent. // Content-Length is automatic, set below. continue - } else if strings.EqualFold(k, "connection") || strings.EqualFold(k, "proxy-connection") || - strings.EqualFold(k, "transfer-encoding") || strings.EqualFold(k, "upgrade") || - strings.EqualFold(k, "keep-alive") { + } else if asciiEqualFold(k, "connection") || + asciiEqualFold(k, "proxy-connection") || + asciiEqualFold(k, "transfer-encoding") || + asciiEqualFold(k, "upgrade") || + asciiEqualFold(k, "keep-alive") { // Per 8.1.2.2 Connection-Specific Header // Fields, don't send connection-specific // fields. We have already checked if any // are error-worthy so just ignore the rest. continue - } else if strings.EqualFold(k, "user-agent") { + } else if asciiEqualFold(k, "user-agent") { // Match Go's http1 behavior: at most one // User-Agent. If set to nil or empty string, // then omit it. Otherwise if not mentioned, @@ -1556,7 +1543,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail if vv[0] == "" { continue } - } else if strings.EqualFold(k, "cookie") { + } else if asciiEqualFold(k, "cookie") { // Per 8.1.2.5 To allow for better compression efficiency, the // Cookie header field MAY be split into separate header fields, // each with one or more cookie-pairs. @@ -1615,7 +1602,12 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail // Header list size is ok. Write the headers. enumerateHeaders(func(name, value string) { - name = strings.ToLower(name) + name, ascii := asciiToLower(name) + if !ascii { + // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header + // field names have to be ASCII characters (just as in HTTP/1.x). + return + } cc.writeHeader(name, value) if traceHeaders { traceWroteHeaderField(trace, name, value) @@ -1663,9 +1655,14 @@ func (cc *ClientConn) encodeTrailers(req *http.Request) ([]byte, error) { } for k, vv := range req.Trailer { + lowKey, ascii := asciiToLower(k) + if !ascii { + // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header + // field names have to be ASCII characters (just as in HTTP/1.x). + continue + } // Transfer-Encoding, etc.. have already been filtered at the // start of RoundTrip - lowKey := strings.ToLower(k) for _, v := range vv { cc.writeHeader(lowKey, v) } diff --git a/awsproviderlint/vendor/golang.org/x/net/http2/write.go b/awsproviderlint/vendor/golang.org/x/net/http2/write.go index 3849bc2632ef..33f61398a123 100644 --- a/awsproviderlint/vendor/golang.org/x/net/http2/write.go +++ b/awsproviderlint/vendor/golang.org/x/net/http2/write.go @@ -341,7 +341,12 @@ func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) { } for _, k := range keys { vv := h[k] - k = lowerHeader(k) + k, ascii := lowerHeader(k) + if !ascii { + // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header + // field names have to be ASCII characters (just as in HTTP/1.x). + continue + } if !validWireHeaderFieldName(k) { // Skip it as backup paranoia. Per // golang.org/issue/14048, these should diff --git a/awsproviderlint/vendor/golang.org/x/net/idna/idna10.0.0.go b/awsproviderlint/vendor/golang.org/x/net/idna/idna10.0.0.go index 7e69ee1b22ed..5208ba6cb884 100644 --- a/awsproviderlint/vendor/golang.org/x/net/idna/idna10.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/net/idna/idna10.0.0.go @@ -67,15 +67,14 @@ func Transitional(transitional bool) Option { // VerifyDNSLength sets whether a Profile should fail if any of the IDN parts // are longer than allowed by the RFC. +// +// This option corresponds to the VerifyDnsLength flag in UTS #46. func VerifyDNSLength(verify bool) Option { return func(o *options) { o.verifyDNSLength = verify } } // RemoveLeadingDots removes leading label separators. Leading runes that map to // dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well. -// -// This is the behavior suggested by the UTS #46 and is adopted by some -// browsers. func RemoveLeadingDots(remove bool) Option { return func(o *options) { o.removeLeadingDots = remove } } @@ -83,6 +82,8 @@ func RemoveLeadingDots(remove bool) Option { // ValidateLabels sets whether to check the mandatory label validation criteria // as defined in Section 5.4 of RFC 5891. This includes testing for correct use // of hyphens ('-'), normalization, validity of runes, and the context rules. +// In particular, ValidateLabels also sets the CheckHyphens and CheckJoiners flags +// in UTS #46. func ValidateLabels(enable bool) Option { return func(o *options) { // Don't override existing mappings, but set one that at least checks @@ -91,25 +92,48 @@ func ValidateLabels(enable bool) Option { o.mapping = normalize } o.trie = trie - o.validateLabels = enable - o.fromPuny = validateFromPunycode + o.checkJoiners = enable + o.checkHyphens = enable + if enable { + o.fromPuny = validateFromPunycode + } else { + o.fromPuny = nil + } + } +} + +// CheckHyphens sets whether to check for correct use of hyphens ('-') in +// labels. Most web browsers do not have this option set, since labels such as +// "r3---sn-apo3qvuoxuxbt-j5pe" are in common use. +// +// This option corresponds to the CheckHyphens flag in UTS #46. +func CheckHyphens(enable bool) Option { + return func(o *options) { o.checkHyphens = enable } +} + +// CheckJoiners sets whether to check the ContextJ rules as defined in Appendix +// A of RFC 5892, concerning the use of joiner runes. +// +// This option corresponds to the CheckJoiners flag in UTS #46. +func CheckJoiners(enable bool) Option { + return func(o *options) { + o.trie = trie + o.checkJoiners = enable } } // StrictDomainName limits the set of permissible ASCII characters to those // allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the -// hyphen). This is set by default for MapForLookup and ValidateForRegistration. +// hyphen). This is set by default for MapForLookup and ValidateForRegistration, +// but is only useful if ValidateLabels is set. // // This option is useful, for instance, for browsers that allow characters // outside this range, for example a '_' (U+005F LOW LINE). See -// http://www.rfc-editor.org/std/std3.txt for more details This option -// corresponds to the UseSTD3ASCIIRules option in UTS #46. +// http://www.rfc-editor.org/std/std3.txt for more details. +// +// This option corresponds to the UseSTD3ASCIIRules flag in UTS #46. func StrictDomainName(use bool) Option { - return func(o *options) { - o.trie = trie - o.useSTD3Rules = use - o.fromPuny = validateFromPunycode - } + return func(o *options) { o.useSTD3Rules = use } } // NOTE: the following options pull in tables. The tables should not be linked @@ -117,6 +141,8 @@ func StrictDomainName(use bool) Option { // BidiRule enables the Bidi rule as defined in RFC 5893. Any application // that relies on proper validation of labels should include this rule. +// +// This option corresponds to the CheckBidi flag in UTS #46. func BidiRule() Option { return func(o *options) { o.bidirule = bidirule.ValidString } } @@ -152,7 +178,8 @@ func MapForLookup() Option { type options struct { transitional bool useSTD3Rules bool - validateLabels bool + checkHyphens bool + checkJoiners bool verifyDNSLength bool removeLeadingDots bool @@ -225,8 +252,11 @@ func (p *Profile) String() string { if p.useSTD3Rules { s += ":UseSTD3Rules" } - if p.validateLabels { - s += ":ValidateLabels" + if p.checkHyphens { + s += ":CheckHyphens" + } + if p.checkJoiners { + s += ":CheckJoiners" } if p.verifyDNSLength { s += ":VerifyDNSLength" @@ -254,26 +284,29 @@ var ( punycode = &Profile{} lookup = &Profile{options{ - transitional: true, - useSTD3Rules: true, - validateLabels: true, - trie: trie, - fromPuny: validateFromPunycode, - mapping: validateAndMap, - bidirule: bidirule.ValidString, + transitional: true, + useSTD3Rules: true, + checkHyphens: true, + checkJoiners: true, + trie: trie, + fromPuny: validateFromPunycode, + mapping: validateAndMap, + bidirule: bidirule.ValidString, }} display = &Profile{options{ - useSTD3Rules: true, - validateLabels: true, - trie: trie, - fromPuny: validateFromPunycode, - mapping: validateAndMap, - bidirule: bidirule.ValidString, + useSTD3Rules: true, + checkHyphens: true, + checkJoiners: true, + trie: trie, + fromPuny: validateFromPunycode, + mapping: validateAndMap, + bidirule: bidirule.ValidString, }} registration = &Profile{options{ useSTD3Rules: true, - validateLabels: true, verifyDNSLength: true, + checkHyphens: true, + checkJoiners: true, trie: trie, fromPuny: validateFromPunycode, mapping: validateRegistration, @@ -340,7 +373,7 @@ func (p *Profile) process(s string, toASCII bool) (string, error) { } isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight labels.set(u) - if err == nil && p.validateLabels { + if err == nil && p.fromPuny != nil { err = p.fromPuny(p, u) } if err == nil { @@ -681,16 +714,18 @@ func (p *Profile) validateLabel(s string) (err error) { } return nil } - if !p.validateLabels { - return nil - } - trie := p.trie // p.validateLabels is only set if trie is set. - if len(s) > 4 && s[2] == '-' && s[3] == '-' { - return &labelError{s, "V2"} + if p.checkHyphens { + if len(s) > 4 && s[2] == '-' && s[3] == '-' { + return &labelError{s, "V2"} + } + if s[0] == '-' || s[len(s)-1] == '-' { + return &labelError{s, "V3"} + } } - if s[0] == '-' || s[len(s)-1] == '-' { - return &labelError{s, "V3"} + if !p.checkJoiners { + return nil } + trie := p.trie // p.checkJoiners is only set if trie is set. // TODO: merge the use of this in the trie. v, sz := trie.lookupString(s) x := info(v) diff --git a/awsproviderlint/vendor/golang.org/x/net/idna/idna9.0.0.go b/awsproviderlint/vendor/golang.org/x/net/idna/idna9.0.0.go index 7c7456374c13..55f718f12744 100644 --- a/awsproviderlint/vendor/golang.org/x/net/idna/idna9.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/net/idna/idna9.0.0.go @@ -66,15 +66,14 @@ func Transitional(transitional bool) Option { // VerifyDNSLength sets whether a Profile should fail if any of the IDN parts // are longer than allowed by the RFC. +// +// This option corresponds to the VerifyDnsLength flag in UTS #46. func VerifyDNSLength(verify bool) Option { return func(o *options) { o.verifyDNSLength = verify } } // RemoveLeadingDots removes leading label separators. Leading runes that map to // dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well. -// -// This is the behavior suggested by the UTS #46 and is adopted by some -// browsers. func RemoveLeadingDots(remove bool) Option { return func(o *options) { o.removeLeadingDots = remove } } @@ -82,6 +81,8 @@ func RemoveLeadingDots(remove bool) Option { // ValidateLabels sets whether to check the mandatory label validation criteria // as defined in Section 5.4 of RFC 5891. This includes testing for correct use // of hyphens ('-'), normalization, validity of runes, and the context rules. +// In particular, ValidateLabels also sets the CheckHyphens and CheckJoiners flags +// in UTS #46. func ValidateLabels(enable bool) Option { return func(o *options) { // Don't override existing mappings, but set one that at least checks @@ -90,25 +91,48 @@ func ValidateLabels(enable bool) Option { o.mapping = normalize } o.trie = trie - o.validateLabels = enable - o.fromPuny = validateFromPunycode + o.checkJoiners = enable + o.checkHyphens = enable + if enable { + o.fromPuny = validateFromPunycode + } else { + o.fromPuny = nil + } + } +} + +// CheckHyphens sets whether to check for correct use of hyphens ('-') in +// labels. Most web browsers do not have this option set, since labels such as +// "r3---sn-apo3qvuoxuxbt-j5pe" are in common use. +// +// This option corresponds to the CheckHyphens flag in UTS #46. +func CheckHyphens(enable bool) Option { + return func(o *options) { o.checkHyphens = enable } +} + +// CheckJoiners sets whether to check the ContextJ rules as defined in Appendix +// A of RFC 5892, concerning the use of joiner runes. +// +// This option corresponds to the CheckJoiners flag in UTS #46. +func CheckJoiners(enable bool) Option { + return func(o *options) { + o.trie = trie + o.checkJoiners = enable } } // StrictDomainName limits the set of permissable ASCII characters to those // allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the -// hyphen). This is set by default for MapForLookup and ValidateForRegistration. +// hyphen). This is set by default for MapForLookup and ValidateForRegistration, +// but is only useful if ValidateLabels is set. // // This option is useful, for instance, for browsers that allow characters // outside this range, for example a '_' (U+005F LOW LINE). See -// http://www.rfc-editor.org/std/std3.txt for more details This option -// corresponds to the UseSTD3ASCIIRules option in UTS #46. +// http://www.rfc-editor.org/std/std3.txt for more details. +// +// This option corresponds to the UseSTD3ASCIIRules flag in UTS #46. func StrictDomainName(use bool) Option { - return func(o *options) { - o.trie = trie - o.useSTD3Rules = use - o.fromPuny = validateFromPunycode - } + return func(o *options) { o.useSTD3Rules = use } } // NOTE: the following options pull in tables. The tables should not be linked @@ -116,6 +140,8 @@ func StrictDomainName(use bool) Option { // BidiRule enables the Bidi rule as defined in RFC 5893. Any application // that relies on proper validation of labels should include this rule. +// +// This option corresponds to the CheckBidi flag in UTS #46. func BidiRule() Option { return func(o *options) { o.bidirule = bidirule.ValidString } } @@ -152,7 +178,8 @@ func MapForLookup() Option { type options struct { transitional bool useSTD3Rules bool - validateLabels bool + checkHyphens bool + checkJoiners bool verifyDNSLength bool removeLeadingDots bool @@ -225,8 +252,11 @@ func (p *Profile) String() string { if p.useSTD3Rules { s += ":UseSTD3Rules" } - if p.validateLabels { - s += ":ValidateLabels" + if p.checkHyphens { + s += ":CheckHyphens" + } + if p.checkJoiners { + s += ":CheckJoiners" } if p.verifyDNSLength { s += ":VerifyDNSLength" @@ -255,9 +285,10 @@ var ( punycode = &Profile{} lookup = &Profile{options{ transitional: true, - useSTD3Rules: true, - validateLabels: true, removeLeadingDots: true, + useSTD3Rules: true, + checkHyphens: true, + checkJoiners: true, trie: trie, fromPuny: validateFromPunycode, mapping: validateAndMap, @@ -265,8 +296,9 @@ var ( }} display = &Profile{options{ useSTD3Rules: true, - validateLabels: true, removeLeadingDots: true, + checkHyphens: true, + checkJoiners: true, trie: trie, fromPuny: validateFromPunycode, mapping: validateAndMap, @@ -274,8 +306,9 @@ var ( }} registration = &Profile{options{ useSTD3Rules: true, - validateLabels: true, verifyDNSLength: true, + checkHyphens: true, + checkJoiners: true, trie: trie, fromPuny: validateFromPunycode, mapping: validateRegistration, @@ -339,7 +372,7 @@ func (p *Profile) process(s string, toASCII bool) (string, error) { continue } labels.set(u) - if err == nil && p.validateLabels { + if err == nil && p.fromPuny != nil { err = p.fromPuny(p, u) } if err == nil { @@ -629,16 +662,18 @@ func (p *Profile) validateLabel(s string) error { if p.bidirule != nil && !p.bidirule(s) { return &labelError{s, "B"} } - if !p.validateLabels { - return nil - } - trie := p.trie // p.validateLabels is only set if trie is set. - if len(s) > 4 && s[2] == '-' && s[3] == '-' { - return &labelError{s, "V2"} + if p.checkHyphens { + if len(s) > 4 && s[2] == '-' && s[3] == '-' { + return &labelError{s, "V2"} + } + if s[0] == '-' || s[len(s)-1] == '-' { + return &labelError{s, "V3"} + } } - if s[0] == '-' || s[len(s)-1] == '-' { - return &labelError{s, "V3"} + if !p.checkJoiners { + return nil } + trie := p.trie // p.checkJoiners is only set if trie is set. // TODO: merge the use of this in the trie. v, sz := trie.lookupString(s) x := info(v) diff --git a/awsproviderlint/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go b/awsproviderlint/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go index e4c62289f90d..8a7392c4a162 100644 --- a/awsproviderlint/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.10 // +build go1.10 package bidirule diff --git a/awsproviderlint/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go b/awsproviderlint/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go index 02b9e1e9d4c2..bb0a920018c8 100644 --- a/awsproviderlint/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.10 // +build !go1.10 package bidirule diff --git a/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go b/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go index d8c94e1bd1a6..42fa8d72cec0 100644 --- a/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go @@ -1,5 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. +//go:build go1.10 && !go1.13 // +build go1.10,!go1.13 package bidi diff --git a/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go b/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go index 16b11db53883..56a0e1ea2165 100644 --- a/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go @@ -1,5 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. +//go:build go1.13 && !go1.14 // +build go1.13,!go1.14 package bidi diff --git a/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go b/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go index 647f2d4279e6..baacf32b43c3 100644 --- a/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go @@ -1,5 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. +//go:build go1.14 && !go1.16 // +build go1.14,!go1.16 package bidi diff --git a/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go b/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go index c937d0976feb..f248effae17b 100644 --- a/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go @@ -1,5 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. +//go:build go1.16 // +build go1.16 package bidi diff --git a/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go b/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go index 0ca0193ebe2d..f517fdb202a5 100644 --- a/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go @@ -1,5 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. +//go:build !go1.10 // +build !go1.10 package bidi diff --git a/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go b/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go index 26fbd55a1243..f5a0788277ff 100644 --- a/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go @@ -1,5 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. +//go:build go1.10 && !go1.13 // +build go1.10,!go1.13 package norm diff --git a/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go b/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go index 2c58f09baa49..cb7239c4377d 100644 --- a/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go @@ -1,5 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. +//go:build go1.13 && !go1.14 // +build go1.13,!go1.14 package norm diff --git a/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go b/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go index 7e1ae096e5c0..11b27330017d 100644 --- a/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go @@ -1,5 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. +//go:build go1.14 && !go1.16 // +build go1.14,!go1.16 package norm diff --git a/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go b/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go index 9ea1b421407d..96a130d30e9e 100644 --- a/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go @@ -1,5 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. +//go:build go1.16 // +build go1.16 package norm diff --git a/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go b/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go index 942906929135..0175eae50aa6 100644 --- a/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go +++ b/awsproviderlint/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go @@ -1,5 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. +//go:build !go1.10 // +build !go1.10 package norm diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 5af0bac157a4..87f7b43fbb1c 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.39.0 +# github.com/aws/aws-sdk-go v1.39.2 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn @@ -390,7 +390,7 @@ golang.org/x/lint/golint # golang.org/x/mod v0.3.0 golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/net v0.0.0-20210326060303-6b1517762897 +# golang.org/x/net v0.0.0-20210614182718-04defd469f4e golang.org/x/net/context golang.org/x/net/context/ctxhttp golang.org/x/net/http/httpguts @@ -408,7 +408,7 @@ golang.org/x/oauth2/jwt # golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 golang.org/x/sys/internal/unsafeheader golang.org/x/sys/unix -# golang.org/x/text v0.3.5 +# golang.org/x/text v0.3.6 golang.org/x/text/secure/bidirule golang.org/x/text/transform golang.org/x/text/unicode/bidi From 67c0e44e36a7bfc1ae88e970aa9964bc63dc5b00 Mon Sep 17 00:00:00 2001 From: Karri Balk Date: Sat, 5 Jun 2021 20:58:35 +0000 Subject: [PATCH 0997/1208] Ignore RAM OperationNotPermittedException disassocation err --- aws/resource_aws_ram_resource_share_accepter.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_ram_resource_share_accepter.go b/aws/resource_aws_ram_resource_share_accepter.go index cb157f6bcc16..dd8594ece24f 100644 --- a/aws/resource_aws_ram_resource_share_accepter.go +++ b/aws/resource_aws_ram_resource_share_accepter.go @@ -207,8 +207,9 @@ func resourceAwsRamResourceShareAccepterDelete(d *schema.ResourceData, meta inte _, err := conn.DisassociateResourceShare(input) - if err != nil { + if err != nil && !tfawserr.ErrCodeEquals(err, ram.ErrCodeOperationNotPermittedException) { return fmt.Errorf("Error leaving RAM resource share: %s", err) + } _, err = waiter.ResourceShareOwnedBySelfDisassociated(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) From 84a231c9cde65b2336aa87deccf2dfc98452a1f0 Mon Sep 17 00:00:00 2001 From: Karri Balk Date: Tue, 8 Jun 2021 03:08:59 +0000 Subject: [PATCH 0998/1208] Add test with shared route53 resource --- ...ce_aws_ram_resource_share_accepter_test.go | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/aws/resource_aws_ram_resource_share_accepter_test.go b/aws/resource_aws_ram_resource_share_accepter_test.go index ee8cc4879370..bfa2b3664ae5 100644 --- a/aws/resource_aws_ram_resource_share_accepter_test.go +++ b/aws/resource_aws_ram_resource_share_accepter_test.go @@ -78,6 +78,45 @@ func TestAccAwsRamResourceShareAccepter_disappears(t *testing.T) { }) } +func TestAccAwsRamResourceShareAccepter_resource_association(t *testing.T) { + var providers []*schema.Provider + resourceName := "aws_ram_resource_share_accepter.test" + principalAssociationResourceName := "aws_ram_principal_association.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ErrorCheck: testAccErrorCheck(t, ram.EndpointsID), + ProviderFactories: testAccProviderFactoriesAlternate(&providers), + CheckDestroy: testAccCheckAwsRamResourceShareAccepterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsRamResourceShareAccepterResourceAssociation(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsRamResourceShareAccepterExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "share_arn", principalAssociationResourceName, "resource_share_arn"), + testAccMatchResourceAttrRegionalARNAccountID(resourceName, "invitation_arn", "ram", `\d{12}`, regexp.MustCompile(fmt.Sprintf("resource-share-invitation/%s$", uuidRegexPattern))), + resource.TestMatchResourceAttr(resourceName, "share_id", regexp.MustCompile(fmt.Sprintf(`^rs-%s$`, uuidRegexPattern))), + resource.TestCheckResourceAttr(resourceName, "status", ram.ResourceShareStatusActive), + testAccCheckResourceAttrAccountID(resourceName, "receiver_account_id"), + resource.TestMatchResourceAttr(resourceName, "sender_account_id", regexp.MustCompile(`\d{12}`)), + resource.TestCheckResourceAttr(resourceName, "share_name", rName), + resource.TestCheckResourceAttr(resourceName, "resources.%", "0"), + ), + }, + { + Config: testAccAwsRamResourceShareAccepterResourceAssociation(rName), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckAwsRamResourceShareAccepterDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ramconn @@ -158,3 +197,27 @@ resource "aws_ram_principal_association" "test" { data "aws_caller_identity" "receiver" {} `, rName) } + +func testAccAwsRamResourceShareAccepterResourceAssociation(rName string) string { + return composeConfig(testAccAwsRamResourceShareAccepterBasic(rName), fmt.Sprintf(` +resource "aws_ram_resource_association" "test" { + provider = "awsalternate" + resource_arn = aws_route53_resolver_query_log_config.test.arn + resource_share_arn = aws_ram_resource_share.test.arn +} + +resource "aws_route53_resolver_query_log_config" "test" { + provider = "awsalternate" + + name = %[1]q + destination_arn = aws_s3_bucket.test.arn +} + +resource "aws_s3_bucket" "test" { + bucket = %[1]q + provider = "awsalternate" + + force_destroy = true +} +`, rName)) +} From e0ad098b087c0c0d74eff259a4cef6d01d427707 Mon Sep 17 00:00:00 2001 From: Karri Balk Date: Tue, 8 Jun 2021 19:37:46 +0000 Subject: [PATCH 0999/1208] Add change log --- .changelog/19718.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19718.txt diff --git a/.changelog/19718.txt b/.changelog/19718.txt new file mode 100644 index 000000000000..b2cf0a1874b6 --- /dev/null +++ b/.changelog/19718.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_ram_resource_share_acceptor: Destroy aws_ram_resource_share_accepter from member account when share contains some resource types +``` From db357b0c598242416dcfffd55c78dc4f84355719 Mon Sep 17 00:00:00 2001 From: Karri Balk Date: Tue, 15 Jun 2021 23:13:19 +0000 Subject: [PATCH 1000/1208] Replace unit test with one that doesn't fail --- ...ce_aws_ram_resource_share_accepter_test.go | 73 ++++++++++++++++--- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_ram_resource_share_accepter_test.go b/aws/resource_aws_ram_resource_share_accepter_test.go index bfa2b3664ae5..89b1cfa0430f 100644 --- a/aws/resource_aws_ram_resource_share_accepter_test.go +++ b/aws/resource_aws_ram_resource_share_accepter_test.go @@ -202,22 +202,77 @@ func testAccAwsRamResourceShareAccepterResourceAssociation(rName string) string return composeConfig(testAccAwsRamResourceShareAccepterBasic(rName), fmt.Sprintf(` resource "aws_ram_resource_association" "test" { provider = "awsalternate" - resource_arn = aws_route53_resolver_query_log_config.test.arn + resource_arn = aws_codebuild_project.test.arn resource_share_arn = aws_ram_resource_share.test.arn } -resource "aws_route53_resolver_query_log_config" "test" { - provider = "awsalternate" +resource "aws_codebuild_project" "test" { + provider = "awsalternate" - name = %[1]q - destination_arn = aws_s3_bucket.test.arn + name = %[1]q + service_role = aws_iam_role.test.arn + + artifacts { + type = "NO_ARTIFACTS" + } + + environment { + compute_type = "BUILD_GENERAL1_SMALL" + image = "2" + type = "LINUX_CONTAINER" + } + + source { + type = "GITHUB" + location = "https://github.com/hashicorp/packer.git" + } } -resource "aws_s3_bucket" "test" { - bucket = %[1]q - provider = "awsalternate" +resource "aws_iam_role" "test" { + provider = "awsalternate" + + name = %[1]q + + assume_role_policy = <<-EOF + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + }, + "Action": "sts:AssumeRole" + } + ] + } + EOF +} + +resource "aws_iam_role_policy" "test" { + provider = "awsalternate" - force_destroy = true + name = %[1]q + role = aws_iam_role.test.name + + policy = <<-POLICY + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Resource": [ + "*" + ], + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ] + } + ] + } + POLICY } `, rName)) } From 70ef0217ddc2bcb06e5b3ef2332cc1569f5014b3 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 09:14:51 -0400 Subject: [PATCH 1001/1208] Update changelog language --- .changelog/19718.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/19718.txt b/.changelog/19718.txt index b2cf0a1874b6..02c0d651b12d 100644 --- a/.changelog/19718.txt +++ b/.changelog/19718.txt @@ -1,3 +1,3 @@ ```release-note:bug -resource/aws_ram_resource_share_acceptor: Destroy aws_ram_resource_share_accepter from member account when share contains some resource types +resource/aws_ram_resource_share_acceptor: Allow destroy even where AWS API provides no way to disassociate ``` From f1e5959cd6ac00c1deeb427f3e898d1eb016641d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 09:15:47 -0400 Subject: [PATCH 1002/1208] r/ram_resource_share_accepter: Delete succeed with one type of error --- aws/resource_aws_ram_resource_share_accepter.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_ram_resource_share_accepter.go b/aws/resource_aws_ram_resource_share_accepter.go index dd8594ece24f..75297d8f6936 100644 --- a/aws/resource_aws_ram_resource_share_accepter.go +++ b/aws/resource_aws_ram_resource_share_accepter.go @@ -207,12 +207,16 @@ func resourceAwsRamResourceShareAccepterDelete(d *schema.ResourceData, meta inte _, err := conn.DisassociateResourceShare(input) + if tfawserr.ErrCodeEquals(err, ram.ErrCodeOperationNotPermittedException) { + log.Printf("[WARN] Resource share could not be disassociated, but continuing: %s", err) + } + if err != nil && !tfawserr.ErrCodeEquals(err, ram.ErrCodeOperationNotPermittedException) { return fmt.Errorf("Error leaving RAM resource share: %s", err) - } _, err = waiter.ResourceShareOwnedBySelfDisassociated(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) + if err != nil { return fmt.Errorf("Error waiting for RAM resource share (%s) state: %s", d.Id(), err) } From 3bd16ce334bdf8341555064505aae86f27fc89d6 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 09:16:27 -0400 Subject: [PATCH 1003/1208] tests/r/ram_resource_share_accepter: Clean up tests --- ...ce_aws_ram_resource_share_accepter_test.go | 68 ++++++++----------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/aws/resource_aws_ram_resource_share_accepter_test.go b/aws/resource_aws_ram_resource_share_accepter_test.go index 89b1cfa0430f..34695af140ef 100644 --- a/aws/resource_aws_ram_resource_share_accepter_test.go +++ b/aws/resource_aws_ram_resource_share_accepter_test.go @@ -78,7 +78,7 @@ func TestAccAwsRamResourceShareAccepter_disappears(t *testing.T) { }) } -func TestAccAwsRamResourceShareAccepter_resource_association(t *testing.T) { +func TestAccAwsRamResourceShareAccepter_resourceAssociation(t *testing.T) { var providers []*schema.Provider resourceName := "aws_ram_resource_share_accepter.test" principalAssociationResourceName := "aws_ram_principal_association.test" @@ -207,7 +207,7 @@ resource "aws_ram_resource_association" "test" { } resource "aws_codebuild_project" "test" { - provider = "awsalternate" + provider = "awsalternate" name = %[1]q service_role = aws_iam_role.test.arn @@ -228,51 +228,43 @@ resource "aws_codebuild_project" "test" { } } +data "aws_partition" "current" {} + resource "aws_iam_role" "test" { provider = "awsalternate" - name = %[1]q - - assume_role_policy = <<-EOF - { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": { - "Service": "codebuild.amazonaws.com" - }, - "Action": "sts:AssumeRole" - } - ] - } - EOF + name = %[1]q + + assume_role_policy = jsonencode({ + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "codebuild.${data.aws_partition.current.dns_suffix}" + } + }] + Version = "2012-10-17" + }) } resource "aws_iam_role_policy" "test" { provider = "awsalternate" - name = %[1]q - role = aws_iam_role.test.name - - policy = <<-POLICY - { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Resource": [ - "*" - ], - "Action": [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents" - ] - } + name = %[1]q + role = aws_iam_role.test.name + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Resource = ["*"] + Action = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" ] - } - POLICY + }] + }) } `, rName)) } From 6265cf54561953d8bff7898be6fdefc62d16ba8d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 09:17:58 -0400 Subject: [PATCH 1004/1208] tests/r/ram_resource_share_accepter: Clean up tests --- aws/resource_aws_ram_resource_share_accepter_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_ram_resource_share_accepter_test.go b/aws/resource_aws_ram_resource_share_accepter_test.go index 34695af140ef..666be5a8c2c3 100644 --- a/aws/resource_aws_ram_resource_share_accepter_test.go +++ b/aws/resource_aws_ram_resource_share_accepter_test.go @@ -201,7 +201,8 @@ data "aws_caller_identity" "receiver" {} func testAccAwsRamResourceShareAccepterResourceAssociation(rName string) string { return composeConfig(testAccAwsRamResourceShareAccepterBasic(rName), fmt.Sprintf(` resource "aws_ram_resource_association" "test" { - provider = "awsalternate" + provider = "awsalternate" + resource_arn = aws_codebuild_project.test.arn resource_share_arn = aws_ram_resource_share.test.arn } From 5f10edcaae4459bb76084eeda4b1a552c650eb0b Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 09:20:04 -0400 Subject: [PATCH 1005/1208] tests/r/ram_resource_share_accepter: Appease linter overlord --- aws/resource_aws_ram_resource_share_accepter_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_ram_resource_share_accepter_test.go b/aws/resource_aws_ram_resource_share_accepter_test.go index 666be5a8c2c3..3b30df4fdbae 100644 --- a/aws/resource_aws_ram_resource_share_accepter_test.go +++ b/aws/resource_aws_ram_resource_share_accepter_test.go @@ -255,14 +255,14 @@ resource "aws_iam_role_policy" "test" { role = aws_iam_role.test.name policy = jsonencode({ - Version = "2012-10-17" + Version = "2012-10-17" Statement = [{ Effect = "Allow" Resource = ["*"] Action = [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents" + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" ] }] }) From cc094523ef5de16c899080a04cb6d9100412dc71 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 10:50:20 -0400 Subject: [PATCH 1006/1208] r/aws_dx_gateway_association_proposal: Ensure that any pseudo-proposal ID is not blank. --- .../service/directconnect/finder/finder.go | 20 +- aws/resource_aws_dx_gateway_association.go | 17 +- ...rce_aws_dx_gateway_association_proposal.go | 310 +++++------------- ...ws_dx_gateway_association_proposal_test.go | 15 +- ...gateway_association_proposal.html.markdown | 1 + 5 files changed, 124 insertions(+), 239 deletions(-) diff --git a/aws/internal/service/directconnect/finder/finder.go b/aws/internal/service/directconnect/finder/finder.go index 9bcf768f73e2..9a97f05d34d1 100644 --- a/aws/internal/service/directconnect/finder/finder.go +++ b/aws/internal/service/directconnect/finder/finder.go @@ -40,16 +40,23 @@ func GatewayAssociation(conn *directconnect.DirectConnect, input *directconnect. // TODO Check for multiple results. // TODO https://github.com/hashicorp/terraform-provider-aws/pull/17613. - gatewayAssociation := output.DirectConnectGatewayAssociations[0] + association := output.DirectConnectGatewayAssociations[0] - if state := aws.StringValue(gatewayAssociation.AssociationState); state == directconnect.GatewayAssociationStateDisassociated { + if state := aws.StringValue(association.AssociationState); state == directconnect.GatewayAssociationStateDisassociated { return nil, &resource.NotFoundError{ Message: state, LastRequest: input, } } - return gatewayAssociation, nil + if association.AssociatedGateway == nil { + return nil, &resource.NotFoundError{ + Message: "Empty AssociatedGateway", + LastRequest: input, + } + } + + return association, nil } func GatewayAssociationProposalByID(conn *directconnect.DirectConnect, id string) (*directconnect.GatewayAssociationProposal, error) { @@ -82,5 +89,12 @@ func GatewayAssociationProposalByID(conn *directconnect.DirectConnect, id string } } + if proposal.AssociatedGateway == nil { + return nil, &resource.NotFoundError{ + Message: "Empty AssociatedGateway", + LastRequest: input, + } + } + return proposal, nil } diff --git a/aws/resource_aws_dx_gateway_association.go b/aws/resource_aws_dx_gateway_association.go index a574640275ee..f9f6ea4d1b5b 100644 --- a/aws/resource_aws_dx_gateway_association.go +++ b/aws/resource_aws_dx_gateway_association.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directconnect" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -233,21 +234,23 @@ func resourceAwsDxGatewayAssociationUpdate(d *schema.ResourceData, meta interfac func resourceAwsDxGatewayAssociationDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).dxconn - associationId := d.Get("dx_gateway_association_id").(string) + associationID := d.Get("dx_gateway_association_id").(string) - log.Printf("[DEBUG] Deleting Direct Connect gateway association: %s", d.Id()) + log.Printf("[DEBUG] Deleting Direct Connect Gateway Association: %s", d.Id()) _, err := conn.DeleteDirectConnectGatewayAssociation(&directconnect.DeleteDirectConnectGatewayAssociationInput{ - AssociationId: aws.String(associationId), + AssociationId: aws.String(associationID), }) - if isAWSErr(err, directconnect.ErrCodeClientException, "No association exists") { + + if tfawserr.ErrMessageContains(err, directconnect.ErrCodeClientException, "does not exist") { return nil } + if err != nil { - return fmt.Errorf("error deleting Direct Connect gateway association: %s", err) + return fmt.Errorf("error deleting Direct Connect Gateway Association (%s): %w", d.Id(), err) } - if err := waitForDirectConnectGatewayAssociationDeletion(conn, associationId, d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("error waiting for Direct Connect gateway association (%s) to be deleted: %s", d.Id(), err) + if err := waitForDirectConnectGatewayAssociationDeletion(conn, associationID, d.Timeout(schema.TimeoutDelete)); err != nil { + return fmt.Errorf("error waiting for Direct Connect Gateway Association (%s) to delete: %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index 6218cde43ea0..b5fc3d409971 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -8,8 +8,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directconnect" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" @@ -29,30 +29,23 @@ func resourceAwsDxGatewayAssociationProposal() *schema.Resource { // Accepting the proposal with overridden prefixes changes the returned RequestedAllowedPrefixesToDirectConnectGateway value (allowed_prefixes attribute). // We only want to force a new resource if this value changes and the current proposal state is "requested". customdiff.ForceNewIf("allowed_prefixes", func(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool { + conn := meta.(*AWSClient).dxconn + + log.Printf("[DEBUG] CustomizeDiff for Direct Connect Gateway Association Proposal (%s) allowed_prefixes", d.Id()) - log.Printf("[DEBUG] Checking diff for Direct Connect Gateway Association Proposal (%s) allowed_prefixes", d.Id()) + output, err := finder.GatewayAssociationProposalByID(conn, d.Id()) - if len(strings.Join(strings.Fields(d.Id()), "")) < 1 { - log.Printf("[WARN] Direct Connect Gateway Association Proposal Id not available (%s)", d.Id()) - log.Printf("[DEBUG] Direct Connect Gateway Association Proposal UpdatedKeys (%s)", strings.Join(d.UpdatedKeys(), "/")) - // assume proposal is end-of-life, rely on Read func to test + if tfresource.NotFound(err) { + // Proposal may be end-of-life and removed by AWS. return false } - conn := meta.(*AWSClient).dxconn - - proposal, err := describeDirectConnectGatewayAssociationProposal(conn, d.Id()) if err != nil { log.Printf("[ERROR] Error reading Direct Connect Gateway Association Proposal (%s): %s", d.Id(), err) return false } - if proposal == nil { - // proposal maybe end-of-life and removed by AWS, existence checked in Read func - return false - } - - return aws.StringValue(proposal.ProposalState) == directconnect.GatewayAssociationProposalStateRequested + return aws.StringValue(output.ProposalState) == directconnect.GatewayAssociationProposalStateRequested }), ), @@ -63,24 +56,29 @@ func resourceAwsDxGatewayAssociationProposal() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "associated_gateway_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "associated_gateway_owner_account_id": { Type: schema.TypeString, Computed: true, }, + "associated_gateway_type": { Type: schema.TypeString, Computed: true, }, + "dx_gateway_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "dx_gateway_owner_account_id": { Type: schema.TypeString, Required: true, @@ -94,19 +92,23 @@ func resourceAwsDxGatewayAssociationProposal() *schema.Resource { func resourceAwsDxGatewayAssociationProposalCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).dxconn - allowedPrefixes := expandDirectConnectGatewayAssociationProposalAllowedPrefixes(d.Get("allowed_prefixes").(*schema.Set).List()) + directConnectGatewayID := d.Get("dx_gateway_id").(string) + associatedGatewayID := d.Get("associated_gateway_id").(string) input := &directconnect.CreateDirectConnectGatewayAssociationProposalInput{ - AddAllowedPrefixesToDirectConnectGateway: allowedPrefixes, - DirectConnectGatewayId: aws.String(d.Get("dx_gateway_id").(string)), - DirectConnectGatewayOwnerAccount: aws.String(d.Get("dx_gateway_owner_account_id").(string)), - GatewayId: aws.String(d.Get("associated_gateway_id").(string)), + DirectConnectGatewayId: aws.String(directConnectGatewayID), + DirectConnectGatewayOwnerAccount: aws.String(d.Get("dx_gateway_owner_account_id").(string)), + GatewayId: aws.String(associatedGatewayID), + } + + if v, ok := d.GetOk("allowed_prefixes"); ok && v.(*schema.Set).Len() > 0 { + input.AddAllowedPrefixesToDirectConnectGateway = expandDirectConnectRouteFilterPrefixes(v.(*schema.Set).List()) } log.Printf("[DEBUG] Creating Direct Connect Gateway Association Proposal: %s", input) output, err := conn.CreateDirectConnectGatewayAssociationProposal(input) if err != nil { - return fmt.Errorf("error creating Direct Connect Gateway Association Proposal: %s", err) + return fmt.Errorf("error creating Direct Connect Gateway Association Proposal (%s/%s): %w", directConnectGatewayID, associatedGatewayID, err) } d.SetId(aws.StringValue(output.DirectConnectGatewayAssociationProposal.ProposalId)) @@ -115,274 +117,142 @@ func resourceAwsDxGatewayAssociationProposalCreate(d *schema.ResourceData, meta } func resourceAwsDxGatewayAssociationProposalRead(d *schema.ResourceData, meta interface{}) error { - log.Printf("[DEBUG] Read Direct Connect Gateway Association Proposal: %s", d.Id()) - - var proposal *directconnect.GatewayAssociationProposal - conn := meta.(*AWSClient).dxconn - trimmedId := strings.Join(strings.Fields(d.Id()), "") - if len(trimmedId) > 0 { - var err error - proposal, err = describeDirectConnectGatewayAssociationProposal(conn, d.Id()) + // First attempt to find by proposal ID. + output, err := finder.GatewayAssociationProposalByID(conn, d.Id()) - if err != nil { - return fmt.Errorf("error reading Direct Connect Gateway Association Proposal (%s): %s", d.Id(), err) - } - } else { - log.Printf("[WARN] Direct Connect Gateway Association Proposal Id not available (%s)", d.Id()) - } - - if proposal == nil || len(trimmedId) < 1 { - log.Printf("[WARN] Direct Connect Gateway Association Proposal (%s) not found, checking for associated gateway", d.Id()) + if tfresource.NotFound(err) { + // Attempt to find an existing association. + directConnectGatewayID := d.Get("dx_gateway_id").(string) + associatedGatewayID := d.Get("associated_gateway_id").(string) - var dxGatewayId string - if rawDGId, ok := d.GetOk("dx_gateway_id"); ok { - dxGatewayId = rawDGId.(string) - } else if rawDGId == nil { - d.SetId("") - return fmt.Errorf("error reading dx_gateway_id (%s) from Proposal state", d.Id()) - } + output, err := finder.GatewayAssociationByDirectConnectGatewayIDAndAssociatedGatewayID(conn, directConnectGatewayID, associatedGatewayID) - var associatedGatewayId string - if rawAGId, ok := d.GetOk("associated_gateway_id"); ok { - associatedGatewayId = rawAGId.(string) - } else if rawAGId == nil { + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Direct Connect Gateway Association Proposal (%s) not found, removing from state", d.Id()) d.SetId("") - return fmt.Errorf("error reading associated_gateway_id (%s) from Proposal state", d.Id()) + return nil } - log.Printf("[DEBUG] looking for Direct Connect Gateway Association using dx_gateway_id (%s) and associated_gateway_id (%s) to validate Proposal state data", dxGatewayId, associatedGatewayId) - assocRaw, state, err := getDxGatewayAssociation(conn, dxGatewayId, associatedGatewayId)() - if err != nil { - d.SetId("") - return fmt.Errorf("error reading Direct Connect gateway association (%s) from Proposal state: %s", d.Id(), err) - } - - if state == gatewayAssociationStateDeleted { - log.Printf("[WARN] Direct Connect gateway association (%s/%s/%s) not found, removing from state", d.Id(), dxGatewayId, associatedGatewayId) - d.SetId("") - return nil + return fmt.Errorf("error reading Direct Connect Gateway Association (%s/%s): %w", directConnectGatewayID, associatedGatewayID, err) } - // once accepted, AWS will delete the proposal after after some time (days?) - // in this case we don't need to create a new proposal, use metadata from the association + // Once accepted, AWS will delete the proposal after after some time (days?). + // In this case we don't need to create a new proposal, use metadata from the association // to artificially populate the missing proposal in state as if it was still there. - log.Printf("[INFO] Direct Connect Gateway Association Proposal (%s) has reached end-of-life and has been removed by AWS.", d.Id()) - assoc := assocRaw.(*directconnect.GatewayAssociation) + log.Printf("[INFO] Direct Connect Gateway Association Proposal (%s) has reached end-of-life and has been removed by AWS", d.Id()) - err = d.Set("allowed_prefixes", flattenDxRouteFilterPrefixes(assoc.AllowedPrefixesToDirectConnectGateway)) - if err != nil { - return fmt.Errorf("error setting allowed_prefixes: %s", err) + if err := d.Set("allowed_prefixes", flattenDirectConnectRouteFilterPrefixes(output.AllowedPrefixesToDirectConnectGateway)); err != nil { + return fmt.Errorf("error setting allowed_prefixes: %w", err) } - d.Set("associated_gateway_id", assoc.AssociatedGateway.Id) - d.Set("dx_gateway_id", assoc.DirectConnectGatewayId) - d.Set("dx_gateway_owner_account_id", assoc.DirectConnectGatewayOwnerAccount) + d.Set("associated_gateway_id", output.AssociatedGateway.Id) + d.Set("associated_gateway_owner_account_id", output.AssociatedGateway.OwnerAccount) + d.Set("associated_gateway_type", output.AssociatedGateway.Type) + d.Set("dx_gateway_id", output.DirectConnectGatewayId) + d.Set("dx_gateway_owner_account_id", output.DirectConnectGatewayOwnerAccount) + } else if err != nil { + return fmt.Errorf("error reading Direct Connect Gateway Association Proposal (%s): %w", d.Id(), err) } else { - log.Printf("[DEBUG] Direct Connect Gateway Association Proposal (%s) found, continuing as normal: %s", d.Id(), proposal.String()) - - if aws.StringValue(proposal.ProposalState) == directconnect.GatewayAssociationProposalStateDeleted { - log.Printf("[WARN] Direct Connect Gateway Association Proposal (%s) deleted, removing from state", d.Id()) - d.SetId("") - return nil + if err := d.Set("allowed_prefixes", flattenDirectConnectRouteFilterPrefixes(output.RequestedAllowedPrefixesToDirectConnectGateway)); err != nil { + return fmt.Errorf("error setting allowed_prefixes: %w", err) } - if proposal.AssociatedGateway == nil { - return fmt.Errorf("error reading Direct Connect Gateway Association Proposal (%s): missing associated gateway information", d.Id()) - } - - if err := d.Set("allowed_prefixes", flattenDirectConnectGatewayAssociationProposalAllowedPrefixes(proposal.RequestedAllowedPrefixesToDirectConnectGateway)); err != nil { - return fmt.Errorf("error setting allowed_prefixes: %s", err) - } - - d.Set("associated_gateway_id", proposal.AssociatedGateway.Id) - d.Set("associated_gateway_owner_account_id", proposal.AssociatedGateway.OwnerAccount) - d.Set("associated_gateway_type", proposal.AssociatedGateway.Type) - d.Set("dx_gateway_id", proposal.DirectConnectGatewayId) - d.Set("dx_gateway_owner_account_id", proposal.DirectConnectGatewayOwnerAccount) - + d.Set("associated_gateway_id", output.AssociatedGateway.Id) + d.Set("associated_gateway_owner_account_id", output.AssociatedGateway.OwnerAccount) + d.Set("associated_gateway_type", output.AssociatedGateway.Type) + d.Set("dx_gateway_id", output.DirectConnectGatewayId) + d.Set("dx_gateway_owner_account_id", output.DirectConnectGatewayOwnerAccount) } + return nil } func resourceAwsDxGatewayAssociationProposalDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).dxconn - input := &directconnect.DeleteDirectConnectGatewayAssociationProposalInput{ - ProposalId: aws.String(d.Id()), - } - log.Printf("[DEBUG] Deleting Direct Connect Gateway Association Proposal: %s", d.Id()) + _, err := conn.DeleteDirectConnectGatewayAssociationProposal(&directconnect.DeleteDirectConnectGatewayAssociationProposalInput{ + ProposalId: aws.String(d.Id()), + }) - _, err := conn.DeleteDirectConnectGatewayAssociationProposal(input) + if tfawserr.ErrMessageContains(err, directconnect.ErrCodeClientException, "is not found") { + return nil + } if err != nil { - return fmt.Errorf("error deleting Direct Connect Gateway Association Proposal (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting Direct Connect Gateway Association Proposal (%s): %w", d.Id(), err) } return nil } -func describeDirectConnectGatewayAssociationProposal(conn *directconnect.DirectConnect, proposalID string) (*directconnect.GatewayAssociationProposal, error) { - input := &directconnect.DescribeDirectConnectGatewayAssociationProposalsInput{ - ProposalId: aws.String(proposalID), +func expandDirectConnectRouteFilterPrefixes(tfList []interface{}) []*directconnect.RouteFilterPrefix { + if len(tfList) == 0 { + return nil } - for { - output, err := conn.DescribeDirectConnectGatewayAssociationProposals(input) + var apiObjects []*directconnect.RouteFilterPrefix - if err != nil { - return nil, err - } + for _, tfStringRaw := range tfList { + tfString, ok := tfStringRaw.(string) - if output == nil { + if !ok { continue } - for _, proposal := range output.DirectConnectGatewayAssociationProposals { - if aws.StringValue(proposal.ProposalId) == proposalID { - return proposal, nil - } + apiObject := &directconnect.RouteFilterPrefix{ + Cidr: aws.String(tfString), } - if aws.StringValue(output.NextToken) == "" { - break - } - - input.NextToken = output.NextToken + apiObjects = append(apiObjects, apiObject) } - return nil, nil + return apiObjects } -func expandDirectConnectGatewayAssociationProposalAllowedPrefixes(allowedPrefixes []interface{}) []*directconnect.RouteFilterPrefix { - if len(allowedPrefixes) == 0 { +func flattenDirectConnectRouteFilterPrefixes(apiObjects []*directconnect.RouteFilterPrefix) []interface{} { + if len(apiObjects) == 0 { return nil } - var routeFilterPrefixes []*directconnect.RouteFilterPrefix + var tfList []interface{} - for _, allowedPrefixRaw := range allowedPrefixes { - if allowedPrefixRaw == nil { + for _, apiObject := range apiObjects { + if apiObject == nil { continue } - routeFilterPrefix := &directconnect.RouteFilterPrefix{ - Cidr: aws.String(allowedPrefixRaw.(string)), - } - - routeFilterPrefixes = append(routeFilterPrefixes, routeFilterPrefix) + tfList = append(tfList, aws.StringValue(apiObject.Cidr)) } - return routeFilterPrefixes -} - -func flattenDirectConnectGatewayAssociationProposalAllowedPrefixes(routeFilterPrefixes []*directconnect.RouteFilterPrefix) []interface{} { - if len(routeFilterPrefixes) == 0 { - return []interface{}{} - } - - var allowedPrefixes []interface{} - - for _, routeFilterPrefix := range routeFilterPrefixes { - if routeFilterPrefix == nil { - continue - } - - allowedPrefix := aws.StringValue(routeFilterPrefix.Cidr) - - allowedPrefixes = append(allowedPrefixes, allowedPrefix) - } - - return allowedPrefixes + return tfList } func resourceAwsDxGatewayAssociationProposalImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - parts := strings.Split(strings.ToLower(d.Id()), "/") - - var proposalID, directConnectGatewayID, associatedGatewayID string - switch n := len(parts); n { + switch parts := strings.Split(strings.ToLower(d.Id()), "/"); len(parts) { case 1: - return []*schema.ResourceData{d}, nil + break case 3: - proposalID = parts[0] - directConnectGatewayID = parts[1] - associatedGatewayID = parts[2] + proposalID := parts[0] + directConnectGatewayID := parts[1] + associatedGatewayID := parts[2] - if directConnectGatewayID == "" || associatedGatewayID == "" { - return nil, fmt.Errorf("Incorrect resource ID format: %q. DXGATEWAYID and TARGETGATEWAYID must not be empty strings", d.Id()) + if proposalID == "" || directConnectGatewayID == "" || associatedGatewayID == "" { + return nil, fmt.Errorf("Incorrect resource ID format: %q. PROPOSALID, DXGATEWAYID and TARGETGATEWAYID must not be empty strings", d.Id()) } - break + // Use pseudo-proposal ID and actual DirectConnectGatewayId and AssociatedGatewayId. + d.SetId(proposalID) + d.Set("associated_gateway_id", associatedGatewayID) + d.Set("dx_gateway_id", directConnectGatewayID) default: return nil, fmt.Errorf("Incorrect resource ID format: %q. Expected PROPOSALID or PROPOSALID/DXGATEWAYID/TARGETGATEWAYID", d.Id()) } - conn := meta.(*AWSClient).dxconn - - if proposalID != "" { - _, err := finder.GatewayAssociationProposalByID(conn, proposalID) - - if tfresource.NotFound(err) { - // Proposal not found. - } else if err != nil { - return nil, err - } else { - // Proposal still exists. - d.SetId(proposalID) - - return []*schema.ResourceData{d}, nil - } - } - - _, err := finder.GatewayAssociationByDirectConnectGatewayIDAndAssociatedGatewayID(conn, directConnectGatewayID, associatedGatewayID) - - if err != nil { - return nil, err - } - - d.SetId(proposalID) - d.Set("associated_gateway_id", associatedGatewayID) - d.Set("dx_gateway_id", directConnectGatewayID) - return []*schema.ResourceData{d}, nil } - -func getDxGatewayAssociation(conn *directconnect.DirectConnect, dxGatewayId, associatedGatewayId string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - - resp, err := conn.DescribeDirectConnectGatewayAssociations(&directconnect.DescribeDirectConnectGatewayAssociationsInput{ - AssociatedGatewayId: &associatedGatewayId, - DirectConnectGatewayId: &dxGatewayId, - }) - - if err != nil { - return nil, "", err - } - - n := len(resp.DirectConnectGatewayAssociations) - switch n { - case 0: - return "", gatewayAssociationStateDeleted, nil - - case 1: - assoc := resp.DirectConnectGatewayAssociations[0] - - if stateChangeError := aws.StringValue(assoc.StateChangeError); stateChangeError != "" { - id := dxGatewayAssociationId( - aws.StringValue(resp.DirectConnectGatewayAssociations[0].DirectConnectGatewayId), - aws.StringValue(resp.DirectConnectGatewayAssociations[0].AssociatedGateway.Id)) - log.Printf("[INFO] Direct Connect gateway association (%s) state change error: %s", id, stateChangeError) - } - - return assoc, aws.StringValue(assoc.AssociationState), nil - - default: - return nil, "", fmt.Errorf("Found %d Direct Connect gateway associations for %s, expected 1", n, associatedGatewayId) - } - } -} diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index 2f30084a2c01..9e17079a0b18 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -373,10 +373,10 @@ func testAccCheckAwsDxGatewayAssociationProposalDisappears(proposal *directconne } } -func testAccCheckAwsDxGatewayAssociationProposalRecreated(i, j *directconnect.GatewayAssociationProposal) resource.TestCheckFunc { +func testAccCheckAwsDxGatewayAssociationProposalRecreated(old, new *directconnect.GatewayAssociationProposal) resource.TestCheckFunc { return func(s *terraform.State) error { - if aws.StringValue(i.ProposalId) == aws.StringValue(j.ProposalId) { - return fmt.Errorf("Direct Connect Gateway Association Proposal not recreated") + if old, new := aws.StringValue(old.ProposalId), aws.StringValue(new.ProposalId); old == new { + return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not recreated", old) } return nil @@ -392,19 +392,16 @@ func testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName string) re conn := testAccProvider.Meta().(*AWSClient).dxconn - proposal, err := describeDirectConnectGatewayAssociationProposal(conn, rs.Primary.ID) + output, err := finder.GatewayAssociationProposalByID(conn, rs.Primary.ID) if err != nil { return err } - if proposal == nil { - return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not found", rs.Primary.ID) - } - - if aws.StringValue(proposal.ProposalState) != "accepted" { + if aws.StringValue(output.ProposalState) != directconnect.GatewayAssociationProposalStateAccepted { return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not accepted", rs.Primary.ID) } + return nil } } diff --git a/website/docs/r/dx_gateway_association_proposal.html.markdown b/website/docs/r/dx_gateway_association_proposal.html.markdown index 5701772d2b41..74ce04dc4a82 100644 --- a/website/docs/r/dx_gateway_association_proposal.html.markdown +++ b/website/docs/r/dx_gateway_association_proposal.html.markdown @@ -55,3 +55,4 @@ $ terraform import aws_dx_gateway_association_proposal.example ac90e981-b718-436 The latter case is useful when a previous proposal has been accepted and deleted by AWS. The `aws_dx_gateway_association_proposal` resource will then represent a pseudo-proposal for the same Direct Connect Gateway and associated gateway. +If no previous proposal is available, use a tool like [`uuidgen`](http://manpages.ubuntu.com/manpages/bionic/man1/uuidgen.1.html) to generate a new random pseudo-proposal ID. From 50910413e150f74fcb2f78c1a1b9bef3616f710f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 11:14:15 -0400 Subject: [PATCH 1007/1208] Tweak acceptance test configurations. --- ...ws_dx_gateway_association_proposal_test.go | 126 +++++++----------- ...esource_aws_dx_gateway_association_test.go | 22 +-- 2 files changed, 53 insertions(+), 95 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index 9e17079a0b18..de71096ffd73 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -82,7 +82,7 @@ func testSweepDirectConnectGatewayAssociationProposals(region string) error { } func TestAccAwsDxGatewayAssociationProposal_basicVpnGateway(t *testing.T) { - var proposal1 directconnect.GatewayAssociationProposal + var proposal directconnect.GatewayAssociationProposal var providers []*schema.Provider rBgpAsn := acctest.RandIntRange(64512, 65534) rName := acctest.RandomWithPrefix("tf-acc-test") @@ -91,10 +91,7 @@ func TestAccAwsDxGatewayAssociationProposal_basicVpnGateway(t *testing.T) { resourceNameVgw := "aws_vpn_gateway.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccAlternateAccountPreCheck(t) - }, + PreCheck: func() { testAccPreCheck(t); testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsDxGatewayAssociationProposalDestroy, @@ -102,12 +99,12 @@ func TestAccAwsDxGatewayAssociationProposal_basicVpnGateway(t *testing.T) { { Config: testAccDxGatewayAssociationProposalConfig_basicVpnGateway(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal1), - resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), + testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameVgw, "id"), testAccCheckResourceAttrAccountID(resourceName, "associated_gateway_owner_account_id"), resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "virtualPrivateGateway"), - resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), ), }, { @@ -121,7 +118,7 @@ func TestAccAwsDxGatewayAssociationProposal_basicVpnGateway(t *testing.T) { } func TestAccAwsDxGatewayAssociationProposal_basicTransitGateway(t *testing.T) { - var proposal1 directconnect.GatewayAssociationProposal + var proposal directconnect.GatewayAssociationProposal var providers []*schema.Provider rBgpAsn := acctest.RandIntRange(64512, 65534) rName := acctest.RandomWithPrefix("tf-acc-test") @@ -130,10 +127,7 @@ func TestAccAwsDxGatewayAssociationProposal_basicTransitGateway(t *testing.T) { resourceNameTgw := "aws_ec2_transit_gateway.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccAlternateAccountPreCheck(t) - }, + PreCheck: func() { testAccPreCheck(t); testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsDxGatewayAssociationProposalDestroy, @@ -141,14 +135,14 @@ func TestAccAwsDxGatewayAssociationProposal_basicTransitGateway(t *testing.T) { { Config: testAccDxGatewayAssociationProposalConfig_basicTransitGateway(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal1), - resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), - resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameTgw, "id"), - testAccCheckResourceAttrAccountID(resourceName, "associated_gateway_owner_account_id"), - resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "transitGateway"), + testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal), resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "2"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.0/30"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.8/30"), + resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameTgw, "id"), + testAccCheckResourceAttrAccountID(resourceName, "associated_gateway_owner_account_id"), + resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "transitGateway"), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), ), }, { @@ -162,17 +156,14 @@ func TestAccAwsDxGatewayAssociationProposal_basicTransitGateway(t *testing.T) { } func TestAccAwsDxGatewayAssociationProposal_disappears(t *testing.T) { - var proposal1 directconnect.GatewayAssociationProposal + var proposal directconnect.GatewayAssociationProposal var providers []*schema.Provider rBgpAsn := acctest.RandIntRange(64512, 65534) rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_dx_gateway_association_proposal.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccAlternateAccountPreCheck(t) - }, + PreCheck: func() { testAccPreCheck(t); testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsDxGatewayAssociationProposalDestroy, @@ -180,8 +171,8 @@ func TestAccAwsDxGatewayAssociationProposal_disappears(t *testing.T) { { Config: testAccDxGatewayAssociationProposalConfig_basicVpnGateway(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal1), - testAccCheckAwsDxGatewayAssociationProposalDisappears(&proposal1), + testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal), + testAccCheckResourceDisappears(testAccProvider, resourceAwsDxGatewayAssociationProposal(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -190,17 +181,14 @@ func TestAccAwsDxGatewayAssociationProposal_disappears(t *testing.T) { } func TestAccAwsDxGatewayAssociationProposal_endOfLifeVpn(t *testing.T) { - var proposal1 directconnect.GatewayAssociationProposal + var proposal directconnect.GatewayAssociationProposal var providers []*schema.Provider rBgpAsn := acctest.RandIntRange(64512, 65534) rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_dx_gateway_association_proposal.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccAlternateAccountPreCheck(t) - }, + PreCheck: func() { testAccPreCheck(t); testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsDxGatewayAssociationProposalDestroy, @@ -208,39 +196,36 @@ func TestAccAwsDxGatewayAssociationProposal_endOfLifeVpn(t *testing.T) { { Config: testAccDxGatewayAssociationProposalConfig_endOfLifeVpn(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal1), + testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal), testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName), - testAccCheckAwsDxGatewayAssociationProposalDisappears(&proposal1), + testAccCheckResourceDisappears(testAccProvider, resourceAwsDxGatewayAssociationProposal(), resourceName), ), }, { ResourceName: resourceName, ImportStateIdFunc: func(s *terraform.State) (string, error) { return strings.Join([]string{ - aws.StringValue(proposal1.ProposalId), - aws.StringValue(proposal1.DirectConnectGatewayId), - aws.StringValue(proposal1.AssociatedGateway.Id), + aws.StringValue(proposal.ProposalId), + aws.StringValue(proposal.DirectConnectGatewayId), + aws.StringValue(proposal.AssociatedGateway.Id), }, "/"), nil }, ImportState: true, - ImportStateVerify: false, // proposal attributes not applicable when it does not exist + ImportStateVerify: true, }, }, }) } func TestAccAwsDxGatewayAssociationProposal_endOfLifeTgw(t *testing.T) { - var proposal1 directconnect.GatewayAssociationProposal + var proposal directconnect.GatewayAssociationProposal var providers []*schema.Provider rBgpAsn := acctest.RandIntRange(64512, 65534) rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_dx_gateway_association_proposal.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccAlternateAccountPreCheck(t) - }, + PreCheck: func() { testAccPreCheck(t); testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsDxGatewayAssociationProposalDestroy, @@ -248,22 +233,22 @@ func TestAccAwsDxGatewayAssociationProposal_endOfLifeTgw(t *testing.T) { { Config: testAccDxGatewayAssociationProposalConfig_endOfLifeTgw(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal1), + testAccCheckAwsDxGatewayAssociationProposalExists(resourceName, &proposal), testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName), - testAccCheckAwsDxGatewayAssociationProposalDisappears(&proposal1), + testAccCheckResourceDisappears(testAccProvider, resourceAwsDxGatewayAssociationProposal(), resourceName), ), }, { ResourceName: resourceName, ImportStateIdFunc: func(s *terraform.State) (string, error) { return strings.Join([]string{ - aws.StringValue(proposal1.ProposalId), - aws.StringValue(proposal1.DirectConnectGatewayId), - aws.StringValue(proposal1.AssociatedGateway.Id), + aws.StringValue(proposal.ProposalId), + aws.StringValue(proposal.DirectConnectGatewayId), + aws.StringValue(proposal.AssociatedGateway.Id), }, "/"), nil }, ImportState: true, - ImportStateVerify: false, // proposal attributes not applicable when it does not exist + ImportStateVerify: true, }, }, }) @@ -277,10 +262,7 @@ func TestAccAwsDxGatewayAssociationProposal_AllowedPrefixes(t *testing.T) { resourceName := "aws_dx_gateway_association_proposal.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccAlternateAccountPreCheck(t) - }, + PreCheck: func() { testAccPreCheck(t); testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsDxGatewayAssociationProposalDestroy, @@ -359,20 +341,6 @@ func testAccCheckAwsDxGatewayAssociationProposalExists(resourceName string, gate } } -func testAccCheckAwsDxGatewayAssociationProposalDisappears(proposal *directconnect.GatewayAssociationProposal) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).dxconn - - input := &directconnect.DeleteDirectConnectGatewayAssociationProposalInput{ - ProposalId: proposal.ProposalId, - } - - _, err := conn.DeleteDirectConnectGatewayAssociationProposal(input) - - return err - } -} - func testAccCheckAwsDxGatewayAssociationProposalRecreated(old, new *directconnect.GatewayAssociationProposal) resource.TestCheckFunc { return func(s *terraform.State) error { if old, new := aws.StringValue(old.ProposalId), aws.StringValue(new.ProposalId); old == new { @@ -407,7 +375,7 @@ func testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName string) re } func testAccDxGatewayAssociationProposalConfigBase_vpnGateway(rName string, rBgpAsn int) string { - return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` + return composeConfig(testAccAlternateAccountProviderConfig(), fmt.Sprintf(` resource "aws_dx_gateway" "test" { provider = "awsalternate" @@ -430,21 +398,21 @@ resource "aws_vpn_gateway" "test" { Name = %[1]q } } -`, rName, rBgpAsn) +`, rName, rBgpAsn)) } func testAccDxGatewayAssociationProposalConfig_basicVpnGateway(rName string, rBgpAsn int) string { - return testAccDxGatewayAssociationProposalConfigBase_vpnGateway(rName, rBgpAsn) + ` + return composeConfig(testAccDxGatewayAssociationProposalConfigBase_vpnGateway(rName, rBgpAsn), ` resource "aws_dx_gateway_association_proposal" "test" { dx_gateway_id = aws_dx_gateway.test.id dx_gateway_owner_account_id = aws_dx_gateway.test.owner_account_id associated_gateway_id = aws_vpn_gateway.test.id } -` +`) } func testAccDxGatewayAssociationProposalConfig_endOfLifeVpn(rName string, rBgpAsn int) string { - return testAccDxGatewayAssociationProposalConfig_basicVpnGateway(rName, rBgpAsn) + ` + return composeConfig(testAccDxGatewayAssociationProposalConfig_basicVpnGateway(rName, rBgpAsn), ` data "aws_caller_identity" "current" {} resource "aws_dx_gateway_association" "test" { @@ -454,11 +422,11 @@ proposal_id = aws_dx_gateway_association_proposal.test.i dx_gateway_id = aws_dx_gateway.test.id associated_gateway_owner_account_id = data.aws_caller_identity.current.account_id } -` +`) } func testAccDxGatewayAssociationProposalConfig_endOfLifeTgw(rName string, rBgpAsn int) string { - return testAccDxGatewayAssociationProposalConfig_basicTransitGateway(rName, rBgpAsn) + ` + return composeConfig(testAccDxGatewayAssociationProposalConfig_basicTransitGateway(rName, rBgpAsn), ` data "aws_caller_identity" "current" {} resource "aws_dx_gateway_association" "test" { @@ -468,11 +436,11 @@ proposal_id = aws_dx_gateway_association_proposal.test.i dx_gateway_id = aws_dx_gateway.test.id associated_gateway_owner_account_id = data.aws_caller_identity.current.account_id } -` +`) } func testAccDxGatewayAssociationProposalConfig_basicTransitGateway(rName string, rBgpAsn int) string { - return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` + return composeConfig(testAccAlternateAccountProviderConfig(), fmt.Sprintf(` resource "aws_dx_gateway" "test" { provider = "awsalternate" @@ -496,27 +464,27 @@ resource "aws_dx_gateway_association_proposal" "test" { "10.255.255.8/30", ] } -`, rName, rBgpAsn) +`, rName, rBgpAsn)) } func testAccDxGatewayAssociationProposalConfigAllowedPrefixes1(rName string, rBgpAsn int) string { - return testAccDxGatewayAssociationProposalConfigBase_vpnGateway(rName, rBgpAsn) + ` + return composeConfig(testAccDxGatewayAssociationProposalConfigBase_vpnGateway(rName, rBgpAsn), ` resource "aws_dx_gateway_association_proposal" "test" { allowed_prefixes = ["10.0.0.0/16"] dx_gateway_id = aws_dx_gateway.test.id dx_gateway_owner_account_id = aws_dx_gateway.test.owner_account_id associated_gateway_id = aws_vpn_gateway.test.id } -` +`) } func testAccDxGatewayAssociationProposalConfigAllowedPrefixes2(rName string, rBgpAsn int) string { - return testAccDxGatewayAssociationProposalConfigBase_vpnGateway(rName, rBgpAsn) + ` + return composeConfig(testAccDxGatewayAssociationProposalConfigBase_vpnGateway(rName, rBgpAsn), ` resource "aws_dx_gateway_association_proposal" "test" { allowed_prefixes = ["10.0.0.0/24", "10.0.1.0/24"] dx_gateway_id = aws_dx_gateway.test.id dx_gateway_owner_account_id = aws_dx_gateway.test.owner_account_id associated_gateway_id = aws_vpn_gateway.test.id } -` +`) } diff --git a/aws/resource_aws_dx_gateway_association_test.go b/aws/resource_aws_dx_gateway_association_test.go index d85ed68d5bab..ff4229816343 100644 --- a/aws/resource_aws_dx_gateway_association_test.go +++ b/aws/resource_aws_dx_gateway_association_test.go @@ -490,7 +490,7 @@ func TestAccAwsDxGatewayAssociation_recreateProposal(t *testing.T) { Config: testAccDxGatewayAssociationConfig_basicVpnGatewayCrossAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga1, &gap1), - testAccCheckAwsDxGatewayAssociationProposalDisappears(&gap1), + testAccCheckResourceDisappears(testAccProvider, resourceAwsDxGatewayAssociationProposal(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -498,8 +498,8 @@ func TestAccAwsDxGatewayAssociation_recreateProposal(t *testing.T) { Config: testAccDxGatewayAssociationConfig_basicVpnGatewayCrossAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga2, &gap2), - testAccCheckAwsDxGatewayAssociationSameAssociation(&ga1, &ga2), - testAccCheckAwsDxGatewayAssociationDifferentProposal(&gap1, &gap2), + testAccCheckAwsDxGatewayAssociationNotRecreated(&ga1, &ga2), + testAccCheckAwsDxGatewayAssociationProposalRecreated(&gap1, &gap2), ), }, }, @@ -575,20 +575,10 @@ func testAccCheckAwsDxGatewayAssociationExists(name string, ga *directconnect.Ga } } -func testAccCheckAwsDxGatewayAssociationSameAssociation(ga1, ga2 *directconnect.GatewayAssociation) resource.TestCheckFunc { +func testAccCheckAwsDxGatewayAssociationNotRecreated(old, new *directconnect.GatewayAssociation) resource.TestCheckFunc { return func(s *terraform.State) error { - if aws.StringValue(ga1.AssociationId) != aws.StringValue(ga2.AssociationId) { - return fmt.Errorf("Association IDs differ") - } - - return nil - } -} - -func testAccCheckAwsDxGatewayAssociationDifferentProposal(gap1, gap2 *directconnect.GatewayAssociationProposal) resource.TestCheckFunc { - return func(s *terraform.State) error { - if aws.StringValue(gap1.ProposalId) == aws.StringValue(gap2.ProposalId) { - return fmt.Errorf("Proposals IDs are equal") + if old, new := aws.StringValue(old.AssociationId), aws.StringValue(new.AssociationId); old == new { + return fmt.Errorf("Direct Connect Gateway Association (%s) recreated (%s)", old, new) } return nil From f06467088341e408a658903f6e000cac02e597c0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 11:30:08 -0400 Subject: [PATCH 1008/1208] Correct resource name in CHANGELOG --- .changelog/19718.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/19718.txt b/.changelog/19718.txt index 02c0d651b12d..10a50d191fa9 100644 --- a/.changelog/19718.txt +++ b/.changelog/19718.txt @@ -1,3 +1,3 @@ ```release-note:bug -resource/aws_ram_resource_share_acceptor: Allow destroy even where AWS API provides no way to disassociate +resource/aws_ram_resource_share_accepter: Allow destroy even where AWS API provides no way to disassociate ``` From 81f8ff4b5e72bf385b5cff693562749481805b54 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 8 Jul 2021 15:34:31 +0000 Subject: [PATCH 1009/1208] Update CHANGELOG.md for #20105 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4eade413bc5e..8117c545ea28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ENHANCEMENTS: BUG FIXES: * resource/aws_eks_cluster: Don't associate an `encryption_config` if there's already one ([#19986](https://github.com/hashicorp/terraform-provider-aws/issues/19986)) +* resource/aws_ram_resource_share_accepter: Allow destroy even where AWS API provides no way to disassociate ([#19718](https://github.com/hashicorp/terraform-provider-aws/issues/19718)) ## 3.48.0 (July 02, 2021) From 847d868699f34843817e1baa3e7cf40f0f404628 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 11:39:18 -0400 Subject: [PATCH 1010/1208] Fix 'errcheck' linter errors. --- aws/resource_aws_dx_gateway_association_proposal_test.go | 2 +- aws/resource_aws_dx_gateway_association_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index de71096ffd73..c77eed169a12 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -35,7 +35,7 @@ func testSweepDirectConnectGatewayAssociationProposals(region string) error { var sweeperErrs *multierror.Error sweepResources := make([]*testSweepResource, 0) - lister.DescribeDirectConnectGatewayAssociationProposalsPages(conn, input, func(page *directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput, lastPage bool) bool { + err = lister.DescribeDirectConnectGatewayAssociationProposalsPages(conn, input, func(page *directconnect.DescribeDirectConnectGatewayAssociationProposalsOutput, lastPage bool) bool { if page == nil { return !lastPage } diff --git a/aws/resource_aws_dx_gateway_association_test.go b/aws/resource_aws_dx_gateway_association_test.go index ff4229816343..c57fc0efaacd 100644 --- a/aws/resource_aws_dx_gateway_association_test.go +++ b/aws/resource_aws_dx_gateway_association_test.go @@ -40,7 +40,7 @@ func testSweepDirectConnectGatewayAssociations(region string) error { var sweeperErrs *multierror.Error sweepResources := make([]*testSweepResource, 0) - lister.DescribeDirectConnectGatewaysPages(conn, input, func(page *directconnect.DescribeDirectConnectGatewaysOutput, lastPage bool) bool { + err = lister.DescribeDirectConnectGatewaysPages(conn, input, func(page *directconnect.DescribeDirectConnectGatewaysOutput, lastPage bool) bool { if page == nil { return !lastPage } From 260874d8a01cd33b05163e0fef578041b7a71a90 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 11:42:30 -0400 Subject: [PATCH 1011/1208] Remove reference to hashibot --- docs/MAINTAINING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/MAINTAINING.md b/docs/MAINTAINING.md index bb36731efe7f..8561a4e3ab8c 100644 --- a/docs/MAINTAINING.md +++ b/docs/MAINTAINING.md @@ -506,4 +506,4 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi - Web interface: With the `DEPLOYMENT_TARGET_VERSION` matching the expected release milestone and `DEPLOYMENT_NEXT_VERSION` matching the next release milestone - Wait for the TeamCity release job to complete either by watching the build logs or Slack notifications - Close the release milestone -- Create a new GitHub release with the release title exactly matching the tag and milestone (e.g. `v2.22.0`) and copy the entries from the CHANGELOG to the release notes. This will trigger [HashiBot](https://github.com/apps/hashibot) release comments. +- Create a new GitHub release with the release title exactly matching the tag and milestone (e.g. `v2.22.0`) and copy the entries from the CHANGELOG to the release notes. From 1a884d2a7934a7ab746e26403b6a061a5872a91c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 11:59:46 -0400 Subject: [PATCH 1012/1208] r/aws_dx_gateway_association: Use internal waiter package. --- aws/resource_aws_dx_gateway_association.go | 61 ++++------------------ 1 file changed, 11 insertions(+), 50 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association.go b/aws/resource_aws_dx_gateway_association.go index f9f6ea4d1b5b..19ba70b50bf0 100644 --- a/aws/resource_aws_dx_gateway_association.go +++ b/aws/resource_aws_dx_gateway_association.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/waiter" ) const ( @@ -23,6 +24,7 @@ func resourceAwsDxGatewayAssociation() *schema.Resource { Read: resourceAwsDxGatewayAssociationRead, Update: resourceAwsDxGatewayAssociationUpdate, Delete: resourceAwsDxGatewayAssociationDelete, + Importer: &schema.ResourceImporter{ State: resourceAwsDxGatewayAssociationImport, }, @@ -50,6 +52,7 @@ func resourceAwsDxGatewayAssociation() *schema.Resource { Computed: true, ForceNew: true, ConflictsWith: []string{"associated_gateway_owner_account_id", "proposal_id"}, + AtLeastOneOf: []string{"associated_gateway_id", "associated_gateway_owner_account_id", "proposal_id"}, }, "associated_gateway_owner_account_id": { @@ -59,6 +62,8 @@ func resourceAwsDxGatewayAssociation() *schema.Resource { ForceNew: true, ValidateFunc: validateAwsAccountId, ConflictsWith: []string{"associated_gateway_id"}, + RequiredWith: []string{"proposal_id"}, + AtLeastOneOf: []string{"associated_gateway_id", "associated_gateway_owner_account_id", "proposal_id"}, }, "associated_gateway_type": { @@ -86,6 +91,7 @@ func resourceAwsDxGatewayAssociation() *schema.Resource { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"associated_gateway_id", "vpn_gateway_id"}, + AtLeastOneOf: []string{"associated_gateway_id", "associated_gateway_owner_account_id", "proposal_id"}, }, "vpn_gateway_id": { @@ -161,8 +167,8 @@ func resourceAwsDxGatewayAssociationCreate(d *schema.ResourceData, meta interfac } d.Set("dx_gateway_association_id", associationId) - if err := waitForDirectConnectGatewayAssociationAvailabilityOnCreate(conn, associationId, d.Timeout(schema.TimeoutCreate)); err != nil { - return fmt.Errorf("error waiting for Direct Connect gateway association (%s) to become available: %s", d.Id(), err) + if _, err := waiter.GatewayAssociationCreated(conn, associationId, d.Timeout(schema.TimeoutCreate)); err != nil { + return fmt.Errorf("error waiting for Direct Connect Gateway Association (%s) to create: %w", d.Id(), err) } return resourceAwsDxGatewayAssociationRead(d, meta) @@ -223,8 +229,8 @@ func resourceAwsDxGatewayAssociationUpdate(d *schema.ResourceData, meta interfac return fmt.Errorf("error updating Direct Connect gateway association (%s): %s", d.Id(), err) } - if err := waitForDirectConnectGatewayAssociationAvailabilityOnUpdate(conn, associationId, d.Timeout(schema.TimeoutUpdate)); err != nil { - return fmt.Errorf("error waiting for Direct Connect gateway association (%s) to become available: %s", d.Id(), err) + if _, err := waiter.GatewayAssociationUpdated(conn, associationId, d.Timeout(schema.TimeoutUpdate)); err != nil { + return fmt.Errorf("error waiting for Direct Connect Gateway Association (%s) to update: %w", d.Id(), err) } } @@ -249,7 +255,7 @@ func resourceAwsDxGatewayAssociationDelete(d *schema.ResourceData, meta interfac return fmt.Errorf("error deleting Direct Connect Gateway Association (%s): %w", d.Id(), err) } - if err := waitForDirectConnectGatewayAssociationDeletion(conn, associationID, d.Timeout(schema.TimeoutDelete)); err != nil { + if _, err := waiter.GatewayAssociationDeleted(conn, associationID, d.Timeout(schema.TimeoutDelete)); err != nil { return fmt.Errorf("error waiting for Direct Connect Gateway Association (%s) to delete: %w", d.Id(), err) } @@ -323,48 +329,3 @@ func dxGatewayAssociationStateRefresh(conn *directconnect.DirectConnect, associa func dxGatewayAssociationId(dxgwId, gwId string) string { return fmt.Sprintf("ga-%s%s", dxgwId, gwId) } - -func waitForDirectConnectGatewayAssociationAvailabilityOnCreate(conn *directconnect.DirectConnect, associationId string, timeout time.Duration) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{directconnect.GatewayAssociationStateAssociating}, - Target: []string{directconnect.GatewayAssociationStateAssociated}, - Refresh: dxGatewayAssociationStateRefresh(conn, associationId), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 5 * time.Second, - } - - _, err := stateConf.WaitForState() - - return err -} - -func waitForDirectConnectGatewayAssociationAvailabilityOnUpdate(conn *directconnect.DirectConnect, associationId string, timeout time.Duration) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{directconnect.GatewayAssociationStateUpdating}, - Target: []string{directconnect.GatewayAssociationStateAssociated}, - Refresh: dxGatewayAssociationStateRefresh(conn, associationId), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 5 * time.Second, - } - - _, err := stateConf.WaitForState() - - return err -} - -func waitForDirectConnectGatewayAssociationDeletion(conn *directconnect.DirectConnect, associationId string, timeout time.Duration) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{directconnect.GatewayAssociationStateDisassociating}, - Target: []string{directconnect.GatewayAssociationStateDisassociated, gatewayAssociationStateDeleted}, - Refresh: dxGatewayAssociationStateRefresh(conn, associationId), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 5 * time.Second, - } - - _, err := stateConf.WaitForState() - - return err -} From 50c70f0a169ed7356d40fcd8b9b814e16631b88f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:24:58 -0400 Subject: [PATCH 1013/1208] i/lakeformation: Add enum file --- aws/internal/service/lakeformation/enum.go | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 aws/internal/service/lakeformation/enum.go diff --git a/aws/internal/service/lakeformation/enum.go b/aws/internal/service/lakeformation/enum.go new file mode 100644 index 000000000000..d6be8ccf03f7 --- /dev/null +++ b/aws/internal/service/lakeformation/enum.go @@ -0,0 +1,8 @@ +package lakeformation + +const ( + TableNameAllTables = "ALL_TABLES" + TableTypeTable = "Table" + TableTypeTableWithColumns = "TableWithColumns" + IAMAllowedPrincipals = "IAM_ALLOWED_PRINCIPALS" +) From fa5163176fa8be3e9ecc386fc0eb12525dddfbe4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:28:30 -0400 Subject: [PATCH 1014/1208] docs/r/lakeformation_permissions: Add docs on IAMAllowedPrincipals --- .../r/lakeformation_permissions.html.markdown | 85 +++++++++++++++++-- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index 9fb3166fe722..d6b116689bf3 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -10,8 +10,83 @@ description: |- Grants permissions to the principal to access metadata in the Data Catalog and data organized in underlying data storage such as Amazon S3. Permissions are granted to a principal, in a Data Catalog, relative to a Lake Formation resource, which includes the Data Catalog, databases, and tables. For more information, see [Security and Access Control to Metadata and Data in Lake Formation](https://docs.aws.amazon.com/lake-formation/latest/dg/security-data-access.html). +!> **WARNING:** Lake Formation permissions are not in effect by default within AWS. Using this resource will not secure your data and will result in errors if you do not change the security settings for existing resources and the default security settings for new resources. See [Default Behavior and `IAMAllowedPrincipals`](#default-behavior-and-iamallowedprincipals) for additional details. + ~> **NOTE:** In general, the `principal` should _NOT_ be a Lake Formation administrator or the entity (e.g., IAM role) that is running Terraform. Administrators have implicit permissions. These should be managed by granting or not granting administrator rights using `aws_lakeformation_data_lake_settings`, _not_ with this resource. +## Default Behavior and `IAMAllowedPrincipals` + +**_Lake Formation permissions are not in effect by default within AWS._** `IAMAllowedPrincipals` (i.e., `IAM_ALLOWED_PRINCIPALS`) conflicts with individual Lake Formation permissions (i.e., non-`IAMAllowedPrincipals` permissions), will cause unexpected behavior, and may result in errors. + +When using Lake Formation, you need to choose between these two mutually exclusive options: + +1. Use this resource (`aws_lakeformation_permissions`), change the default security settings using [`aws_lakeformation_data_lake_settings`](/docs/providers/aws/r/lakeformation_data_lake_settings.html), and remove existing `IAMAllowedPrincipals` permissions +2. Use `IAMAllowedPrincipals` and not use this resource + +This example shows removing the `IAMAllowedPrincipals` default security settings and making the caller a Lake Formation admin. Since `create_database_default_permissions` and `create_table_default_permissions` are not set in the [`aws_lakeformation_data_lake_settings`](/docs/providers/aws/r/lakeformation_data_lake_settings.html) resource, they are cleared. + +```terraform +data "aws_caller_identity" "current" {} + +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + +resource "aws_lakeformation_data_lake_settings" "test" { + admins = [data.aws_iam_session_context.current.issuer_arn] +} +``` + +To remove existing `IAMAllowedPrincipals` permissions, use the [AWS Lake Formation Console](https://console.aws.amazon.com/lakeformation/) or [AWS CLI](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lakeformation/batch-revoke-permissions.html). + +`IAMAllowedPrincipals` is a hook to maintain backwards compatibility with AWS Glue. `IAMAllowedPrincipals` is a pseudo-entity group that acts like a Lake Formation principal. The group includes any IAM users and roles that are allowed access to your Data Catalog resources by your IAM policies. + +This is Lake Formation's default behavior: + +* Lake Formation grants `Super` permission to `IAMAllowedPrincipals` on all existing AWS Glue Data Catalog resources. +* Lake Formation enables "Use only IAM access control" for new Data Catalog resources. + +For more details, see [Changing the Default Security Settings for Your Data Lake](https://docs.aws.amazon.com/lake-formation/latest/dg/change-settings.html). + +### Example Problem Using `IAMAllowedPrincipals` + +AWS does not support combining `IAMAllowedPrincipals` permissions and non-`IAMAllowedPrincipals` permissions. Doing so results in unexpected permissions. For example, this configuration grants a user `SELECT` on a column in a table. + +```terraform +resource "aws_glue_catalog_database" "example" { + name = "sadabate" +} + +resource "aws_glue_catalog_table" "example" { + name = "abelt" + database_name = aws_glue_catalog_database.test.name + + storage_descriptor { + columns { + name = "event" + type = "string" + } + } +} + +resource "aws_lakeformation_permissions" "example" { + permissions = ["SELECT"] + principal = "arn:aws:iam:us-east-1:123456789012:user/SanHolo" + + table_with_columns { + database_name = aws_glue_catalog_table.example.database_name + name = aws_glue_catalog_table.example.name + column_names = ["event"] + } +} +``` + +The resulting permissions depend on whether the table had `IAMAllowedPrincipals` (IAP) permissions or not. + +| Result With IAP | Result Without IAP | +| ---- | ---- | +| `SELECT` on table with columns with column wildcard (i.e., all columns) | `SELECT` on `"event"` (as expected) | + ## Using Lake Formation Permissions Lake Formation grants implicit permissions to data lake administrators, database creators, and table creators. These implicit permissions cannot be revoked _per se_. If this resource reads implicit permissions, it will attempt to revoke them, which causes an error when the resource is destroyed. @@ -25,12 +100,12 @@ If the `principal` is also a data lake administrator, AWS grants implicit permis ### Grant Permissions For A Lake Formation S3 Resource ```terraform -resource "aws_lakeformation_permissions" "test" { +resource "aws_lakeformation_permissions" "example" { principal = aws_iam_role.workflow_role.arn permissions = ["ALL"] data_location { - arn = aws_lakeformation_resource.test.arn + arn = aws_lakeformation_resource.example.arn } } ``` @@ -38,12 +113,12 @@ resource "aws_lakeformation_permissions" "test" { ### Grant Permissions For A Glue Catalog Database ```terraform -resource "aws_lakeformation_permissions" "test" { +resource "aws_lakeformation_permissions" "example" { role = aws_iam_role.workflow_role.arn permissions = ["CREATE_TABLE", "ALTER", "DROP"] database { - name = aws_glue_catalog_database.test.name + name = aws_glue_catalog_database.example.name catalog_id = "110376042874" } } @@ -54,7 +129,7 @@ resource "aws_lakeformation_permissions" "test" { The following arguments are required: * `permissions` – (Required) List of permissions granted to the principal. Valid values may include `ALL`, `ALTER`, `CREATE_DATABASE`, `CREATE_TABLE`, `DATA_LOCATION_ACCESS`, `DELETE`, `DESCRIBE`, `DROP`, `INSERT`, and `SELECT`. For details on each permission, see [Lake Formation Permissions Reference](https://docs.aws.amazon.com/lake-formation/latest/dg/lf-permissions-reference.html). -* `principal` – (Required) Principal to be granted the permissions on the resource. Supported principals include IAM roles, users, groups, SAML groups and users, QuickSight groups, OUs, and organizations as well as AWS account IDs for cross-account permissions. For more information, see [Lake Formation Permissions Reference](https://docs.aws.amazon.com/lake-formation/latest/dg/lf-permissions-reference.html). +* `principal` – (Required) Principal to be granted the permissions on the resource. Supported principals include `IAM_ALLOWED_PRINCIPALS` (see [Default Behavior and `IAMAllowedPrincipals`](#default-behavior-and-iamallowedprincipals) above), IAM roles, users, groups, SAML groups and users, QuickSight groups, OUs, and organizations as well as AWS account IDs for cross-account permissions. For more information, see [Lake Formation Permissions Reference](https://docs.aws.amazon.com/lake-formation/latest/dg/lf-permissions-reference.html). ~> **NOTE:** We highly recommend that the `principal` _NOT_ be a Lake Formation administrator (granted using `aws_lakeformation_data_lake_settings`). The entity (e.g., IAM role) running Terraform will most likely need to be a Lake Formation administrator. As such, the entity will have implicit permissions and does not need permissions granted through this resource. From 10970c4e99ddf1988432f31b3b2c0a696fbcd2c7 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:29:06 -0400 Subject: [PATCH 1015/1208] tests/lakeformation: Add new tests, rename existing --- aws/resource_aws_lakeformation_test.go | 53 +++++++++++++++----------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/aws/resource_aws_lakeformation_test.go b/aws/resource_aws_lakeformation_test.go index 6f012aefe4e4..aef0bd5574ba 100644 --- a/aws/resource_aws_lakeformation_test.go +++ b/aws/resource_aws_lakeformation_test.go @@ -8,35 +8,42 @@ func TestAccAWSLakeFormation_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "DataLakeSettings": { "basic": testAccAWSLakeFormationDataLakeSettings_basic, + "dataSource": testAccAWSLakeFormationDataLakeSettingsDataSource_basic, "disappears": testAccAWSLakeFormationDataLakeSettings_disappears, "withoutCatalogId": testAccAWSLakeFormationDataLakeSettings_withoutCatalogId, - "dataSource": testAccAWSLakeFormationDataLakeSettingsDataSource_basic, }, - "BasicPermissions": { - "basic": testAccAWSLakeFormationPermissions_basic, - "dataLocation": testAccAWSLakeFormationPermissions_dataLocation, - "database": testAccAWSLakeFormationPermissions_database, - "disappears": testAccAWSLakeFormationPermissions_disappears, + "PermissionsBasic": { + "basic": testAccAWSLakeFormationPermissions_basic, + "database": testAccAWSLakeFormationPermissions_database, + "databaseIAMAllowed": testAccAWSLakeFormationPermissions_databaseIAMAllowed, + "databaseMultiple": testAccAWSLakeFormationPermissions_databaseMultiple, + "dataLocation": testAccAWSLakeFormationPermissions_dataLocation, + "disappears": testAccAWSLakeFormationPermissions_disappears, }, - "TablePermissions": { - "implicitTablePermissions": testAccAWSLakeFormationPermissions_implicitTablePermissions, - "selectPermissions": testAccAWSLakeFormationPermissions_selectPermissions, - "tableName": testAccAWSLakeFormationPermissions_tableName, - "tableWildcard": testAccAWSLakeFormationPermissions_tableWildcard, - "tableWildcardPermissions": testAccAWSLakeFormationPermissions_tableWildcardPermissions, + "PermissionsDataSource": { + "basic": testAccAWSLakeFormationPermissionsDataSource_basic, + "database": testAccAWSLakeFormationPermissionsDataSource_database, + "dataLocation": testAccAWSLakeFormationPermissionsDataSource_dataLocation, + "table": testAccAWSLakeFormationPermissionsDataSource_table, + "tableWithColumns": testAccAWSLakeFormationPermissionsDataSource_tableWithColumns, }, - "TableWithColumnsPermissions": { - "columnWildcardExcludedColumnsPermissions": testAccAWSLakeFormationPermissions_columnWildcardExcludedColumnsPermissions, - "columnWildcardPermissions": testAccAWSLakeFormationPermissions_columnWildcardPermissions, - "implicitTableWithColumnsPermissions": testAccAWSLakeFormationPermissions_implicitTableWithColumnsPermissions, - "tableWithColumns": testAccAWSLakeFormationPermissions_tableWithColumns, + "PermissionsTable": { + "basic": testAccAWSLakeFormationPermissions_tableBasic, + "iamAllowed": testAccAWSLakeFormationPermissions_tableIAMAllowed, + "implicit": testAccAWSLakeFormationPermissions_tableImplicit, + "multipleRoles": testAccAWSLakeFormationPermissions_tableMultipleRoles, + "selectOnly": testAccAWSLakeFormationPermissions_tableSelectOnly, + "selectPlus": testAccAWSLakeFormationPermissions_tableSelectPlus, + "wildcardNoSelect": testAccAWSLakeFormationPermissions_tableWildcardNoSelect, + "wildcardSelectOnly": testAccAWSLakeFormationPermissions_tableWildcardSelectOnly, + "wildcardSelectPlus": testAccAWSLakeFormationPermissions_tableWildcardSelectPlus, }, - "DataSourcePermissions": { - "basicDataSource": testAccAWSLakeFormationPermissionsDataSource_basic, - "dataLocationDataSource": testAccAWSLakeFormationPermissionsDataSource_dataLocation, - "databaseDataSource": testAccAWSLakeFormationPermissionsDataSource_database, - "tableDataSource": testAccAWSLakeFormationPermissionsDataSource_table, - "tableWithColumnsDataSource": testAccAWSLakeFormationPermissionsDataSource_tableWithColumns, + "PermissionsTableWithColumns": { + "basic": testAccAWSLakeFormationPermissions_twcBasic, + "implicit": testAccAWSLakeFormationPermissions_twcImplicit, + "wildcardExcludedColumns": testAccAWSLakeFormationPermissions_twcWildcardExcludedColumns, + "wildcardSelectOnly": testAccAWSLakeFormationPermissions_twcWildcardSelectOnly, + "wildcardSelectPlus": testAccAWSLakeFormationPermissions_twcWildcardSelectPlus, }, } From 81b10a55bcc58a59b13256bd7ef60cd9140c0955 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:29:42 -0400 Subject: [PATCH 1016/1208] tests/r/lakeformation_permissions: Fix bugs --- ...urce_aws_lakeformation_permissions_test.go | 1485 ++++++++++++----- 1 file changed, 1081 insertions(+), 404 deletions(-) diff --git a/aws/resource_aws_lakeformation_permissions_test.go b/aws/resource_aws_lakeformation_permissions_test.go index bfd87e3fd9fe..8fcbb28dcc4d 100644 --- a/aws/resource_aws_lakeformation_permissions_test.go +++ b/aws/resource_aws_lakeformation_permissions_test.go @@ -53,7 +53,7 @@ func testAccAWSLakeFormationPermissions_disappears(t *testing.T) { CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName, "\"event\", \"timestamp\""), + Config: testAccAWSLakeFormationPermissionsConfig_twcBasic(rName, "\"event\", \"timestamp\""), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), testAccCheckResourceDisappears(testAccProvider, resourceAwsLakeFormationPermissions(), resourceName), @@ -64,11 +64,11 @@ func testAccAWSLakeFormationPermissions_disappears(t *testing.T) { }) } -func testAccAWSLakeFormationPermissions_dataLocation(t *testing.T) { +func testAccAWSLakeFormationPermissions_database(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" roleName := "aws_iam_role.test" - bucketName := "aws_s3_bucket.test" + dbName := "aws_glue_catalog_database.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, @@ -77,25 +77,60 @@ func testAccAWSLakeFormationPermissions_dataLocation(t *testing.T) { CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_dataLocation(rName), + Config: testAccAWSLakeFormationPermissionsConfig_database(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), - resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), - resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionDataLocationAccess), resource.TestCheckResourceAttr(resourceName, "catalog_resource", "false"), - resource.TestCheckResourceAttr(resourceName, "data_location.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "data_location.0.arn", bucketName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "database.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "database.0.name", dbName, "name"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "3"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionAlter), + resource.TestCheckResourceAttr(resourceName, "permissions.1", lakeformation.PermissionCreateTable), + resource.TestCheckResourceAttr(resourceName, "permissions.2", lakeformation.PermissionDrop), + resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.0", lakeformation.PermissionCreateTable), ), }, }, }) } -func testAccAWSLakeFormationPermissions_database(t *testing.T) { +func testAccAWSLakeFormationPermissions_databaseIAMAllowed(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lakeformation_permissions.test" + dbName := "aws_glue_catalog_database.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, lakeformation.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLakeFormationPermissionsConfig_databaseIAMAllowed(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "principal", tflakeformation.IAMAllowedPrincipals), + resource.TestCheckResourceAttr(resourceName, "catalog_resource", "false"), + resource.TestCheckResourceAttr(resourceName, "database.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "database.0.name", dbName, "name"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionAll), + resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "0"), + ), + }, + }, + }) +} + +func testAccAWSLakeFormationPermissions_databaseMultiple(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" + resourceName2 := "aws_lakeformation_permissions.test2" roleName := "aws_iam_role.test" + roleName2 := "aws_iam_role.test2" dbName := "aws_glue_catalog_database.test" resource.Test(t, resource.TestCase{ @@ -105,7 +140,7 @@ func testAccAWSLakeFormationPermissions_database(t *testing.T) { CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_database(rName), + Config: testAccAWSLakeFormationPermissionsConfig_databaseMultiple(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), @@ -114,18 +149,56 @@ func testAccAWSLakeFormationPermissions_database(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "database.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "database.0.name", dbName, "name"), resource.TestCheckResourceAttr(resourceName, "permissions.#", "3"), - resource.TestCheckResourceAttr(resourceName, "permissions.0", "ALTER"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionAlter), resource.TestCheckResourceAttr(resourceName, "permissions.1", lakeformation.PermissionCreateTable), resource.TestCheckResourceAttr(resourceName, "permissions.2", lakeformation.PermissionDrop), resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "1"), resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.0", lakeformation.PermissionCreateTable), + testAccCheckAWSLakeFormationPermissionsExists(resourceName2), + resource.TestCheckResourceAttrPair(resourceName2, "principal", roleName2, "arn"), + resource.TestCheckResourceAttr(resourceName2, "catalog_resource", "false"), + resource.TestCheckResourceAttrPair(resourceName2, "principal", roleName2, "arn"), + resource.TestCheckResourceAttr(resourceName2, "database.#", "1"), + resource.TestCheckResourceAttrPair(resourceName2, "database.0.name", dbName, "name"), + resource.TestCheckResourceAttr(resourceName2, "permissions.#", "2"), + resource.TestCheckResourceAttr(resourceName2, "permissions.0", lakeformation.PermissionAlter), + resource.TestCheckResourceAttr(resourceName2, "permissions.1", lakeformation.PermissionDrop), + resource.TestCheckResourceAttr(resourceName2, "permissions_with_grant_option.#", "0"), + ), + }, + }, + }) +} + +func testAccAWSLakeFormationPermissions_dataLocation(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lakeformation_permissions.test" + roleName := "aws_iam_role.test" + bucketName := "aws_s3_bucket.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, lakeformation.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLakeFormationPermissionsConfig_dataLocation(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionDataLocationAccess), + resource.TestCheckResourceAttr(resourceName, "catalog_resource", "false"), + resource.TestCheckResourceAttr(resourceName, "data_location.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "data_location.0.arn", bucketName, "arn"), ), }, }, }) } -func testAccAWSLakeFormationPermissions_tableName(t *testing.T) { +func testAccAWSLakeFormationPermissions_tableBasic(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" roleName := "aws_iam_role.test" @@ -138,7 +211,7 @@ func testAccAWSLakeFormationPermissions_tableName(t *testing.T) { CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_tableName(rName), + Config: testAccAWSLakeFormationPermissionsConfig_tableBasic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), resource.TestCheckResourceAttrPair(roleName, "arn", resourceName, "principal"), @@ -155,10 +228,10 @@ func testAccAWSLakeFormationPermissions_tableName(t *testing.T) { }) } -func testAccAWSLakeFormationPermissions_tableWildcard(t *testing.T) { +func testAccAWSLakeFormationPermissions_tableIAMAllowed(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" - databaseResourceName := "aws_glue_catalog_database.test" + dbName := "aws_glue_catalog_table.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, @@ -167,19 +240,24 @@ func testAccAWSLakeFormationPermissions_tableWildcard(t *testing.T) { CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_tableWildcard(rName), + Config: testAccAWSLakeFormationPermissionsConfig_tableIAMAllowed(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "principal", tflakeformation.IAMAllowedPrincipals), + resource.TestCheckResourceAttr(resourceName, "catalog_resource", "false"), resource.TestCheckResourceAttr(resourceName, "table.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "table.0.database_name", databaseResourceName, "name"), - resource.TestCheckResourceAttr(resourceName, "table.0.wildcard", "true"), + resource.TestCheckResourceAttrPair(resourceName, "table.0.database_name", dbName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table.0.name", dbName, "name"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionAll), + resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "0"), ), }, }, }) } -func testAccAWSLakeFormationPermissions_tableWithColumns(t *testing.T) { +func testAccAWSLakeFormationPermissions_tableImplicit(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" roleName := "aws_iam_role.test" @@ -192,61 +270,80 @@ func testAccAWSLakeFormationPermissions_tableWithColumns(t *testing.T) { CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName, "\"event\", \"timestamp\""), + Config: testAccAWSLakeFormationPermissionsConfig_tableImplicit(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), - resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "2"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.1", "timestamp"), - resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), - resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), - ), - }, - { - Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName, "\"timestamp\", \"event\""), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSLakeFormationPermissionsExists(resourceName), - resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), - resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "2"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.1", "timestamp"), - resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), - resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), + resource.TestCheckResourceAttr(resourceName, "table.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "7"), + resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "7"), ), }, + }, + }) +} + +func testAccAWSLakeFormationPermissions_tableMultipleRoles(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lakeformation_permissions.test" + resourceName2 := "aws_lakeformation_permissions.test2" + roleName := "aws_iam_role.test" + roleName2 := "aws_iam_role.test2" + tableName := "aws_glue_catalog_table.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, lakeformation.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, + Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName, "\"timestamp\", \"event\", \"transactionamount\""), + Config: testAccAWSLakeFormationPermissionsConfig_tableMultipleRoles(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), - resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), - resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "3"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.1", "timestamp"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.2", "transactionamount"), - resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), - resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), + resource.TestCheckResourceAttrPair(roleName, "arn", resourceName, "principal"), + resource.TestCheckResourceAttr(resourceName, "table.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "3"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionAlter), + resource.TestCheckResourceAttr(resourceName, "permissions.1", lakeformation.PermissionDelete), + resource.TestCheckResourceAttr(resourceName, "permissions.2", lakeformation.PermissionDescribe), + testAccCheckAWSLakeFormationPermissionsExists(resourceName2), + resource.TestCheckResourceAttrPair(roleName2, "arn", resourceName2, "principal"), + resource.TestCheckResourceAttr(resourceName2, "table.#", "1"), + resource.TestCheckResourceAttrPair(resourceName2, "table.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName2, "table.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName2, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName2, "permissions.0", lakeformation.PermissionSelect), ), }, + }, + }) +} + +func testAccAWSLakeFormationPermissions_tableSelectOnly(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lakeformation_permissions.test" + roleName := "aws_iam_role.test" + tableName := "aws_glue_catalog_table.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, lakeformation.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, + Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_tableWithColumns(rName, "\"event\""), + Config: testAccAWSLakeFormationPermissionsConfig_tableSelectOnly(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), - resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), - resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "1"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), + resource.TestCheckResourceAttrPair(roleName, "arn", resourceName, "principal"), + resource.TestCheckResourceAttr(resourceName, "table.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table.0.name", tableName, "name"), resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), ), @@ -255,11 +352,10 @@ func testAccAWSLakeFormationPermissions_tableWithColumns(t *testing.T) { }) } -func testAccAWSLakeFormationPermissions_implicitTableWithColumnsPermissions(t *testing.T) { +func testAccAWSLakeFormationPermissions_tableSelectPlus(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" roleName := "aws_iam_role.test" - tableName := "aws_glue_catalog_table.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, @@ -268,14 +364,10 @@ func testAccAWSLakeFormationPermissions_implicitTableWithColumnsPermissions(t *t CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_implicitTableWithColumnsPermissions(rName), + Config: testAccAWSLakeFormationPermissionsConfig_tableSelectPlus(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), - resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), - resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.wildcard", "true"), resource.TestCheckResourceAttr(resourceName, "permissions.#", "7"), resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "7"), ), @@ -284,11 +376,10 @@ func testAccAWSLakeFormationPermissions_implicitTableWithColumnsPermissions(t *t }) } -func testAccAWSLakeFormationPermissions_implicitTablePermissions(t *testing.T) { +func testAccAWSLakeFormationPermissions_tableWildcardNoSelect(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" - roleName := "aws_iam_role.test" - tableName := "aws_glue_catalog_table.test" + databaseResourceName := "aws_glue_catalog_database.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, @@ -297,22 +388,19 @@ func testAccAWSLakeFormationPermissions_implicitTablePermissions(t *testing.T) { CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_implicitTablePermissions(rName), + Config: testAccAWSLakeFormationPermissionsConfig_tableWildcardNoSelect(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), - resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), resource.TestCheckResourceAttr(resourceName, "table.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "table.0.database_name", tableName, "database_name"), - resource.TestCheckResourceAttrPair(resourceName, "table.0.name", tableName, "name"), - resource.TestCheckResourceAttr(resourceName, "permissions.#", "7"), - resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "7"), + resource.TestCheckResourceAttrPair(resourceName, "table.0.database_name", databaseResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "table.0.wildcard", "true"), ), }, }, }) } -func testAccAWSLakeFormationPermissions_selectPermissions(t *testing.T) { +func testAccAWSLakeFormationPermissions_tableWildcardSelectOnly(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" roleName := "aws_iam_role.test" @@ -324,19 +412,20 @@ func testAccAWSLakeFormationPermissions_selectPermissions(t *testing.T) { CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_selectPermissions(rName), + Config: testAccAWSLakeFormationPermissionsConfig_tableWildcardSelectOnly(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), - resource.TestCheckResourceAttr(resourceName, "permissions.#", "7"), - resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "7"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), + resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "0"), ), }, }, }) } -func testAccAWSLakeFormationPermissions_tableWildcardPermissions(t *testing.T) { +func testAccAWSLakeFormationPermissions_tableWildcardSelectPlus(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" roleName := "aws_iam_role.test" @@ -348,7 +437,7 @@ func testAccAWSLakeFormationPermissions_tableWildcardPermissions(t *testing.T) { CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_tableWildcardPermissions(rName), + Config: testAccAWSLakeFormationPermissionsConfig_tableWildcardSelectPlus(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), @@ -360,10 +449,11 @@ func testAccAWSLakeFormationPermissions_tableWildcardPermissions(t *testing.T) { }) } -func testAccAWSLakeFormationPermissions_columnWildcardPermissions(t *testing.T) { +func testAccAWSLakeFormationPermissions_twcBasic(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" roleName := "aws_iam_role.test" + tableName := "aws_glue_catalog_table.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, @@ -372,22 +462,74 @@ func testAccAWSLakeFormationPermissions_columnWildcardPermissions(t *testing.T) CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_columnWildcardPermissions(rName), + Config: testAccAWSLakeFormationPermissionsConfig_twcBasic(rName, "\"event\", \"timestamp\""), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), - resource.TestCheckResourceAttr(resourceName, "permissions.#", "7"), - resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "0"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "2"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.1", "timestamp"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), + ), + }, + { + Config: testAccAWSLakeFormationPermissionsConfig_twcBasic(rName, "\"timestamp\", \"event\""), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "2"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.1", "timestamp"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), + ), + }, + { + Config: testAccAWSLakeFormationPermissionsConfig_twcBasic(rName, "\"timestamp\", \"event\", \"transactionamount\""), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "3"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.1", "timestamp"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.2", "transactionamount"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), + ), + }, + { + Config: testAccAWSLakeFormationPermissionsConfig_twcBasic(rName, "\"event\""), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "1"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.0", "event"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), ), }, }, }) } -func testAccAWSLakeFormationPermissions_columnWildcardExcludedColumnsPermissions(t *testing.T) { +func testAccAWSLakeFormationPermissions_twcImplicit(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lakeformation_permissions.test" roleName := "aws_iam_role.test" + tableName := "aws_glue_catalog_table.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, @@ -396,34 +538,116 @@ func testAccAWSLakeFormationPermissions_columnWildcardExcludedColumnsPermissions CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLakeFormationPermissionsConfig_columnWildcardExcludedColumnsPermissions(rName), + Config: testAccAWSLakeFormationPermissionsConfig_twcImplicit(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationPermissionsExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), - resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), - resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "0"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.wildcard", "true"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "7"), + resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "7"), ), }, }, }) } -func testAccCheckAWSLakeFormationPermissionsDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).lakeformationconn +func testAccAWSLakeFormationPermissions_twcWildcardExcludedColumns(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lakeformation_permissions.test" + roleName := "aws_iam_role.test" - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_lakeformation_permissions" { - continue - } + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, lakeformation.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLakeFormationPermissionsConfig_twcWildcardExcludedColumns(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "0"), + ), + }, + }, + }) +} + +func testAccAWSLakeFormationPermissions_twcWildcardSelectOnly(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lakeformation_permissions.test" + roleName := "aws_iam_role.test" + tableName := "aws_glue_catalog_table.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, lakeformation.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLakeFormationPermissionsConfig_twcWildcardSelectOnly(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.database_name", tableName, "database_name"), + resource.TestCheckResourceAttrPair(resourceName, "table_with_columns.0.name", tableName, "name"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.column_names.#", "0"), + resource.TestCheckResourceAttr(resourceName, "table_with_columns.0.wildcard", "true"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "permissions.0", lakeformation.PermissionSelect), + ), + }, + }, + }) +} + +func testAccAWSLakeFormationPermissions_twcWildcardSelectPlus(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lakeformation_permissions.test" + roleName := "aws_iam_role.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(lakeformation.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, lakeformation.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLakeFormationPermissionsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLakeFormationPermissionsConfig_twcWildcardSelectPlus(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLakeFormationPermissionsExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "principal", roleName, "arn"), + resource.TestCheckResourceAttr(resourceName, "permissions.#", "7"), + resource.TestCheckResourceAttr(resourceName, "permissions_with_grant_option.#", "0"), + ), + }, + }, + }) +} + +func testAccCheckAWSLakeFormationPermissionsDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).lakeformationconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_lakeformation_permissions" { + continue + } permCount, err := permissionCountForLakeFormationResource(conn, rs) if err != nil { - return fmt.Errorf("error listing Lake Formation permissions (%s): %w", rs.Primary.ID, err) + return fmt.Errorf("acceptance test: error listing Lake Formation permissions (%s): %w", rs.Primary.ID, err) } if permCount != 0 { - return fmt.Errorf("Lake Formation permissions (%s) still exist: %d", rs.Primary.ID, permCount) + return fmt.Errorf("acceptance test: Lake Formation permissions (%s) still exist: %d", rs.Primary.ID, permCount) } return nil @@ -435,8 +659,9 @@ func testAccCheckAWSLakeFormationPermissionsDestroy(s *terraform.State) error { func testAccCheckAWSLakeFormationPermissionsExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] + if !ok { - return fmt.Errorf("resource not found: %s", resourceName) + return fmt.Errorf("acceptance test: resource not found: %s", resourceName) } conn := testAccProvider.Meta().(*AWSClient).lakeformationconn @@ -444,11 +669,11 @@ func testAccCheckAWSLakeFormationPermissionsExists(resourceName string) resource permCount, err := permissionCountForLakeFormationResource(conn, rs) if err != nil { - return fmt.Errorf("error listing Lake Formation permissions (%s): %w", rs.Primary.ID, err) + return fmt.Errorf("acceptance test: error listing Lake Formation permissions (%s): %w", rs.Primary.ID, err) } if permCount == 0 { - return fmt.Errorf("Lake Formation permissions (%s) do not exist or could not be found", rs.Primary.ID) + return fmt.Errorf("acceptance test: Lake Formation permissions (%s) do not exist or could not be found", rs.Primary.ID) } return nil @@ -463,12 +688,18 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, Resource: &lakeformation.Resource{}, } + noResource := true + if v, ok := rs.Primary.Attributes["catalog_id"]; ok && v != "" { input.CatalogId = aws.String(v) + + noResource = false } if v, ok := rs.Primary.Attributes["catalog_resource"]; ok && v != "" && v == "true" { input.Resource.Catalog = expandLakeFormationCatalogResource() + + noResource = false } if v, ok := rs.Primary.Attributes["data_location.#"]; ok && v != "" && v != "0" { @@ -483,6 +714,8 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, } input.Resource.DataLocation = expandLakeFormationDataLocationResource(tfMap) + + noResource = false } if v, ok := rs.Primary.Attributes["database.#"]; ok && v != "" && v != "0" { @@ -497,6 +730,8 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, } input.Resource.Database = expandLakeFormationDatabaseResource(tfMap) + + noResource = false } tableType := "" @@ -523,6 +758,8 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, } input.Resource.Table = expandLakeFormationTableResource(tfMap) + + noResource = false } if v, ok := rs.Primary.Attributes["table_with_columns.#"]; ok && v != "" && v != "0" { @@ -543,6 +780,13 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, } input.Resource.Table = expandLakeFormationTableWithColumnsResourceAsTable(tfMap) + + noResource = false + } + + if noResource { + // if after read, there is no resource, it has been deleted + return 0, nil } log.Printf("[DEBUG] Reading Lake Formation permissions: %v", input) @@ -565,7 +809,7 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, return resource.RetryableError(err) } - return resource.NonRetryableError(fmt.Errorf("error listing Lake Formation Permissions: %w", err)) + return resource.NonRetryableError(fmt.Errorf("acceptance test: error listing Lake Formation Permissions getting permission count: %w", err)) } return nil }) @@ -592,7 +836,7 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, } if err != nil { - return 0, fmt.Errorf("error listing Lake Formation permissions after retry: %w", err) + return 0, fmt.Errorf("acceptance test: error listing Lake Formation permissions after retry %v: %w", input, err) } columnNames := make([]*string, 0) @@ -610,7 +854,7 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, colCount, err = strconv.Atoi(rs.Primary.Attributes["table_with_columns.0.column_names.#"]) if err != nil { - return 0, fmt.Errorf("could not convert string (%s) Atoi for column_names: %w", rs.Primary.Attributes["table_with_columns.0.column_names.#"], err) + return 0, fmt.Errorf("acceptance test: could not convert string (%s) Atoi for column_names: %w", rs.Primary.Attributes["table_with_columns.0.column_names.#"], err) } } @@ -624,7 +868,7 @@ func permissionCountForLakeFormationResource(conn *lakeformation.LakeFormation, colCount, err = strconv.Atoi(rs.Primary.Attributes["table_with_columns.0.excluded_column_names.#"]) if err != nil { - return 0, fmt.Errorf("could not convert string (%s) Atoi for excluded_column_names: %w", rs.Primary.Attributes["table_with_columns.0.excluded_column_names.#"], err) + return 0, fmt.Errorf("acceptance test: could not convert string (%s) Atoi for excluded_column_names: %w", rs.Primary.Attributes["table_with_columns.0.excluded_column_names.#"], err) } } @@ -643,36 +887,455 @@ func testAccAWSLakeFormationPermissionsConfig_basic(rName string) string { return fmt.Sprintf(` data "aws_partition" "current" {} -resource "aws_iam_role" "test" { - name = %[1]q +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = jsonencode({ + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "glue.${data.aws_partition.current.dns_suffix}" + } + }] + Version = "2012-10-17" + }) +} + +data "aws_caller_identity" "current" {} + +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + +resource "aws_lakeformation_data_lake_settings" "test" { + admins = [data.aws_iam_session_context.current.issuer_arn] +} + +resource "aws_lakeformation_permissions" "test" { + principal = aws_iam_role.test.arn + permissions = ["CREATE_DATABASE"] + catalog_resource = true + + # for consistency, ensure that admins are setup before testing + depends_on = [aws_lakeformation_data_lake_settings.test] +} +`, rName) +} + +func testAccAWSLakeFormationPermissionsConfig_database(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + path = "/" + + assume_role_policy = jsonencode({ + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "glue.${data.aws_partition.current.dns_suffix}" + } + }] + Version = "2012-10-17" + }) +} + +resource "aws_glue_catalog_database" "test" { + name = %[1]q +} + +data "aws_caller_identity" "current" {} + +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + +resource "aws_lakeformation_data_lake_settings" "test" { + admins = [data.aws_iam_session_context.current.issuer_arn] +} + +resource "aws_lakeformation_permissions" "test" { + permissions = ["ALTER", "CREATE_TABLE", "DROP"] + permissions_with_grant_option = ["CREATE_TABLE"] + principal = aws_iam_role.test.arn + + database { + name = aws_glue_catalog_database.test.name + } + + # for consistency, ensure that admins are setup before testing + depends_on = [aws_lakeformation_data_lake_settings.test] +} +`, rName) +} + +func testAccAWSLakeFormationPermissionsConfig_databaseIAMAllowed(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +data "aws_caller_identity" "current" {} + +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + +resource "aws_lakeformation_data_lake_settings" "test" { + admins = [data.aws_iam_session_context.current.issuer_arn] +} + +resource "aws_glue_catalog_database" "test" { + name = %[1]q +} + +resource "aws_glue_catalog_table" "test" { + name = %[1]q + database_name = aws_glue_catalog_database.test.name + + storage_descriptor { + columns { + name = "event" + type = "string" + } + + columns { + name = "timestamp" + type = "date" + } + + columns { + name = "transactionamount" + type = "double" + } + } +} + +resource "aws_lakeformation_permissions" "test" { + permissions = ["ALL"] + principal = "IAM_ALLOWED_PRINCIPALS" + + database { + name = aws_glue_catalog_database.test.name + } + + # for consistency, ensure that admins are setup before testing + depends_on = [aws_lakeformation_data_lake_settings.test] +} +`, rName) +} + +func testAccAWSLakeFormationPermissionsConfig_databaseMultiple(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + path = "/" + + assume_role_policy = jsonencode({ + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "glue.${data.aws_partition.current.dns_suffix}" + } + }] + Version = "2012-10-17" + }) +} + +resource "aws_iam_role" "test2" { + name = "%[1]s-2" + path = "/" + + assume_role_policy = jsonencode({ + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "glue.${data.aws_partition.current.dns_suffix}" + } + }] + Version = "2012-10-17" + }) +} + +resource "aws_glue_catalog_database" "test" { + name = %[1]q +} + +data "aws_caller_identity" "current" {} + +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + +resource "aws_lakeformation_data_lake_settings" "test" { + admins = [data.aws_iam_session_context.current.issuer_arn] +} + +resource "aws_lakeformation_permissions" "test" { + permissions = ["ALTER", "CREATE_TABLE", "DROP"] + permissions_with_grant_option = ["CREATE_TABLE"] + principal = aws_iam_role.test.arn + + database { + name = aws_glue_catalog_database.test.name + } + + # for consistency, ensure that admins are setup before testing + depends_on = [aws_lakeformation_data_lake_settings.test] +} + +resource "aws_lakeformation_permissions" "test2" { + permissions = ["ALTER", "DROP"] + principal = aws_iam_role.test2.arn + + database { + name = aws_glue_catalog_database.test.name + } + + # for consistency, ensure that admins are setup before testing + depends_on = [aws_lakeformation_data_lake_settings.test] +} +`, rName) +} + +func testAccAWSLakeFormationPermissionsConfig_dataLocation(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + path = "/" + + assume_role_policy = jsonencode({ + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "glue.${data.aws_partition.current.dns_suffix}" + } + },{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "s3.${data.aws_partition.current.dns_suffix}" + } + }] + Version = "2012-10-17" + }) +} + +resource "aws_s3_bucket" "test" { + bucket = %[1]q + acl = "private" + force_destroy = true +} + +resource "aws_lakeformation_resource" "test" { + arn = aws_s3_bucket.test.arn + role_arn = aws_iam_role.test.arn +} + +data "aws_caller_identity" "current" {} + +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + +resource "aws_lakeformation_data_lake_settings" "test" { + admins = [data.aws_iam_session_context.current.issuer_arn] +} + +resource "aws_lakeformation_permissions" "test" { + principal = aws_iam_role.test.arn + permissions = ["DATA_LOCATION_ACCESS"] + + data_location { + arn = aws_s3_bucket.test.arn + } + + # for consistency, ensure that admins are setup before testing + depends_on = [aws_lakeformation_data_lake_settings.test] +} +`, rName) +} + +func testAccAWSLakeFormationPermissionsConfig_tableBasic(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + path = "/" + + assume_role_policy = jsonencode({ + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "glue.${data.aws_partition.current.dns_suffix}" + } + }] + Version = "2012-10-17" + }) +} + +resource "aws_glue_catalog_database" "test" { + name = %[1]q +} + +resource "aws_glue_catalog_table" "test" { + name = %[1]q + database_name = aws_glue_catalog_database.test.name +} + +data "aws_caller_identity" "current" {} + +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + +resource "aws_lakeformation_data_lake_settings" "test" { + admins = [data.aws_iam_session_context.current.issuer_arn] +} + +resource "aws_lakeformation_permissions" "test" { + permissions = ["ALTER", "DELETE", "DESCRIBE"] + principal = aws_iam_role.test.arn + + table { + database_name = aws_glue_catalog_table.test.database_name + name = aws_glue_catalog_table.test.name + } + + # for consistency, ensure that admins are setup before testing + depends_on = [aws_lakeformation_data_lake_settings.test] +} +`, rName) +} + +func testAccAWSLakeFormationPermissionsConfig_tableIAMAllowed(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +data "aws_caller_identity" "current" {} + +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + +resource "aws_lakeformation_data_lake_settings" "test" { + admins = [data.aws_iam_session_context.current.issuer_arn] +} + +resource "aws_glue_catalog_database" "test" { + name = %[1]q +} + +resource "aws_glue_catalog_table" "test" { + name = %[1]q + database_name = aws_glue_catalog_database.test.name + + storage_descriptor { + columns { + name = "event" + type = "string" + } + + columns { + name = "timestamp" + type = "date" + } + + columns { + name = "transactionamount" + type = "double" + } + } +} + +resource "aws_lakeformation_permissions" "test" { + permissions = ["ALL"] + principal = "IAM_ALLOWED_PRINCIPALS" + + table { + database_name = aws_glue_catalog_database.test.name + name = aws_glue_catalog_table.test.name + } +} +`, rName) +} + +func testAccAWSLakeFormationPermissionsConfig_tableImplicit(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + path = "/" + + assume_role_policy = jsonencode({ + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "glue.${data.aws_partition.current.dns_suffix}" + } + }] + Version = "2012-10-17" + }) +} + +resource "aws_glue_catalog_database" "test" { + name = %[1]q +} + +resource "aws_glue_catalog_table" "test" { + name = %[1]q + database_name = aws_glue_catalog_database.test.name + + storage_descriptor { + columns { + name = "event" + type = "string" + } + + columns { + name = "timestamp" + type = "date" + } - assume_role_policy = < Date: Thu, 8 Jul 2021 14:30:02 -0400 Subject: [PATCH 1017/1208] r/lakeformation_permissions: Fix bugs --- aws/resource_aws_lakeformation_permissions.go | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_lakeformation_permissions.go b/aws/resource_aws_lakeformation_permissions.go index 93dc46901588..98c454df7edb 100644 --- a/aws/resource_aws_lakeformation_permissions.go +++ b/aws/resource_aws_lakeformation_permissions.go @@ -484,6 +484,18 @@ func resourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta interf if v, ok := d.GetOk("table"); ok && len(v.([]interface{})) > 0 { // since perm list could include TableWithColumns, get the right one for _, perm := range cleanPermissions { + if perm.Resource == nil { + continue + } + + if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnWildcard != nil { + if err := d.Set("table", []interface{}{flattenLakeFormationTableWithColumnsResourceAsTable(perm.Resource.TableWithColumns)}); err != nil { + return fmt.Errorf("error setting table: %w", err) + } + tableSet = true + break + } + if perm.Resource.Table != nil { if err := d.Set("table", []interface{}{flattenLakeFormationTableResource(perm.Resource.Table)}); err != nil { return fmt.Errorf("error setting table: %w", err) @@ -491,6 +503,7 @@ func resourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta interf tableSet = true break } + } } @@ -585,7 +598,7 @@ func resourceAwsLakeFormationPermissionsDelete(d *schema.ResourceData, meta inte _, err = conn.RevokePermissions(input) } - if tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "No permissions revoked. Grantee has no") { + if tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "No permissions revoked. Grantee") { return nil } @@ -616,7 +629,11 @@ func resourceAwsLakeFormationPermissionsDelete(d *schema.ResourceData, meta inte _, err = conn.RevokePermissions(input) } - if err != nil && !tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "No permissions revoked. Grantee has no") { + if tfawserr.ErrMessageContains(err, lakeformation.ErrCodeInvalidInputException, "No permissions revoked. Grantee") { + return nil + } + + if err != nil { return fmt.Errorf("unable to revoke LakeFormation Permissions (input: %v): %w", input, err) } @@ -844,6 +861,33 @@ func flattenLakeFormationTableWithColumnsResource(apiObject *lakeformation.Table return tfMap } +// This only happens in very specific situations: +// (Select) TWC + ColumnWildcard = (Select) Table +// (Select) TWC + ColumnWildcard + ALL_TABLES = (Select) Table + TableWildcard +func flattenLakeFormationTableWithColumnsResourceAsTable(apiObject *lakeformation.TableWithColumnsResource) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.CatalogId; v != nil { + tfMap["catalog_id"] = aws.StringValue(v) + } + + if v := apiObject.DatabaseName; v != nil { + tfMap["database_name"] = aws.StringValue(v) + } + + if v := apiObject.Name; v != nil && aws.StringValue(v) == tflakeformation.TableNameAllTables && apiObject.ColumnWildcard != nil { + tfMap["wildcard"] = true + } else if v := apiObject.Name; v != nil { + tfMap["name"] = aws.StringValue(v) + } + + return tfMap +} + func flattenLakeFormationPermissions(apiObjects []*lakeformation.PrincipalResourcePermissions) []string { if apiObjects == nil { return nil From 2199d55c8390d720be0ce28674e431d73bd10ab0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:30:34 -0400 Subject: [PATCH 1018/1208] tests/lakeformation_data_lake_setting: Rework for STS --- ...s_lakeformation_data_lake_settings_test.go | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_lakeformation_data_lake_settings_test.go b/aws/resource_aws_lakeformation_data_lake_settings_test.go index 3c3ec5375ae2..fcbfc1cb6366 100644 --- a/aws/resource_aws_lakeformation_data_lake_settings_test.go +++ b/aws/resource_aws_lakeformation_data_lake_settings_test.go @@ -12,7 +12,6 @@ import ( ) func testAccAWSLakeFormationDataLakeSettings_basic(t *testing.T) { - callerIdentityName := "data.aws_caller_identity.current" resourceName := "aws_lakeformation_data_lake_settings.test" resource.Test(t, resource.TestCase{ @@ -25,9 +24,9 @@ func testAccAWSLakeFormationDataLakeSettings_basic(t *testing.T) { Config: testAccAWSLakeFormationDataLakeSettingsConfig_basic, Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationDataLakeSettingsExists(resourceName), - resource.TestCheckResourceAttrPair(resourceName, "catalog_id", callerIdentityName, "account_id"), + resource.TestCheckResourceAttrPair(resourceName, "catalog_id", "data.aws_caller_identity.current", "account_id"), resource.TestCheckResourceAttr(resourceName, "admins.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "admins.0", callerIdentityName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "admins.0", "data.aws_iam_session_context.current", "issuer_arn"), ), }, }, @@ -56,7 +55,6 @@ func testAccAWSLakeFormationDataLakeSettings_disappears(t *testing.T) { } func testAccAWSLakeFormationDataLakeSettings_withoutCatalogId(t *testing.T) { - callerIdentityName := "data.aws_caller_identity.current" resourceName := "aws_lakeformation_data_lake_settings.test" resource.Test(t, resource.TestCase{ @@ -70,7 +68,7 @@ func testAccAWSLakeFormationDataLakeSettings_withoutCatalogId(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSLakeFormationDataLakeSettingsExists(resourceName), resource.TestCheckResourceAttr(resourceName, "admins.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "admins.0", callerIdentityName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "admins.0", "data.aws_iam_session_context.current", "issuer_arn"), ), }, }, @@ -137,6 +135,10 @@ func testAccCheckAWSLakeFormationDataLakeSettingsExists(resourceName string) res const testAccAWSLakeFormationDataLakeSettingsConfig_basic = ` data "aws_caller_identity" "current" {} +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + resource "aws_lakeformation_data_lake_settings" "test" { catalog_id = data.aws_caller_identity.current.account_id @@ -150,7 +152,7 @@ resource "aws_lakeformation_data_lake_settings" "test" { permissions = ["ALL"] } - admins = [data.aws_caller_identity.current.arn] + admins = [data.aws_iam_session_context.current.issuer_arn] trusted_resource_owners = [data.aws_caller_identity.current.account_id] } ` @@ -158,7 +160,11 @@ resource "aws_lakeformation_data_lake_settings" "test" { const testAccAWSLakeFormationDataLakeSettingsConfig_withoutCatalogId = ` data "aws_caller_identity" "current" {} +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + resource "aws_lakeformation_data_lake_settings" "test" { - admins = [data.aws_caller_identity.current.arn] + admins = [data.aws_iam_session_context.current.issuer_arn] } ` From ab8c63fc7bd50a6bc2789c91910b1f3dd4bedcd2 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:31:30 -0400 Subject: [PATCH 1019/1208] i/lakeformation: Reduce permissions delete TO --- aws/internal/service/lakeformation/waiter/waiter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/internal/service/lakeformation/waiter/waiter.go b/aws/internal/service/lakeformation/waiter/waiter.go index 80e66a211594..ba7343e01abc 100644 --- a/aws/internal/service/lakeformation/waiter/waiter.go +++ b/aws/internal/service/lakeformation/waiter/waiter.go @@ -9,7 +9,7 @@ import ( const ( PermissionsReadyTimeout = 1 * time.Minute - PermissionsDeleteRetryTimeout = 3 * time.Minute + PermissionsDeleteRetryTimeout = 30 * time.Second StatusAvailable = "AVAILABLE" StatusNotFound = "NOT FOUND" From ddedf2ebc25c2973128ba2de81a82934f54df86f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:32:12 -0400 Subject: [PATCH 1020/1208] i/lakeformation: Ensure same principal --- aws/internal/service/lakeformation/waiter/status.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aws/internal/service/lakeformation/waiter/status.go b/aws/internal/service/lakeformation/waiter/status.go index fca281e92165..80beaa016a8f 100644 --- a/aws/internal/service/lakeformation/waiter/status.go +++ b/aws/internal/service/lakeformation/waiter/status.go @@ -3,6 +3,7 @@ package waiter import ( "fmt" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/lakeformation" "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -19,6 +20,10 @@ func PermissionsStatus(conn *lakeformation.LakeFormation, input *lakeformation.L continue } + if aws.StringValue(input.Principal.DataLakePrincipalIdentifier) != aws.StringValue(permission.Principal.DataLakePrincipalIdentifier) { + continue + } + permissions = append(permissions, permission) } return !lastPage From 1a3c9faad1b7deb112ec439ccb74b4fded8338d8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:33:09 -0400 Subject: [PATCH 1021/1208] i/lakeformation: Filter out different principals --- aws/internal/service/lakeformation/filter.go | 46 +++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/aws/internal/service/lakeformation/filter.go b/aws/internal/service/lakeformation/filter.go index 916df407ebd1..1d53fb8fd6d5 100644 --- a/aws/internal/service/lakeformation/filter.go +++ b/aws/internal/service/lakeformation/filter.go @@ -8,12 +8,6 @@ import ( "github.com/aws/aws-sdk-go/service/lakeformation" ) -const ( - TableNameAllTables = "ALL_TABLES" - TableTypeTable = "Table" - TableTypeTableWithColumns = "TableWithColumns" -) - func FilterPermissions(input *lakeformation.ListPermissionsInput, tableType string, columnNames []*string, excludedColumnNames []*string, columnWildcard bool, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { // For most Lake Formation resources, filtering within the provider is unnecessary. The input // contains everything for AWS to give you back exactly what you want. However, many challenges @@ -29,29 +23,29 @@ func FilterPermissions(input *lakeformation.ListPermissionsInput, tableType stri // permissions in the special cases to avoid extra permissions being included. if input.Resource.Catalog != nil { - return FilterLakeFormationCatalogPermissions(allPermissions) + return FilterLakeFormationCatalogPermissions(input.Principal.DataLakePrincipalIdentifier, allPermissions) } if input.Resource.DataLocation != nil { - return FilterLakeFormationDataLocationPermissions(allPermissions) + return FilterLakeFormationDataLocationPermissions(input.Principal.DataLakePrincipalIdentifier, allPermissions) } if input.Resource.Database != nil { - return FilterLakeFormationDatabasePermissions(allPermissions) + return FilterLakeFormationDatabasePermissions(input.Principal.DataLakePrincipalIdentifier, allPermissions) } if tableType == TableTypeTableWithColumns { - return FilterLakeFormationTableWithColumnsPermissions(input.Resource.Table, columnNames, excludedColumnNames, columnWildcard, allPermissions) + return FilterLakeFormationTableWithColumnsPermissions(input.Principal.DataLakePrincipalIdentifier, input.Resource.Table, columnNames, excludedColumnNames, columnWildcard, allPermissions) } if input.Resource.Table != nil || tableType == TableTypeTable { - return FilterLakeFormationTablePermissions(input.Resource.Table, allPermissions) + return FilterLakeFormationTablePermissions(input.Principal.DataLakePrincipalIdentifier, input.Resource.Table, allPermissions) } return nil } -func FilterLakeFormationTablePermissions(table *lakeformation.TableResource, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { +func FilterLakeFormationTablePermissions(principal *string, table *lakeformation.TableResource, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { // CREATE PERMS (in) = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on Table, Name = (Table Name) // LIST PERMS (out) = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) // LIST PERMS (out) = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard @@ -63,6 +57,10 @@ func FilterLakeFormationTablePermissions(table *lakeformation.TableResource, all var cleanPermissions []*lakeformation.PrincipalResourcePermissions for _, perm := range allPermissions { + if aws.StringValue(principal) != aws.StringValue(perm.Principal.DataLakePrincipalIdentifier) { + continue + } + if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnWildcard != nil { if aws.StringValue(perm.Resource.TableWithColumns.Name) == aws.StringValue(table.Name) || (table.TableWildcard != nil && aws.StringValue(perm.Resource.TableWithColumns.Name) == TableNameAllTables) { if len(perm.Permissions) > 0 && aws.StringValue(perm.Permissions[0]) == lakeformation.PermissionSelect { @@ -94,7 +92,7 @@ func FilterLakeFormationTablePermissions(table *lakeformation.TableResource, all return cleanPermissions } -func FilterLakeFormationTableWithColumnsPermissions(twc *lakeformation.TableResource, columnNames []*string, excludedColumnNames []*string, columnWildcard bool, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { +func FilterLakeFormationTableWithColumnsPermissions(principal *string, twc *lakeformation.TableResource, columnNames []*string, excludedColumnNames []*string, columnWildcard bool, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { // CREATE PERMS (in) = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT, SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard // LIST PERMS (out) = ALL, ALTER, DELETE, DESCRIBE, DROP, INSERT on Table, Name = (Table Name) // LIST PERMS (out) = SELECT on TableWithColumns, Name = (Table Name), ColumnWildcard @@ -102,6 +100,10 @@ func FilterLakeFormationTableWithColumnsPermissions(twc *lakeformation.TableReso var cleanPermissions []*lakeformation.PrincipalResourcePermissions for _, perm := range allPermissions { + if aws.StringValue(principal) != aws.StringValue(perm.Principal.DataLakePrincipalIdentifier) { + continue + } + if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnNames != nil { if StringSlicesEqualIgnoreOrder(perm.Resource.TableWithColumns.ColumnNames, columnNames) { cleanPermissions = append(cleanPermissions, perm) @@ -130,10 +132,14 @@ func FilterLakeFormationTableWithColumnsPermissions(twc *lakeformation.TableReso return cleanPermissions } -func FilterLakeFormationCatalogPermissions(allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { +func FilterLakeFormationCatalogPermissions(principal *string, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { var cleanPermissions []*lakeformation.PrincipalResourcePermissions for _, perm := range allPermissions { + if aws.StringValue(principal) != aws.StringValue(perm.Principal.DataLakePrincipalIdentifier) { + continue + } + if perm.Resource.Catalog != nil { cleanPermissions = append(cleanPermissions, perm) } @@ -142,10 +148,14 @@ func FilterLakeFormationCatalogPermissions(allPermissions []*lakeformation.Princ return cleanPermissions } -func FilterLakeFormationDataLocationPermissions(allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { +func FilterLakeFormationDataLocationPermissions(principal *string, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { var cleanPermissions []*lakeformation.PrincipalResourcePermissions for _, perm := range allPermissions { + if aws.StringValue(principal) != aws.StringValue(perm.Principal.DataLakePrincipalIdentifier) { + continue + } + if perm.Resource.DataLocation != nil { cleanPermissions = append(cleanPermissions, perm) } @@ -154,10 +164,14 @@ func FilterLakeFormationDataLocationPermissions(allPermissions []*lakeformation. return cleanPermissions } -func FilterLakeFormationDatabasePermissions(allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { +func FilterLakeFormationDatabasePermissions(principal *string, allPermissions []*lakeformation.PrincipalResourcePermissions) []*lakeformation.PrincipalResourcePermissions { var cleanPermissions []*lakeformation.PrincipalResourcePermissions for _, perm := range allPermissions { + if aws.StringValue(principal) != aws.StringValue(perm.Principal.DataLakePrincipalIdentifier) { + continue + } + if perm.Resource.Database != nil { cleanPermissions = append(cleanPermissions, perm) } From db714c3a32299f7a71d9810d400bf8a53af1480f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:34:17 -0400 Subject: [PATCH 1022/1208] tests/d/lakeformation_data_lake_settings: Rework for STS --- ...ource_aws_lakeformation_data_lake_settings_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/aws/data_source_aws_lakeformation_data_lake_settings_test.go b/aws/data_source_aws_lakeformation_data_lake_settings_test.go index fa1fe4ab7d4a..09b424fe346a 100644 --- a/aws/data_source_aws_lakeformation_data_lake_settings_test.go +++ b/aws/data_source_aws_lakeformation_data_lake_settings_test.go @@ -8,7 +8,6 @@ import ( ) func testAccAWSLakeFormationDataLakeSettingsDataSource_basic(t *testing.T) { - callerIdentityName := "data.aws_caller_identity.current" resourceName := "data.aws_lakeformation_data_lake_settings.test" resource.Test(t, resource.TestCase{ @@ -20,9 +19,9 @@ func testAccAWSLakeFormationDataLakeSettingsDataSource_basic(t *testing.T) { { Config: testAccAWSLakeFormationDataLakeSettingsDataSourceConfig_basic, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrPair(resourceName, "catalog_id", callerIdentityName, "account_id"), + resource.TestCheckResourceAttrPair(resourceName, "catalog_id", "data.aws_caller_identity.current", "account_id"), resource.TestCheckResourceAttr(resourceName, "admins.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "admins.0", callerIdentityName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "admins.0", "data.aws_iam_session_context.current", "issuer_arn"), ), }, }, @@ -32,9 +31,13 @@ func testAccAWSLakeFormationDataLakeSettingsDataSource_basic(t *testing.T) { const testAccAWSLakeFormationDataLakeSettingsDataSourceConfig_basic = ` data "aws_caller_identity" "current" {} +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.current.arn +} + resource "aws_lakeformation_data_lake_settings" "test" { catalog_id = data.aws_caller_identity.current.account_id - admins = [data.aws_caller_identity.current.arn] + admins = [data.aws_iam_session_context.current.issuer_arn] } data "aws_lakeformation_data_lake_settings" "test" { From 259c816a79ebcbd833120e67463f4f64569e3b11 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:34:47 -0400 Subject: [PATCH 1023/1208] tests/d/lakeformation_permissions: Rework for STS --- ...urce_aws_lakeformation_permissions_test.go | 168 +++++++++--------- 1 file changed, 82 insertions(+), 86 deletions(-) diff --git a/aws/data_source_aws_lakeformation_permissions_test.go b/aws/data_source_aws_lakeformation_permissions_test.go index fe111e051e23..47d2a77ca5af 100644 --- a/aws/data_source_aws_lakeformation_permissions_test.go +++ b/aws/data_source_aws_lakeformation_permissions_test.go @@ -148,28 +148,28 @@ data "aws_partition" "current" {} resource "aws_iam_role" "test" { name = %[1]q + path = "/" - assume_role_policy = < Date: Thu, 8 Jul 2021 14:35:15 -0400 Subject: [PATCH 1024/1208] d/lakeformation_permissions: Fix bugs --- aws/data_source_aws_lakeformation_permissions.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/aws/data_source_aws_lakeformation_permissions.go b/aws/data_source_aws_lakeformation_permissions.go index 9a9c48e777c9..97963b217158 100644 --- a/aws/data_source_aws_lakeformation_permissions.go +++ b/aws/data_source_aws_lakeformation_permissions.go @@ -277,6 +277,18 @@ func dataSourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta inte if v, ok := d.GetOk("table"); ok && len(v.([]interface{})) > 0 { // since perm list could include TableWithColumns, get the right one for _, perm := range cleanPermissions { + if perm.Resource == nil { + continue + } + + if perm.Resource.TableWithColumns != nil && perm.Resource.TableWithColumns.ColumnWildcard != nil { + if err := d.Set("table", []interface{}{flattenLakeFormationTableWithColumnsResourceAsTable(perm.Resource.TableWithColumns)}); err != nil { + return fmt.Errorf("error setting table: %w", err) + } + tableSet = true + break + } + if perm.Resource.Table != nil { if err := d.Set("table", []interface{}{flattenLakeFormationTableResource(perm.Resource.Table)}); err != nil { return fmt.Errorf("error setting table: %w", err) From 8abe9aa435ee949a8de211ac01e64f2af44ad886 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:38:45 -0400 Subject: [PATCH 1025/1208] r/lakeformation_permissions: Add changelog --- .changelog/20108.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/20108.txt diff --git a/.changelog/20108.txt b/.changelog/20108.txt new file mode 100644 index 000000000000..5edc7273ce89 --- /dev/null +++ b/.changelog/20108.txt @@ -0,0 +1,7 @@ +```release-note:bug +resource/aws_lakeformation_permissions: Fix various problems with permissions including select-only +``` + +```release-note:bug +data-source/aws_lakeformation_permissions: Fix various problems with permissions including select-only +``` \ No newline at end of file From 08bba8df4db7b24c6c4ea0fd798611957116f319 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:42:56 -0400 Subject: [PATCH 1026/1208] r/lakeformation_permissions: Linty McLintface --- aws/resource_aws_lakeformation_permissions_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_lakeformation_permissions_test.go b/aws/resource_aws_lakeformation_permissions_test.go index 8fcbb28dcc4d..1299494e0df1 100644 --- a/aws/resource_aws_lakeformation_permissions_test.go +++ b/aws/resource_aws_lakeformation_permissions_test.go @@ -2013,7 +2013,7 @@ resource "aws_lakeformation_permissions" "test" { table_with_columns { database_name = aws_glue_catalog_table.test.database_name name = aws_glue_catalog_table.test.name - wildcard = true + wildcard = true } # for consistency, ensure that admins are setup before testing From 0538764c74c173f82a5fb2530dcc3bf65b9cce64 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:45:06 -0400 Subject: [PATCH 1027/1208] r/lakeformation_permissions: Linty McLintface --- aws/resource_aws_lakeformation_permissions_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_lakeformation_permissions_test.go b/aws/resource_aws_lakeformation_permissions_test.go index 1299494e0df1..70803f348e5e 100644 --- a/aws/resource_aws_lakeformation_permissions_test.go +++ b/aws/resource_aws_lakeformation_permissions_test.go @@ -1015,7 +1015,7 @@ resource "aws_glue_catalog_table" "test" { resource "aws_lakeformation_permissions" "test" { permissions = ["ALL"] principal = "IAM_ALLOWED_PRINCIPALS" - + database { name = aws_glue_catalog_database.test.name } @@ -1261,7 +1261,7 @@ resource "aws_glue_catalog_table" "test" { resource "aws_lakeformation_permissions" "test" { permissions = ["ALL"] principal = "IAM_ALLOWED_PRINCIPALS" - + table { database_name = aws_glue_catalog_database.test.name name = aws_glue_catalog_table.test.name From ede6a1a40bc820a72bc1a7dc0842412371d7666c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:52:03 -0400 Subject: [PATCH 1028/1208] r/lakeformation_permissions: Linty McLintface --- aws/resource_aws_lakeformation_permissions_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_lakeformation_permissions_test.go b/aws/resource_aws_lakeformation_permissions_test.go index 70803f348e5e..57db85a834a0 100644 --- a/aws/resource_aws_lakeformation_permissions_test.go +++ b/aws/resource_aws_lakeformation_permissions_test.go @@ -1090,8 +1090,8 @@ resource "aws_lakeformation_permissions" "test" { } resource "aws_lakeformation_permissions" "test2" { - permissions = ["ALTER", "DROP"] - principal = aws_iam_role.test2.arn + permissions = ["ALTER", "DROP"] + principal = aws_iam_role.test2.arn database { name = aws_glue_catalog_database.test.name @@ -1118,13 +1118,13 @@ resource "aws_iam_role" "test" { Principal = { Service = "glue.${data.aws_partition.current.dns_suffix}" } - },{ + }, { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "s3.${data.aws_partition.current.dns_suffix}" } - }] + }] Version = "2012-10-17" }) } From 9c50c5cb97f2a9ef58003e7062eca14c97ccb74f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:53:58 -0400 Subject: [PATCH 1029/1208] docs/r/lakeformation_permissions: Curse you trailing whitespace --- website/docs/r/lakeformation_permissions.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index d6b116689bf3..a73c9e6bf31f 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -39,7 +39,7 @@ resource "aws_lakeformation_data_lake_settings" "test" { To remove existing `IAMAllowedPrincipals` permissions, use the [AWS Lake Formation Console](https://console.aws.amazon.com/lakeformation/) or [AWS CLI](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lakeformation/batch-revoke-permissions.html). -`IAMAllowedPrincipals` is a hook to maintain backwards compatibility with AWS Glue. `IAMAllowedPrincipals` is a pseudo-entity group that acts like a Lake Formation principal. The group includes any IAM users and roles that are allowed access to your Data Catalog resources by your IAM policies. +`IAMAllowedPrincipals` is a hook to maintain backwards compatibility with AWS Glue. `IAMAllowedPrincipals` is a pseudo-entity group that acts like a Lake Formation principal. The group includes any IAM users and roles that are allowed access to your Data Catalog resources by your IAM policies. This is Lake Formation's default behavior: From b60dbffe10e0cb1a53b18747fa42a4dd3f3f6e19 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 14:55:38 -0400 Subject: [PATCH 1030/1208] docs/r/lakeformation_permissions: Clarify behavior --- website/docs/r/lakeformation_permissions.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index a73c9e6bf31f..fa119544576b 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -85,7 +85,7 @@ The resulting permissions depend on whether the table had `IAMAllowedPrincipals` | Result With IAP | Result Without IAP | | ---- | ---- | -| `SELECT` on table with columns with column wildcard (i.e., all columns) | `SELECT` on `"event"` (as expected) | +| `SELECT` column wildcard (i.e., all columns) | `SELECT` on `"event"` (as expected) | ## Using Lake Formation Permissions From b880067a1fc07c1d3ccf7b2df319e25996fef593 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 15:00:32 -0400 Subject: [PATCH 1031/1208] docs/r/lakeformation_permissions: Heading --- website/docs/r/lakeformation_permissions.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index fa119544576b..7d98355ec117 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -48,7 +48,7 @@ This is Lake Formation's default behavior: For more details, see [Changing the Default Security Settings for Your Data Lake](https://docs.aws.amazon.com/lake-formation/latest/dg/change-settings.html). -### Example Problem Using `IAMAllowedPrincipals` +### Problem Using `IAMAllowedPrincipals` AWS does not support combining `IAMAllowedPrincipals` permissions and non-`IAMAllowedPrincipals` permissions. Doing so results in unexpected permissions. For example, this configuration grants a user `SELECT` on a column in a table. From ccddd60945c379e41167259fa62cf402a6a7c1ef Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 12:43:42 -0400 Subject: [PATCH 1032/1208] r/aws_dx_gateway_association: Use internal finder and waiter packages. --- .../service/directconnect/finder/finder.go | 9 + aws/resource_aws_dx_gateway_association.go | 213 +++++++----------- ...urce_aws_dx_gateway_association_migrate.go | 17 +- ...rce_aws_dx_gateway_association_proposal.go | 4 +- ...ws_dx_gateway_association_proposal_test.go | 2 +- ...esource_aws_dx_gateway_association_test.go | 91 ++++---- 6 files changed, 141 insertions(+), 195 deletions(-) diff --git a/aws/internal/service/directconnect/finder/finder.go b/aws/internal/service/directconnect/finder/finder.go index 9a97f05d34d1..a688455108f5 100644 --- a/aws/internal/service/directconnect/finder/finder.go +++ b/aws/internal/service/directconnect/finder/finder.go @@ -23,6 +23,15 @@ func GatewayAssociationByDirectConnectGatewayIDAndAssociatedGatewayID(conn *dire return GatewayAssociation(conn, input) } +func GatewayAssociationByDirectConnectGatewayIDAndVirtualGatewayID(conn *directconnect.DirectConnect, directConnectGatewayID, virtualGatewayID string) (*directconnect.GatewayAssociation, error) { + input := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ + DirectConnectGatewayId: aws.String(directConnectGatewayID), + VirtualGatewayId: aws.String(virtualGatewayID), + } + + return GatewayAssociation(conn, input) +} + func GatewayAssociation(conn *directconnect.DirectConnect, input *directconnect.DescribeDirectConnectGatewayAssociationsInput) (*directconnect.GatewayAssociation, error) { output, err := conn.DescribeDirectConnectGatewayAssociations(input) diff --git a/aws/resource_aws_dx_gateway_association.go b/aws/resource_aws_dx_gateway_association.go index 19ba70b50bf0..a11e6276b916 100644 --- a/aws/resource_aws_dx_gateway_association.go +++ b/aws/resource_aws_dx_gateway_association.go @@ -9,13 +9,11 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directconnect" "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + tfdirectconnect "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/waiter" -) - -const ( - gatewayAssociationStateDeleted = "deleted" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsDxGatewayAssociation() *schema.Resource { @@ -114,60 +112,57 @@ func resourceAwsDxGatewayAssociation() *schema.Resource { func resourceAwsDxGatewayAssociationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).dxconn - dxgwId := d.Get("dx_gateway_id").(string) - gwIdRaw, gwIdOk := d.GetOk("associated_gateway_id") - gwAcctIdRaw, gwAcctIdOk := d.GetOk("associated_gateway_owner_account_id") - proposalIdRaw, proposalIdOk := d.GetOk("proposal_id") + var associationID string + directConnectGatewayID := d.Get("dx_gateway_id").(string) - if gwAcctIdOk || proposalIdOk { - // Cross-account association. - if !(gwAcctIdOk && proposalIdOk) { - return fmt.Errorf("associated_gateway_owner_account_id and proposal_id must be configured") + if associatedGatewayOwnerAccount := d.Get("associated_gateway_owner_account_id").(string); associatedGatewayOwnerAccount != "" { + proposalID := d.Get("proposal_id").(string) + input := &directconnect.AcceptDirectConnectGatewayAssociationProposalInput{ + AssociatedGatewayOwnerAccount: aws.String(associatedGatewayOwnerAccount), + DirectConnectGatewayId: aws.String(directConnectGatewayID), + ProposalId: aws.String(proposalID), } - } else if !gwIdOk { - return fmt.Errorf("either associated_gateway_owner_account_id and proposal_id, or associated_gateway_id, must be configured") - } - associationId := "" - if gwAcctIdOk { - req := &directconnect.AcceptDirectConnectGatewayAssociationProposalInput{ - AssociatedGatewayOwnerAccount: aws.String(gwAcctIdRaw.(string)), - DirectConnectGatewayId: aws.String(dxgwId), - OverrideAllowedPrefixesToDirectConnectGateway: expandDxRouteFilterPrefixes(d.Get("allowed_prefixes").(*schema.Set)), - ProposalId: aws.String(proposalIdRaw.(string)), + if v, ok := d.GetOk("allowed_prefixes"); ok && v.(*schema.Set).Len() > 0 { + input.OverrideAllowedPrefixesToDirectConnectGateway = expandDirectConnectRouteFilterPrefixes(v.(*schema.Set).List()) } - log.Printf("[DEBUG] Accepting Direct Connect gateway association proposal: %#v", req) - resp, err := conn.AcceptDirectConnectGatewayAssociationProposal(req) + log.Printf("[DEBUG] Accepting Direct Connect Gateway Association Proposal: %s", input) + output, err := conn.AcceptDirectConnectGatewayAssociationProposal(input) + if err != nil { - return fmt.Errorf("error accepting Direct Connect gateway association proposal: %s", err) + return fmt.Errorf("error accepting Direct Connect Gateway Association Proposal (%s): %w", proposalID, err) } // For historical reasons the resource ID isn't set to the association ID returned from the API. - associationId = aws.StringValue(resp.DirectConnectGatewayAssociation.AssociationId) - d.SetId(dxGatewayAssociationId(dxgwId, aws.StringValue(resp.DirectConnectGatewayAssociation.AssociatedGateway.Id))) + associationID = aws.StringValue(output.DirectConnectGatewayAssociation.AssociationId) + d.SetId(tfdirectconnect.GatewayAssociationCreateResourceID(directConnectGatewayID, aws.StringValue(output.DirectConnectGatewayAssociation.AssociatedGateway.Id))) } else { - gwId := gwIdRaw.(string) + associatedGatewayID := d.Get("associated_gateway_id").(string) + input := &directconnect.CreateDirectConnectGatewayAssociationInput{ + DirectConnectGatewayId: aws.String(directConnectGatewayID), + GatewayId: aws.String(associatedGatewayID), + } - req := &directconnect.CreateDirectConnectGatewayAssociationInput{ - AddAllowedPrefixesToDirectConnectGateway: expandDxRouteFilterPrefixes(d.Get("allowed_prefixes").(*schema.Set)), - DirectConnectGatewayId: aws.String(dxgwId), - GatewayId: aws.String(gwId), + if v, ok := d.GetOk("allowed_prefixes"); ok && v.(*schema.Set).Len() > 0 { + input.AddAllowedPrefixesToDirectConnectGateway = expandDirectConnectRouteFilterPrefixes(v.(*schema.Set).List()) } - log.Printf("[DEBUG] Creating Direct Connect gateway association: %#v", req) - resp, err := conn.CreateDirectConnectGatewayAssociation(req) + log.Printf("[DEBUG] Creating Direct Connect Gateway Association: %s", input) + output, err := conn.CreateDirectConnectGatewayAssociation(input) + if err != nil { - return fmt.Errorf("error creating Direct Connect gateway association: %s", err) + return fmt.Errorf("error creating Direct Connect Gateway Association (%s/%s): %w", directConnectGatewayID, associatedGatewayID, err) } // For historical reasons the resource ID isn't set to the association ID returned from the API. - associationId = aws.StringValue(resp.DirectConnectGatewayAssociation.AssociationId) - d.SetId(dxGatewayAssociationId(dxgwId, gwId)) + associationID = aws.StringValue(output.DirectConnectGatewayAssociation.AssociationId) + d.SetId(tfdirectconnect.GatewayAssociationCreateResourceID(directConnectGatewayID, associatedGatewayID)) } - d.Set("dx_gateway_association_id", associationId) - if _, err := waiter.GatewayAssociationCreated(conn, associationId, d.Timeout(schema.TimeoutCreate)); err != nil { + d.Set("dx_gateway_association_id", associationID) + + if _, err := waiter.GatewayAssociationCreated(conn, associationID, d.Timeout(schema.TimeoutCreate)); err != nil { return fmt.Errorf("error waiting for Direct Connect Gateway Association (%s) to create: %w", d.Id(), err) } @@ -177,30 +172,30 @@ func resourceAwsDxGatewayAssociationCreate(d *schema.ResourceData, meta interfac func resourceAwsDxGatewayAssociationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).dxconn - associationId := d.Get("dx_gateway_association_id").(string) - assocRaw, state, err := dxGatewayAssociationStateRefresh(conn, associationId)() - if err != nil { - return fmt.Errorf("error reading Direct Connect gateway association (%s): %s", d.Id(), err) - } - if state == gatewayAssociationStateDeleted { - log.Printf("[WARN] Direct Connect gateway association (%s) not found, removing from state", d.Id()) + associationID := d.Get("dx_gateway_association_id").(string) + + output, err := finder.GatewayAssociationByID(conn, associationID) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Direct Connect Gateway Association (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - assoc := assocRaw.(*directconnect.GatewayAssociation) - - err = d.Set("allowed_prefixes", flattenDxRouteFilterPrefixes(assoc.AllowedPrefixesToDirectConnectGateway)) if err != nil { - return fmt.Errorf("error setting allowed_prefixes: %s", err) + return fmt.Errorf("error reading Direct Connect Gateway Association (%s): %w", d.Id(), err) + } + + if err := d.Set("allowed_prefixes", flattenDirectConnectRouteFilterPrefixes(output.AllowedPrefixesToDirectConnectGateway)); err != nil { + return fmt.Errorf("error setting allowed_prefixes: %w", err) } - d.Set("associated_gateway_id", assoc.AssociatedGateway.Id) - d.Set("associated_gateway_owner_account_id", assoc.AssociatedGateway.OwnerAccount) - d.Set("associated_gateway_type", assoc.AssociatedGateway.Type) - d.Set("dx_gateway_association_id", assoc.AssociationId) - d.Set("dx_gateway_id", assoc.DirectConnectGatewayId) - d.Set("dx_gateway_owner_account_id", assoc.DirectConnectGatewayOwnerAccount) + d.Set("associated_gateway_id", output.AssociatedGateway.Id) + d.Set("associated_gateway_owner_account_id", output.AssociatedGateway.OwnerAccount) + d.Set("associated_gateway_type", output.AssociatedGateway.Type) + d.Set("dx_gateway_association_id", output.AssociationId) + d.Set("dx_gateway_id", output.DirectConnectGatewayId) + d.Set("dx_gateway_owner_account_id", output.DirectConnectGatewayOwnerAccount) return nil } @@ -208,30 +203,31 @@ func resourceAwsDxGatewayAssociationRead(d *schema.ResourceData, meta interface{ func resourceAwsDxGatewayAssociationUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).dxconn - if d.HasChange("allowed_prefixes") { - associationId := d.Get("dx_gateway_association_id").(string) + associationID := d.Get("dx_gateway_association_id").(string) + input := &directconnect.UpdateDirectConnectGatewayAssociationInput{ + AssociationId: aws.String(associationID), + } - oraw, nraw := d.GetChange("allowed_prefixes") - o := oraw.(*schema.Set) - n := nraw.(*schema.Set) - del := o.Difference(n) - add := n.Difference(o) + oraw, nraw := d.GetChange("allowed_prefixes") + o, n := oraw.(*schema.Set), nraw.(*schema.Set) - req := &directconnect.UpdateDirectConnectGatewayAssociationInput{ - AddAllowedPrefixesToDirectConnectGateway: expandDxRouteFilterPrefixes(add), - AssociationId: aws.String(associationId), - RemoveAllowedPrefixesToDirectConnectGateway: expandDxRouteFilterPrefixes(del), - } + if add := n.Difference(o); add.Len() > 0 { + input.AddAllowedPrefixesToDirectConnectGateway = expandDirectConnectRouteFilterPrefixes(add.List()) + } - log.Printf("[DEBUG] Updating Direct Connect gateway association: %#v", req) - _, err := conn.UpdateDirectConnectGatewayAssociation(req) - if err != nil { - return fmt.Errorf("error updating Direct Connect gateway association (%s): %s", d.Id(), err) - } + if del := o.Difference(n); del.Len() > 0 { + input.RemoveAllowedPrefixesToDirectConnectGateway = expandDirectConnectRouteFilterPrefixes(del.List()) + } - if _, err := waiter.GatewayAssociationUpdated(conn, associationId, d.Timeout(schema.TimeoutUpdate)); err != nil { - return fmt.Errorf("error waiting for Direct Connect Gateway Association (%s) to update: %w", d.Id(), err) - } + log.Printf("[DEBUG] Updating Direct Connect Gateway Association: %s", input) + _, err := conn.UpdateDirectConnectGatewayAssociation(input) + + if err != nil { + return fmt.Errorf("error updating Direct Connect Gateway Association (%s): %w", d.Id(), err) + } + + if _, err := waiter.GatewayAssociationUpdated(conn, associationID, d.Timeout(schema.TimeoutUpdate)); err != nil { + return fmt.Errorf("error waiting for Direct Connect Gateway Association (%s) to update: %w", d.Id(), err) } return resourceAwsDxGatewayAssociationRead(d, meta) @@ -263,69 +259,26 @@ func resourceAwsDxGatewayAssociationDelete(d *schema.ResourceData, meta interfac } func resourceAwsDxGatewayAssociationImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + conn := meta.(*AWSClient).dxconn + parts := strings.Split(d.Id(), "/") + if len(parts) != 2 { - return []*schema.ResourceData{}, fmt.Errorf("Wrong format of resource: %s. Please follow 'dx-gw-id/gw-id'", d.Id()) + return nil, fmt.Errorf("Incorrect resource ID format: %q. Expected DXGATEWAYID/ASSOCIATEDGATEWAYID", d.Id()) } - dxgwId := parts[0] - gwId := parts[1] - id := dxGatewayAssociationId(dxgwId, gwId) - log.Printf("[DEBUG] Importing Direct Connect gateway association %s/%s", dxgwId, gwId) + directConnectGatewayID := parts[0] + associatedGatewayID := parts[1] - conn := meta.(*AWSClient).dxconn + output, err := finder.GatewayAssociationByDirectConnectGatewayIDAndAssociatedGatewayID(conn, directConnectGatewayID, associatedGatewayID) - resp, err := conn.DescribeDirectConnectGatewayAssociations(&directconnect.DescribeDirectConnectGatewayAssociationsInput{ - AssociatedGatewayId: aws.String(gwId), - DirectConnectGatewayId: aws.String(dxgwId), - }) if err != nil { return nil, err } - if n := len(resp.DirectConnectGatewayAssociations); n != 1 { - return nil, fmt.Errorf("Found %d Direct Connect gateway associations for %s, expected 1", n, id) - } - d.SetId(id) - d.Set("dx_gateway_id", resp.DirectConnectGatewayAssociations[0].DirectConnectGatewayId) - d.Set("dx_gateway_association_id", resp.DirectConnectGatewayAssociations[0].AssociationId) + d.SetId(tfdirectconnect.GatewayAssociationCreateResourceID(directConnectGatewayID, associatedGatewayID)) + d.Set("dx_gateway_id", output.DirectConnectGatewayId) + d.Set("dx_gateway_association_id", output.AssociationId) return []*schema.ResourceData{d}, nil } - -func dxGatewayAssociationStateRefresh(conn *directconnect.DirectConnect, associationId string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - resp, err := conn.DescribeDirectConnectGatewayAssociations(&directconnect.DescribeDirectConnectGatewayAssociationsInput{ - AssociationId: aws.String(associationId), - }) - if err != nil { - return nil, "", err - } - - n := len(resp.DirectConnectGatewayAssociations) - switch n { - case 0: - return "", gatewayAssociationStateDeleted, nil - - case 1: - assoc := resp.DirectConnectGatewayAssociations[0] - - if stateChangeError := aws.StringValue(assoc.StateChangeError); stateChangeError != "" { - id := dxGatewayAssociationId( - aws.StringValue(resp.DirectConnectGatewayAssociations[0].DirectConnectGatewayId), - aws.StringValue(resp.DirectConnectGatewayAssociations[0].AssociatedGateway.Id)) - log.Printf("[INFO] Direct Connect gateway association (%s) state change error: %s", id, stateChangeError) - } - - return assoc, aws.StringValue(assoc.AssociationState), nil - - default: - return nil, "", fmt.Errorf("Found %d Direct Connect gateway associations for %s, expected 1", n, associationId) - } - } -} - -// Terraform resource ID. -func dxGatewayAssociationId(dxgwId, gwId string) string { - return fmt.Sprintf("ga-%s%s", dxgwId, gwId) -} diff --git a/aws/resource_aws_dx_gateway_association_migrate.go b/aws/resource_aws_dx_gateway_association_migrate.go index 2fd6cfd57b4c..1920c97153e0 100644 --- a/aws/resource_aws_dx_gateway_association_migrate.go +++ b/aws/resource_aws_dx_gateway_association_migrate.go @@ -2,12 +2,11 @@ package aws import ( "context" - "fmt" "log" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/directconnect" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" ) func resourceAwsDxGatewayAssociationResourceV0() *schema.Resource { @@ -78,23 +77,17 @@ func resourceAwsDxGatewayAssociationResourceV0() *schema.Resource { func resourceAwsDxGatewayAssociationStateUpgradeV0(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { conn := meta.(*AWSClient).dxconn - log.Println("[INFO] Found Direct Connect gateway association state v0; migrating to v1") + log.Println("[INFO] Found Direct Connect Gateway Association state v0; migrating to v1") // dx_gateway_association_id was introduced in v2.8.0. Handle the case where it's not yet present. if v, ok := rawState["dx_gateway_association_id"]; !ok || v == nil { - resp, err := conn.DescribeDirectConnectGatewayAssociations(&directconnect.DescribeDirectConnectGatewayAssociationsInput{ - DirectConnectGatewayId: aws.String(rawState["dx_gateway_id"].(string)), - VirtualGatewayId: aws.String(rawState["vpn_gateway_id"].(string)), - }) + output, err := finder.GatewayAssociationByDirectConnectGatewayIDAndVirtualGatewayID(conn, rawState["dx_gateway_id"].(string), rawState["vpn_gateway_id"].(string)) + if err != nil { return nil, err } - if len(resp.DirectConnectGatewayAssociations) == 0 { - return nil, fmt.Errorf("Direct Connect gateway association not found, remove from state using 'terraform state rm'") - } - - rawState["dx_gateway_association_id"] = aws.StringValue(resp.DirectConnectGatewayAssociations[0].AssociationId) + rawState["dx_gateway_association_id"] = aws.StringValue(output.AssociationId) } return rawState, nil diff --git a/aws/resource_aws_dx_gateway_association_proposal.go b/aws/resource_aws_dx_gateway_association_proposal.go index b5fc3d409971..07be87a10da8 100644 --- a/aws/resource_aws_dx_gateway_association_proposal.go +++ b/aws/resource_aws_dx_gateway_association_proposal.go @@ -242,7 +242,7 @@ func resourceAwsDxGatewayAssociationProposalImport(d *schema.ResourceData, meta associatedGatewayID := parts[2] if proposalID == "" || directConnectGatewayID == "" || associatedGatewayID == "" { - return nil, fmt.Errorf("Incorrect resource ID format: %q. PROPOSALID, DXGATEWAYID and TARGETGATEWAYID must not be empty strings", d.Id()) + return nil, fmt.Errorf("Incorrect resource ID format: %q. PROPOSALID, DXGATEWAYID and ASSOCIATEDGATEWAYID must not be empty strings", d.Id()) } // Use pseudo-proposal ID and actual DirectConnectGatewayId and AssociatedGatewayId. @@ -251,7 +251,7 @@ func resourceAwsDxGatewayAssociationProposalImport(d *schema.ResourceData, meta d.Set("dx_gateway_id", directConnectGatewayID) default: - return nil, fmt.Errorf("Incorrect resource ID format: %q. Expected PROPOSALID or PROPOSALID/DXGATEWAYID/TARGETGATEWAYID", d.Id()) + return nil, fmt.Errorf("Incorrect resource ID format: %q. Expected PROPOSALID or PROPOSALID/DXGATEWAYID/ASSOCIATEDGATEWAYID", d.Id()) } return []*schema.ResourceData{d}, nil diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index c77eed169a12..a696eddccb37 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -324,7 +324,7 @@ func testAccCheckAwsDxGatewayAssociationProposalExists(resourceName string, gate } if rs.Primary.ID == "" { - return fmt.Errorf("No Direct Connect Gateway Association Proposal ID is set") + return fmt.Errorf("No ID is set") } conn := testAccProvider.Meta().(*AWSClient).dxconn diff --git a/aws/resource_aws_dx_gateway_association_test.go b/aws/resource_aws_dx_gateway_association_test.go index c57fc0efaacd..cbfe01d13035 100644 --- a/aws/resource_aws_dx_gateway_association_test.go +++ b/aws/resource_aws_dx_gateway_association_test.go @@ -208,14 +208,14 @@ func TestAccAwsDxGatewayAssociation_basicVpnGatewaySingleAccount(t *testing.T) { Config: testAccDxGatewayAssociationConfig_basicVpnGatewaySingleAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga, &gap), - resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.0/28"), resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameVgw, "id"), - resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), - resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "virtualPrivateGateway"), testAccCheckResourceAttrAccountID(resourceName, "associated_gateway_owner_account_id"), + resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "virtualPrivateGateway"), + resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), testAccCheckResourceAttrAccountID(resourceName, "dx_gateway_owner_account_id"), - resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "1"), - resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.0/28"), ), }, { @@ -239,10 +239,7 @@ func TestAccAwsDxGatewayAssociation_basicVpnGatewayCrossAccount(t *testing.T) { var gap directconnect.GatewayAssociationProposal resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccAlternateAccountPreCheck(t) - }, + PreCheck: func() { testAccPreCheck(t); testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsDxGatewayAssociationDestroy, @@ -251,15 +248,15 @@ func TestAccAwsDxGatewayAssociation_basicVpnGatewayCrossAccount(t *testing.T) { Config: testAccDxGatewayAssociationConfig_basicVpnGatewayCrossAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga, &gap), - resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.0/28"), resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameVgw, "id"), - resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), - resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "virtualPrivateGateway"), testAccCheckResourceAttrAccountID(resourceName, "associated_gateway_owner_account_id"), + resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "virtualPrivateGateway"), + resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), // dx_gateway_owner_account_id is the "awsalternate" provider's account ID. // testAccCheckResourceAttrAccountID(resourceName, "dx_gateway_owner_account_id"), - resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "1"), - resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.0/28"), ), }, }, @@ -285,15 +282,15 @@ func TestAccAwsDxGatewayAssociation_basicTransitGatewaySingleAccount(t *testing. Config: testAccDxGatewayAssociationConfig_basicTransitGatewaySingleAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga, &gap), - resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), - resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameTgw, "id"), - resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), - resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "transitGateway"), - testAccCheckResourceAttrAccountID(resourceName, "associated_gateway_owner_account_id"), - testAccCheckResourceAttrAccountID(resourceName, "dx_gateway_owner_account_id"), resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "2"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.0/30"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.8/30"), + resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameTgw, "id"), + testAccCheckResourceAttrAccountID(resourceName, "associated_gateway_owner_account_id"), + resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "transitGateway"), + resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), + testAccCheckResourceAttrAccountID(resourceName, "dx_gateway_owner_account_id"), ), }, { @@ -317,10 +314,7 @@ func TestAccAwsDxGatewayAssociation_basicTransitGatewayCrossAccount(t *testing.T var gap directconnect.GatewayAssociationProposal resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccAlternateAccountPreCheck(t) - }, + PreCheck: func() { testAccPreCheck(t); testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsDxGatewayAssociationDestroy, @@ -329,16 +323,16 @@ func TestAccAwsDxGatewayAssociation_basicTransitGatewayCrossAccount(t *testing.T Config: testAccDxGatewayAssociationConfig_basicTransitGatewayCrossAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga, &gap), - resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.0/30"), + resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.8/30"), resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameTgw, "id"), - resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), - resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "transitGateway"), testAccCheckResourceAttrAccountID(resourceName, "associated_gateway_owner_account_id"), + resource.TestCheckResourceAttr(resourceName, "associated_gateway_type", "transitGateway"), + resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), // dx_gateway_owner_account_id is the "awsalternate" provider's account ID. // testAccCheckResourceAttrAccountID(resourceName, "dx_gateway_owner_account_id"), - resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "2"), - resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.0/30"), - resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.8/30"), ), }, }, @@ -364,12 +358,12 @@ func TestAccAwsDxGatewayAssociation_multiVpnGatewaysSingleAccount(t *testing.T) Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName1, &ga, &gap), testAccCheckAwsDxGatewayAssociationExists(resourceName2, &ga, &gap), - resource.TestCheckResourceAttrSet(resourceName1, "dx_gateway_association_id"), resource.TestCheckResourceAttr(resourceName1, "allowed_prefixes.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName1, "allowed_prefixes.*", "10.255.255.0/28"), - resource.TestCheckResourceAttrSet(resourceName2, "dx_gateway_association_id"), + resource.TestCheckResourceAttrSet(resourceName1, "dx_gateway_association_id"), resource.TestCheckResourceAttr(resourceName2, "allowed_prefixes.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName2, "allowed_prefixes.*", "10.255.255.16/28"), + resource.TestCheckResourceAttrSet(resourceName2, "dx_gateway_association_id"), ), }, }, @@ -395,12 +389,12 @@ func TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewaySingleAccount(t *te Config: testAccDxGatewayAssociationConfig_allowedPrefixesVpnGatewaySingleAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga, &gap), - resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), - resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameVgw, "id"), - resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "2"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.0/30"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.8/30"), + resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameVgw, "id"), + resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), ), }, { @@ -432,10 +426,7 @@ func TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewayCrossAccount(t *tes var gap directconnect.GatewayAssociationProposal resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccAlternateAccountPreCheck(t) - }, + PreCheck: func() { testAccPreCheck(t); testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsDxGatewayAssociationDestroy, @@ -444,11 +435,11 @@ func TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewayCrossAccount(t *tes Config: testAccDxGatewayAssociationConfig_allowedPrefixesVpnGatewayCrossAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga, &gap), - resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), - resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameVgw, "id"), - resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.8/29"), + resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameVgw, "id"), + resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), ), // Accepting the proposal with overridden prefixes changes the returned RequestedAllowedPrefixesToDirectConnectGateway value (allowed_prefixes attribute). ExpectNonEmptyPlan: true, @@ -457,12 +448,12 @@ func TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewayCrossAccount(t *tes Config: testAccDxGatewayAssociationConfig_allowedPrefixesVpnGatewayCrossAccountUpdated(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga, &gap), - resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), - resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameVgw, "id"), - resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "2"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.0/30"), resource.TestCheckTypeSetElemAttr(resourceName, "allowed_prefixes.*", "10.255.255.8/30"), + resource.TestCheckResourceAttrPair(resourceName, "associated_gateway_id", resourceNameVgw, "id"), + resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), ), }, }, @@ -472,16 +463,14 @@ func TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewayCrossAccount(t *tes func TestAccAwsDxGatewayAssociation_recreateProposal(t *testing.T) { var providers []*schema.Provider resourceName := "aws_dx_gateway_association.test" + resourceNameProposal := "aws_dx_gateway_association_proposal.test" rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) var ga1, ga2 directconnect.GatewayAssociation var gap1, gap2 directconnect.GatewayAssociationProposal resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - testAccAlternateAccountPreCheck(t) - }, + PreCheck: func() { testAccPreCheck(t); testAccAlternateAccountPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), ProviderFactories: testAccProviderFactoriesAlternate(&providers), CheckDestroy: testAccCheckAwsDxGatewayAssociationDestroy, @@ -490,7 +479,7 @@ func TestAccAwsDxGatewayAssociation_recreateProposal(t *testing.T) { Config: testAccDxGatewayAssociationConfig_basicVpnGatewayCrossAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga1, &gap1), - testAccCheckResourceDisappears(testAccProvider, resourceAwsDxGatewayAssociationProposal(), resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsDxGatewayAssociationProposal(), resourceNameProposal), ), ExpectNonEmptyPlan: true, }, @@ -592,6 +581,7 @@ func testAccCheckAwsDxGatewayAssociationStateUpgradeV0(name string) resource.Tes if !ok { return fmt.Errorf("Not found: %s", name) } + if rs.Primary.ID == "" { return fmt.Errorf("No ID is set") } @@ -602,6 +592,7 @@ func testAccCheckAwsDxGatewayAssociationStateUpgradeV0(name string) resource.Tes } updatedRawState, err := resourceAwsDxGatewayAssociationStateUpgradeV0(context.Background(), rawState, testAccProvider.Meta()) + if err != nil { return err } From 9a5d4db5492ab615d0cf4245908dcb1300fb4664 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 15:03:06 -0400 Subject: [PATCH 1033/1208] r/aws_dx_gateway: Use internal finder and waiter packages. --- .../service/directconnect/finder/finder.go | 33 ++++ .../service/directconnect/waiter/status.go | 16 ++ .../service/directconnect/waiter/waiter.go | 38 ++++ aws/resource_aws_dx_gateway.go | 125 +++++-------- aws/resource_aws_dx_gateway_test.go | 166 +++++++++++------- 5 files changed, 232 insertions(+), 146 deletions(-) diff --git a/aws/internal/service/directconnect/finder/finder.go b/aws/internal/service/directconnect/finder/finder.go index a688455108f5..5bfca4c06d57 100644 --- a/aws/internal/service/directconnect/finder/finder.go +++ b/aws/internal/service/directconnect/finder/finder.go @@ -6,6 +6,39 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) +func GatewayByID(conn *directconnect.DirectConnect, id string) (*directconnect.Gateway, error) { + input := &directconnect.DescribeDirectConnectGatewaysInput{ + DirectConnectGatewayId: aws.String(id), + } + + output, err := conn.DescribeDirectConnectGateways(input) + + if err != nil { + return nil, err + } + + if output == nil || len(output.DirectConnectGateways) == 0 || output.DirectConnectGateways[0] == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + // TODO Check for multiple results. + // TODO https://github.com/hashicorp/terraform-provider-aws/pull/17613. + + gateway := output.DirectConnectGateways[0] + + if state := aws.StringValue(gateway.DirectConnectGatewayState); state == directconnect.GatewayStateDeleted { + return nil, &resource.NotFoundError{ + Message: state, + LastRequest: input, + } + } + + return gateway, nil +} + func GatewayAssociationByID(conn *directconnect.DirectConnect, id string) (*directconnect.GatewayAssociation, error) { input := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ AssociationId: aws.String(id), diff --git a/aws/internal/service/directconnect/waiter/status.go b/aws/internal/service/directconnect/waiter/status.go index 98e90d4097b4..2513c615b171 100644 --- a/aws/internal/service/directconnect/waiter/status.go +++ b/aws/internal/service/directconnect/waiter/status.go @@ -8,6 +8,22 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) +func GatewayState(conn *directconnect.DirectConnect, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.GatewayByID(conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.DirectConnectGatewayState), nil + } +} + func GatewayAssociationState(conn *directconnect.DirectConnect, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { output, err := finder.GatewayAssociationByID(conn, id) diff --git a/aws/internal/service/directconnect/waiter/waiter.go b/aws/internal/service/directconnect/waiter/waiter.go index ab54c49cb62a..01fe6ad79713 100644 --- a/aws/internal/service/directconnect/waiter/waiter.go +++ b/aws/internal/service/directconnect/waiter/waiter.go @@ -10,6 +10,44 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) +func GatewayCreated(conn *directconnect.DirectConnect, id string, timeout time.Duration) (*directconnect.Gateway, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{directconnect.GatewayStatePending}, + Target: []string{directconnect.GatewayStateAvailable}, + Refresh: GatewayState(conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*directconnect.Gateway); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StateChangeError))) + + return output, err + } + + return nil, err +} + +func GatewayDeleted(conn *directconnect.DirectConnect, id string, timeout time.Duration) (*directconnect.Gateway, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{directconnect.GatewayStatePending, directconnect.GatewayStateAvailable, directconnect.GatewayStateDeleting}, + Target: []string{}, + Refresh: GatewayState(conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*directconnect.Gateway); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StateChangeError))) + + return output, err + } + + return nil, err +} + func GatewayAssociationCreated(conn *directconnect.DirectConnect, id string, timeout time.Duration) (*directconnect.GatewayAssociation, error) { stateConf := &resource.StateChangeConf{ Pending: []string{directconnect.GatewayAssociationStateAssociating}, diff --git a/aws/resource_aws_dx_gateway.go b/aws/resource_aws_dx_gateway.go index 8a2b70de3098..e27598f9cca9 100644 --- a/aws/resource_aws_dx_gateway.go +++ b/aws/resource_aws_dx_gateway.go @@ -8,8 +8,11 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directconnect" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsDxGateway() *schema.Resource { @@ -17,22 +20,25 @@ func resourceAwsDxGateway() *schema.Resource { Create: resourceAwsDxGatewayCreate, Read: resourceAwsDxGatewayRead, Delete: resourceAwsDxGatewayDelete, + Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, "amazon_side_asn": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validateAmazonSideAsn, }, + + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "owner_account_id": { Type: schema.TypeString, Computed: true, @@ -49,36 +55,28 @@ func resourceAwsDxGateway() *schema.Resource { func resourceAwsDxGatewayCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).dxconn - req := &directconnect.CreateDirectConnectGatewayInput{ - DirectConnectGatewayName: aws.String(d.Get("name").(string)), + name := d.Get("name").(string) + input := &directconnect.CreateDirectConnectGatewayInput{ + DirectConnectGatewayName: aws.String(name), } - if asn, ok := d.GetOk("amazon_side_asn"); ok { - i, err := strconv.ParseInt(asn.(string), 10, 64) - if err != nil { - return err + + if v, ok := d.Get("amazon_side_asn").(string); ok && v != "" { + if v, err := strconv.ParseInt(v, 10, 64); err == nil { + input.AmazonSideAsn = aws.Int64(v) } - req.AmazonSideAsn = aws.Int64(i) } - log.Printf("[DEBUG] Creating Direct Connect gateway: %#v", req) - resp, err := conn.CreateDirectConnectGateway(req) + log.Printf("[DEBUG] Creating Direct Connect Gateway: %s", input) + resp, err := conn.CreateDirectConnectGateway(input) + if err != nil { - return fmt.Errorf("Error creating Direct Connect gateway: %s", err) + return fmt.Errorf("error creating Direct Connect Gateway (%s): %w", name, err) } d.SetId(aws.StringValue(resp.DirectConnectGateway.DirectConnectGatewayId)) - stateConf := &resource.StateChangeConf{ - Pending: []string{directconnect.GatewayStatePending}, - Target: []string{directconnect.GatewayStateAvailable}, - Refresh: dxGatewayStateRefresh(conn, d.Id()), - Timeout: d.Timeout(schema.TimeoutCreate), - Delay: 10 * time.Second, - MinTimeout: 5 * time.Second, - } - _, err = stateConf.WaitForState() - if err != nil { - return fmt.Errorf("Error waiting for Direct Connect gateway (%s) to become available: %s", d.Id(), err) + if _, err := waiter.GatewayCreated(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return fmt.Errorf("error waiting for Direct Connect Gateway (%s) to create: %w", d.Id(), err) } return resourceAwsDxGatewayRead(d, meta) @@ -87,20 +85,21 @@ func resourceAwsDxGatewayCreate(d *schema.ResourceData, meta interface{}) error func resourceAwsDxGatewayRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).dxconn - dxGwRaw, state, err := dxGatewayStateRefresh(conn, d.Id())() - if err != nil { - return fmt.Errorf("Error reading Direct Connect gateway: %s", err) - } - if state == directconnect.GatewayStateDeleted { - log.Printf("[WARN] Direct Connect gateway (%s) not found, removing from state", d.Id()) + output, err := finder.GatewayByID(conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Direct Connect Gateway (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - dxGw := dxGwRaw.(*directconnect.Gateway) - d.Set("name", dxGw.DirectConnectGatewayName) - d.Set("amazon_side_asn", strconv.FormatInt(aws.Int64Value(dxGw.AmazonSideAsn), 10)) - d.Set("owner_account_id", dxGw.OwnerAccount) + if err != nil { + return fmt.Errorf("error reading Direct Connect Gateway (%s): %w", d.Id(), err) + } + + d.Set("amazon_side_asn", strconv.FormatInt(aws.Int64Value(output.AmazonSideAsn), 10)) + d.Set("name", output.DirectConnectGatewayName) + d.Set("owner_account_id", output.OwnerAccount) return nil } @@ -108,58 +107,22 @@ func resourceAwsDxGatewayRead(d *schema.ResourceData, meta interface{}) error { func resourceAwsDxGatewayDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).dxconn + log.Printf("[DEBUG] Deleting Direct Connect Gateway: %s", d.Id()) _, err := conn.DeleteDirectConnectGateway(&directconnect.DeleteDirectConnectGatewayInput{ DirectConnectGatewayId: aws.String(d.Id()), }) - if err != nil { - if isAWSErr(err, "DirectConnectClientException", "does not exist") { - return nil - } - return fmt.Errorf("Error deleting Direct Connect gateway: %s", err) - } - if err := waitForDirectConnectGatewayDeletion(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("Error waiting for Direct Connect gateway (%s) to be deleted: %s", d.Id(), err) + if tfawserr.ErrMessageContains(err, directconnect.ErrCodeClientException, "does not exist") { + return nil } - return nil -} - -func dxGatewayStateRefresh(conn *directconnect.DirectConnect, dxgwId string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - resp, err := conn.DescribeDirectConnectGateways(&directconnect.DescribeDirectConnectGatewaysInput{ - DirectConnectGatewayId: aws.String(dxgwId), - }) - if err != nil { - return nil, "", err - } - - n := len(resp.DirectConnectGateways) - switch n { - case 0: - return "", directconnect.GatewayStateDeleted, nil - - case 1: - dxgw := resp.DirectConnectGateways[0] - return dxgw, aws.StringValue(dxgw.DirectConnectGatewayState), nil - - default: - return nil, "", fmt.Errorf("Found %d Direct Connect gateways for %s, expected 1", n, dxgwId) - } + if err != nil { + return fmt.Errorf("error deleting Direct Connect Gateway (%s): %w", d.Id(), err) } -} -func waitForDirectConnectGatewayDeletion(conn *directconnect.DirectConnect, gatewayID string, timeout time.Duration) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{directconnect.GatewayStatePending, directconnect.GatewayStateAvailable, directconnect.GatewayStateDeleting}, - Target: []string{directconnect.GatewayStateDeleted}, - Refresh: dxGatewayStateRefresh(conn, gatewayID), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 5 * time.Second, + if _, err := waiter.GatewayDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return fmt.Errorf("error waiting for Direct Connect Gateway (%s) to delete: %w", d.Id(), err) } - _, err := stateConf.WaitForState() - - return err + return nil } diff --git a/aws/resource_aws_dx_gateway_test.go b/aws/resource_aws_dx_gateway_test.go index 4809545c4420..00a66f3dbe8e 100644 --- a/aws/resource_aws_dx_gateway_test.go +++ b/aws/resource_aws_dx_gateway_test.go @@ -4,13 +4,16 @@ import ( "fmt" "log" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directconnect" + multierror "github.com/hashicorp/go-multierror" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directconnect/lister" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { @@ -26,95 +29,91 @@ func init() { func testSweepDirectConnectGateways(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } conn := client.(*AWSClient).dxconn input := &directconnect.DescribeDirectConnectGatewaysInput{} + var sweeperErrs *multierror.Error + sweepResources := make([]*testSweepResource, 0) - for { - output, err := conn.DescribeDirectConnectGateways(input) - - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping Direct Connect Gateway sweep for %s: %s", region, err) - return nil - } - - if err != nil { - return fmt.Errorf("error retrieving Direct Connect Gateways: %s", err) + err = lister.DescribeDirectConnectGatewaysPages(conn, input, func(page *directconnect.DescribeDirectConnectGatewaysOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - for _, gateway := range output.DirectConnectGateways { - id := aws.StringValue(gateway.DirectConnectGatewayId) + for _, gateway := range page.DirectConnectGateways { + directConnectGatewayID := aws.StringValue(gateway.DirectConnectGatewayId) - if aws.StringValue(gateway.DirectConnectGatewayState) != directconnect.GatewayStateAvailable { - log.Printf("[INFO] Skipping Direct Connect Gateway in non-available (%s) state: %s", aws.StringValue(gateway.DirectConnectGatewayState), id) + if state := aws.StringValue(gateway.DirectConnectGatewayState); state != directconnect.GatewayStateAvailable { + log.Printf("[INFO] Skipping Direct Connect Gateway in non-available (%s) state: %s", state, directConnectGatewayID) continue } - var associations bool - associationInput := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ - DirectConnectGatewayId: gateway.DirectConnectGatewayId, + input := &directconnect.DescribeDirectConnectGatewayAssociationsInput{ + DirectConnectGatewayId: aws.String(directConnectGatewayID), } - for { - associationOutput, err := conn.DescribeDirectConnectGatewayAssociations(associationInput) + var associations bool - if err != nil { - return fmt.Errorf("error retrieving Direct Connect Gateway (%s) Associations: %s", id, err) + err := lister.DescribeDirectConnectGatewayAssociationsPages(conn, input, func(page *directconnect.DescribeDirectConnectGatewayAssociationsOutput, lastPage bool) bool { + if page == nil { + return !lastPage } // If associations still remain, its likely that our region is not the home // region of those associations and the previous sweepers skipped them. // When we hit this condition, we skip trying to delete the gateway as it // will go from deleting -> available after a few minutes and timeout. - if len(associationOutput.DirectConnectGatewayAssociations) > 0 { + if len(page.DirectConnectGatewayAssociations) > 0 { associations = true - break - } - if aws.StringValue(associationOutput.NextToken) == "" { - break + return false } - associationInput.NextToken = associationOutput.NextToken + return !lastPage + }) + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Direct Connect Gateway Associations (%s): %w", region, err)) } if associations { - log.Printf("[INFO] Skipping Direct Connect Gateway with remaining associations: %s", id) + log.Printf("[INFO] Skipping Direct Connect Gateway with remaining associations: %s", directConnectGatewayID) continue } - input := &directconnect.DeleteDirectConnectGatewayInput{ - DirectConnectGatewayId: aws.String(id), - } + r := resourceAwsDxGateway() + d := r.Data(nil) + d.SetId(directConnectGatewayID) - log.Printf("[INFO] Deleting Direct Connect Gateway: %s", id) - _, err := conn.DeleteDirectConnectGateway(input) + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) + } - if isAWSErr(err, directconnect.ErrCodeClientException, "does not exist") { - continue - } + return !lastPage + }) - if err != nil { - return fmt.Errorf("error deleting Direct Connect Gateway (%s): %s", id, err) - } + if testSweepSkipSweepError(err) { + log.Print(fmt.Errorf("[WARN] Skipping Direct Connect Gateway sweep for %s: %w", region, err)) + return sweeperErrs // In case we have completed some pages, but had errors + } - if err := waitForDirectConnectGatewayDeletion(conn, id, 20*time.Minute); err != nil { - return fmt.Errorf("error waiting for Direct Connect Gateway (%s) to be deleted: %s", id, err) - } - } + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error listing Direct Connect Gateways (%s): %w", region, err)) + } - if aws.StringValue(output.NextToken) == "" { - break - } + err = testSweepResourceOrchestrator(sweepResources) - input.NextToken = output.NextToken + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error sweeping Direct Connect Gateways (%s): %w", region, err)) } - return nil + return sweeperErrs.ErrorOrNil() } func TestAccAwsDxGateway_basic(t *testing.T) { + var v directconnect.Gateway + rName := acctest.RandomWithPrefix("tf-acc-test") + rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_dx_gateway.test" resource.ParallelTest(t, resource.TestCase{ @@ -124,9 +123,9 @@ func TestAccAwsDxGateway_basic(t *testing.T) { CheckDestroy: testAccCheckAwsDxGatewayDestroy, Steps: []resource.TestStep{ { - Config: testAccDxGatewayConfig(acctest.RandString(5), acctest.RandIntRange(64512, 65534)), + Config: testAccDxGatewayConfig(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxGatewayExists(resourceName), + testAccCheckAwsDxGatewayExists(resourceName, &v), testAccCheckResourceAttrAccountID(resourceName, "owner_account_id"), ), }, @@ -139,7 +138,32 @@ func TestAccAwsDxGateway_basic(t *testing.T) { }) } +func TestAccAwsDxGateway_disappears(t *testing.T) { + var v directconnect.Gateway + rName := acctest.RandomWithPrefix("tf-acc-test") + rBgpAsn := acctest.RandIntRange(64512, 65534) + resourceName := "aws_dx_gateway.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, directconnect.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsDxGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDxGatewayConfig(rName, rBgpAsn), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsDxGatewayExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsDxGateway(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func TestAccAwsDxGateway_complex(t *testing.T) { + var v directconnect.Gateway rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) resourceName := "aws_dx_gateway.test" @@ -153,7 +177,7 @@ func TestAccAwsDxGateway_complex(t *testing.T) { { Config: testAccDxGatewayAssociationConfig_multiVpnGatewaysSingleAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxGatewayExists(resourceName), + testAccCheckAwsDxGatewayExists(resourceName, &v), testAccCheckResourceAttrAccountID(resourceName, "owner_account_id"), ), }, @@ -174,30 +198,42 @@ func testAccCheckAwsDxGatewayDestroy(s *terraform.State) error { continue } - input := &directconnect.DescribeDirectConnectGatewaysInput{ - DirectConnectGatewayId: aws.String(rs.Primary.ID), + _, err := finder.GatewayByID(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue } - resp, err := conn.DescribeDirectConnectGateways(input) if err != nil { return err } - for _, v := range resp.DirectConnectGateways { - if *v.DirectConnectGatewayId == rs.Primary.ID && !(*v.DirectConnectGatewayState == directconnect.GatewayStateDeleted) { - return fmt.Errorf("[DESTROY ERROR] DX Gateway (%s) not deleted", rs.Primary.ID) - } - } + + return fmt.Errorf("Direct Connect Gateway %s still exists", rs.Primary.ID) } return nil } -func testAccCheckAwsDxGatewayExists(name string) resource.TestCheckFunc { +func testAccCheckAwsDxGatewayExists(name string, v *directconnect.Gateway) resource.TestCheckFunc { return func(s *terraform.State) error { - _, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[name] if !ok { return fmt.Errorf("Not found: %s", name) } + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).dxconn + + output, err := finder.GatewayByID(conn, rs.Primary.ID) + + if err != nil { + return err + } + + *v = *output + return nil } } @@ -205,8 +241,8 @@ func testAccCheckAwsDxGatewayExists(name string) resource.TestCheckFunc { func testAccDxGatewayConfig(rName string, rBgpAsn int) string { return fmt.Sprintf(` resource "aws_dx_gateway" "test" { - name = "terraform-testacc-dxgw-%s" - amazon_side_asn = "%d" + name = %[1]q + amazon_side_asn = "%[2]d" } `, rName, rBgpAsn) } From 306bd032dd2ba78fb7f64dff9d687c637da05d79 Mon Sep 17 00:00:00 2001 From: Dirk Avery <31492422+YakDriver@users.noreply.github.com> Date: Thu, 8 Jul 2021 15:16:38 -0400 Subject: [PATCH 1034/1208] docs/r/lakeformation_permissions: Soften language Co-authored-by: Mary Elizabeth --- website/docs/r/lakeformation_permissions.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index 7d98355ec117..75cb4c478af7 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -18,7 +18,7 @@ Grants permissions to the principal to access metadata in the Data Catalog and d **_Lake Formation permissions are not in effect by default within AWS._** `IAMAllowedPrincipals` (i.e., `IAM_ALLOWED_PRINCIPALS`) conflicts with individual Lake Formation permissions (i.e., non-`IAMAllowedPrincipals` permissions), will cause unexpected behavior, and may result in errors. -When using Lake Formation, you need to choose between these two mutually exclusive options: +When using Lake Formation, choose ONE of the following options as they are mutually exclusive: 1. Use this resource (`aws_lakeformation_permissions`), change the default security settings using [`aws_lakeformation_data_lake_settings`](/docs/providers/aws/r/lakeformation_data_lake_settings.html), and remove existing `IAMAllowedPrincipals` permissions 2. Use `IAMAllowedPrincipals` and not use this resource From ddab58c36c488d4d77de8adece1ef2f7b7551ce3 Mon Sep 17 00:00:00 2001 From: Dirk Avery <31492422+YakDriver@users.noreply.github.com> Date: Thu, 8 Jul 2021 15:17:08 -0400 Subject: [PATCH 1035/1208] docs/r/lakeformation_permissions: Clarify Co-authored-by: Mary Elizabeth --- website/docs/r/lakeformation_permissions.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index 75cb4c478af7..81e5bb583f01 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -21,7 +21,7 @@ Grants permissions to the principal to access metadata in the Data Catalog and d When using Lake Formation, choose ONE of the following options as they are mutually exclusive: 1. Use this resource (`aws_lakeformation_permissions`), change the default security settings using [`aws_lakeformation_data_lake_settings`](/docs/providers/aws/r/lakeformation_data_lake_settings.html), and remove existing `IAMAllowedPrincipals` permissions -2. Use `IAMAllowedPrincipals` and not use this resource +2. Use `IAMAllowedPrincipals` without `aws_lakeformation_permissions` ``` This example shows removing the `IAMAllowedPrincipals` default security settings and making the caller a Lake Formation admin. Since `create_database_default_permissions` and `create_table_default_permissions` are not set in the [`aws_lakeformation_data_lake_settings`](/docs/providers/aws/r/lakeformation_data_lake_settings.html) resource, they are cleared. From fb040dd8f7429b1172616eb9423be5356e3f1298 Mon Sep 17 00:00:00 2001 From: Dirk Avery <31492422+YakDriver@users.noreply.github.com> Date: Thu, 8 Jul 2021 15:17:36 -0400 Subject: [PATCH 1036/1208] docs/r/lakeformation_permissions: Clean up language Co-authored-by: Mary Elizabeth --- website/docs/r/lakeformation_permissions.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index 81e5bb583f01..c23c637c16d7 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -50,7 +50,7 @@ For more details, see [Changing the Default Security Settings for Your Data Lake ### Problem Using `IAMAllowedPrincipals` -AWS does not support combining `IAMAllowedPrincipals` permissions and non-`IAMAllowedPrincipals` permissions. Doing so results in unexpected permissions. For example, this configuration grants a user `SELECT` on a column in a table. +AWS does not support combining `IAMAllowedPrincipals` permissions and non-`IAMAllowedPrincipals` permissions. Doing so results in unexpected permissions and behaviors. For example, this configuration grants a user `SELECT` on a column in a table. ```terraform resource "aws_glue_catalog_database" "example" { From ad016d2b0c2930ef853fdc29de7f6eb1f94eb8b1 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 15:20:37 -0400 Subject: [PATCH 1037/1208] r/lakeformation_permissions: Errant newline --- aws/resource_aws_lakeformation_permissions.go | 1 - 1 file changed, 1 deletion(-) diff --git a/aws/resource_aws_lakeformation_permissions.go b/aws/resource_aws_lakeformation_permissions.go index 98c454df7edb..0b95cc9ab0d6 100644 --- a/aws/resource_aws_lakeformation_permissions.go +++ b/aws/resource_aws_lakeformation_permissions.go @@ -503,7 +503,6 @@ func resourceAwsLakeFormationPermissionsRead(d *schema.ResourceData, meta interf tableSet = true break } - } } From 7d84773269330e64c0f1c4dd158f8b458f8fab90 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 15:27:04 -0400 Subject: [PATCH 1038/1208] Add CHANGELOG entry. --- .changelog/19741.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19741.txt diff --git a/.changelog/19741.txt b/.changelog/19741.txt new file mode 100644 index 000000000000..83d9fc756e95 --- /dev/null +++ b/.changelog/19741.txt @@ -0,0 +1,3 @@ +```release-note:note +resource/aws_dx_gateway_association_proposal: If an accepted Proposal reaches end-of-life and is removed by AWS do not recreate the resource, instead refreshing Terraform state from the resource's Direct Connect Gateway ID and Associated Gateway ID. +``` \ No newline at end of file From d1165875915bf1a2953cace069e54110b9f7557e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 15:28:00 -0400 Subject: [PATCH 1039/1208] 'release-note' not 'release-notes' for CHANGELOG entries --- docs/contributing/pullrequest-submission-and-lifecycle.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/pullrequest-submission-and-lifecycle.md b/docs/contributing/pullrequest-submission-and-lifecycle.md index 19a8ea6f9b71..a3cd2b85cc93 100644 --- a/docs/contributing/pullrequest-submission-and-lifecycle.md +++ b/docs/contributing/pullrequest-submission-and-lifecycle.md @@ -206,11 +206,11 @@ The changelog format requires an entry in the following format, where HEADER cor If a pull request should contain multiple changelog entries, then multiple blocks can be added to the same changelog file. For example: ``````markdown -```release-notes:note +```release-note:note resource/aws_example_thing: The `broken` attribute has been deprecated. All configurations using `broken` should be updated to use the new `not_broken` attribute instead. ``` -```release-notes:enhancement +```release-note:enhancement resource/aws_example_thing: Add `not_broken` attribute ``` `````` From 8b7cb8e715a8249f4eee3ce6aab60697673abbda Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Thu, 8 Jul 2021 16:07:18 -0400 Subject: [PATCH 1040/1208] docs/r/lakeformation_permissions: Remove errants ticks --- website/docs/r/lakeformation_permissions.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lakeformation_permissions.html.markdown b/website/docs/r/lakeformation_permissions.html.markdown index c23c637c16d7..18f7e326d198 100644 --- a/website/docs/r/lakeformation_permissions.html.markdown +++ b/website/docs/r/lakeformation_permissions.html.markdown @@ -21,7 +21,7 @@ Grants permissions to the principal to access metadata in the Data Catalog and d When using Lake Formation, choose ONE of the following options as they are mutually exclusive: 1. Use this resource (`aws_lakeformation_permissions`), change the default security settings using [`aws_lakeformation_data_lake_settings`](/docs/providers/aws/r/lakeformation_data_lake_settings.html), and remove existing `IAMAllowedPrincipals` permissions -2. Use `IAMAllowedPrincipals` without `aws_lakeformation_permissions` ``` +2. Use `IAMAllowedPrincipals` without `aws_lakeformation_permissions` This example shows removing the `IAMAllowedPrincipals` default security settings and making the caller a Lake Formation admin. Since `create_database_default_permissions` and `create_table_default_permissions` are not set in the [`aws_lakeformation_data_lake_settings`](/docs/providers/aws/r/lakeformation_data_lake_settings.html) resource, they are cleared. From 555664a272d68b9555dd81679ba6a8fe07ad4bb9 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 8 Jul 2021 13:42:22 -0700 Subject: [PATCH 1041/1208] Adds test for updating replica count on Global Replication Group secondary member --- ..._aws_elasticache_replication_group_test.go | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_elasticache_replication_group_test.go b/aws/resource_aws_elasticache_replication_group_test.go index 5822a2db70dc..3dbc8a657744 100644 --- a/aws/resource_aws_elasticache_replication_group_test.go +++ b/aws/resource_aws_elasticache_replication_group_test.go @@ -1551,6 +1551,8 @@ func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_Basic(t *tes resource.TestCheckResourceAttrPair(resourceName, "engine", primaryGroupResourceName, "engine"), resource.TestCheckResourceAttrPair(resourceName, "engine_version", primaryGroupResourceName, "engine_version"), resource.TestMatchResourceAttr(resourceName, "parameter_group_name", regexp.MustCompile(fmt.Sprintf("^global-datastore-%s-", rName))), + resource.TestCheckResourceAttr(resourceName, "number_cache_clusters", "1"), + resource.TestCheckResourceAttr(primaryGroupResourceName, "number_cache_clusters", "2"), ), }, { @@ -1571,6 +1573,9 @@ func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_Full(t *test resourceName := "aws_elasticache_replication_group.test" primaryGroupResourceName := "aws_elasticache_replication_group.primary" + initialNumCacheClusters := 2 + updatedNumCacheClusters := 3 + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) @@ -1581,7 +1586,7 @@ func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_Full(t *test CheckDestroy: testAccCheckAWSElasticacheReplicationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Full(rName), + Config: testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Full(rName, initialNumCacheClusters), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), resource.TestCheckResourceAttrPair(resourceName, "global_replication_group_id", "aws_elasticache_global_replication_group.test", "global_replication_group_id"), @@ -1590,7 +1595,7 @@ func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_Full(t *test resource.TestCheckResourceAttrPair(resourceName, "engine_version", primaryGroupResourceName, "engine_version"), resource.TestMatchResourceAttr(resourceName, "parameter_group_name", regexp.MustCompile(fmt.Sprintf("^global-datastore-%s-", rName))), - resource.TestCheckResourceAttrPair(resourceName, "number_cache_clusters", primaryGroupResourceName, "number_cache_clusters"), + resource.TestCheckResourceAttr(resourceName, "number_cache_clusters", strconv.Itoa(initialNumCacheClusters)), resource.TestCheckResourceAttrPair(resourceName, "multi_az_enabled", primaryGroupResourceName, "multi_az_enabled"), resource.TestCheckResourceAttrPair(resourceName, "automatic_failover_enabled", primaryGroupResourceName, "automatic_failover_enabled"), @@ -1607,6 +1612,13 @@ func TestAccAWSElasticacheReplicationGroup_GlobalReplicationGroupId_Full(t *test ImportStateVerify: true, ImportStateVerifyIgnore: []string{"apply_immediately"}, }, + { + Config: testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Full(rName, updatedNumCacheClusters), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSElasticacheReplicationGroupExists(resourceName, &rg), + resource.TestCheckResourceAttr(resourceName, "number_cache_clusters", strconv.Itoa(updatedNumCacheClusters)), + ), + }, }, }) } @@ -2890,12 +2902,12 @@ resource "aws_elasticache_replication_group" "primary" { engine = "redis" engine_version = "5.0.6" - number_cache_clusters = 1 + number_cache_clusters = 2 } `, rName)) } -func testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Full(rName string) string { +func testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_Full(rName string, numCacheClusters int) string { return composeConfig( testAccMultipleRegionProviderConfig(2), testAccElasticacheVpcBaseWithProvider(rName, "test", ProviderNameAws, 2), @@ -2908,7 +2920,7 @@ resource "aws_elasticache_replication_group" "test" { subnet_group_name = aws_elasticache_subnet_group.test.name - number_cache_clusters = 2 + number_cache_clusters = %[2]d automatic_failover_enabled = true multi_az_enabled = true @@ -2943,7 +2955,7 @@ resource "aws_elasticache_replication_group" "primary" { at_rest_encryption_enabled = true transit_encryption_enabled = true } -`, rName)) +`, rName, numCacheClusters)) } func testAccAWSElasticacheReplicationGroupConfig_GlobalReplicationGroupId_ClusterMode(rName string, primaryReplicaCount, secondaryReplicaCount int) string { From c800c67b4af4fc9374ab57e5678e7ca8a8659b74 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 8 Jul 2021 14:03:09 -0700 Subject: [PATCH 1042/1208] Adds CHANGELOG entry --- .changelog/20111.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/20111.txt diff --git a/.changelog/20111.txt b/.changelog/20111.txt new file mode 100644 index 000000000000..5768419145be --- /dev/null +++ b/.changelog/20111.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_elasticache_replication_group: Cannot set `cluster_mode.replicas_per_node_group` when member of Global Replication Group +``` From 8cb22b4bf4187c2c40d9801455699a9eeed20f53 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 8 Jul 2021 17:16:08 -0400 Subject: [PATCH 1043/1208] Taint Proposal to test Gateway Association ForceNew. --- ...rce_aws_dx_gateway_association_proposal_test.go | 14 ++++++++++++-- aws/resource_aws_dx_gateway_association_test.go | 5 ++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index a696eddccb37..700ae9ec673f 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -351,6 +351,16 @@ func testAccCheckAwsDxGatewayAssociationProposalRecreated(old, new *directconnec } } +// func testAccCheckAwsDxGatewayAssociationProposalNotRecreated(old, new *directconnect.GatewayAssociationProposal) resource.TestCheckFunc { +// return func(s *terraform.State) error { +// if old, new := aws.StringValue(old.ProposalId), aws.StringValue(new.ProposalId); old != new { +// return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) recreated (%s)", old, new) +// } + +// return nil +// } +// } + func testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -366,8 +376,8 @@ func testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName string) re return err } - if aws.StringValue(output.ProposalState) != directconnect.GatewayAssociationProposalStateAccepted { - return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not accepted", rs.Primary.ID) + if state := aws.StringValue(output.ProposalState); state != directconnect.GatewayAssociationProposalStateAccepted { + return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) not accepted (%s)", rs.Primary.ID, state) } return nil diff --git a/aws/resource_aws_dx_gateway_association_test.go b/aws/resource_aws_dx_gateway_association_test.go index cbfe01d13035..6578f18265e0 100644 --- a/aws/resource_aws_dx_gateway_association_test.go +++ b/aws/resource_aws_dx_gateway_association_test.go @@ -479,9 +479,7 @@ func TestAccAwsDxGatewayAssociation_recreateProposal(t *testing.T) { Config: testAccDxGatewayAssociationConfig_basicVpnGatewayCrossAccount(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga1, &gap1), - testAccCheckResourceDisappears(testAccProvider, resourceAwsDxGatewayAssociationProposal(), resourceNameProposal), ), - ExpectNonEmptyPlan: true, }, { Config: testAccDxGatewayAssociationConfig_basicVpnGatewayCrossAccount(rName, rBgpAsn), @@ -490,6 +488,7 @@ func TestAccAwsDxGatewayAssociation_recreateProposal(t *testing.T) { testAccCheckAwsDxGatewayAssociationNotRecreated(&ga1, &ga2), testAccCheckAwsDxGatewayAssociationProposalRecreated(&gap1, &gap2), ), + Taint: []string{resourceNameProposal}, }, }, }) @@ -566,7 +565,7 @@ func testAccCheckAwsDxGatewayAssociationExists(name string, ga *directconnect.Ga func testAccCheckAwsDxGatewayAssociationNotRecreated(old, new *directconnect.GatewayAssociation) resource.TestCheckFunc { return func(s *terraform.State) error { - if old, new := aws.StringValue(old.AssociationId), aws.StringValue(new.AssociationId); old == new { + if old, new := aws.StringValue(old.AssociationId), aws.StringValue(new.AssociationId); old != new { return fmt.Errorf("Direct Connect Gateway Association (%s) recreated (%s)", old, new) } From 7271ccbf34f28d383173f0d17ec4b54f00bbfedd Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 8 Jul 2021 21:22:26 +0000 Subject: [PATCH 1044/1208] Update CHANGELOG.md for #20108 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8117c545ea28..58062ef7fbe5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,9 @@ ENHANCEMENTS: BUG FIXES: +* data-source/aws_lakeformation_permissions: Fix various problems with permissions including select-only ([#20108](https://github.com/hashicorp/terraform-provider-aws/issues/20108)) * resource/aws_eks_cluster: Don't associate an `encryption_config` if there's already one ([#19986](https://github.com/hashicorp/terraform-provider-aws/issues/19986)) +* resource/aws_lakeformation_permissions: Fix various problems with permissions including select-only ([#20108](https://github.com/hashicorp/terraform-provider-aws/issues/20108)) * resource/aws_ram_resource_share_accepter: Allow destroy even where AWS API provides no way to disassociate ([#19718](https://github.com/hashicorp/terraform-provider-aws/issues/19718)) ## 3.48.0 (July 02, 2021) From db2261520cacc36241cc72ea65aefc6b7891806d Mon Sep 17 00:00:00 2001 From: tf-release-bot Date: Thu, 8 Jul 2021 21:33:25 +0000 Subject: [PATCH 1045/1208] v3.49.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58062ef7fbe5..f41dcdf719f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 3.49.0 (Unreleased) +## 3.49.0 (July 08, 2021) FEATURES: From f93d5df7e7b81e2ee25bd4f8a438bb40a0f37ead Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 8 Jul 2021 21:51:23 +0000 Subject: [PATCH 1046/1208] Update CHANGELOG.md after v3.49.0 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f41dcdf719f7..64ba9062ffd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +## 3.50.0 (Unreleased) ## 3.49.0 (July 08, 2021) FEATURES: From 45e79f704f799cff0a94847a5939425897e96085 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 16 Jun 2021 17:22:50 -0400 Subject: [PATCH 1047/1208] Add 'SubdirectoryFromLocationURI'. Test output: % go test -v ./aws/internal/service/datasync === RUN TestSubdirectoryFromLocationURI === RUN TestSubdirectoryFromLocationURI/empty_URI === RUN TestSubdirectoryFromLocationURI/invalid_URI_scheme === RUN TestSubdirectoryFromLocationURI/S3_bucket_URI_no_bucket_name_(1) === RUN TestSubdirectoryFromLocationURI/S3_bucket_URI_no_bucket_name_(2) === RUN TestSubdirectoryFromLocationURI/S3_bucket_URI_top_level === RUN TestSubdirectoryFromLocationURI/S3_bucket_URI_one_level === RUN TestSubdirectoryFromLocationURI/S3_bucket_URI_two_levels === RUN TestSubdirectoryFromLocationURI/S3_Outposts_ARN_URI_top_level === RUN TestSubdirectoryFromLocationURI/S3_Outposts_ARN_URI_one_level === RUN TestSubdirectoryFromLocationURI/S3_Outposts_ARN_URI_two_levels === RUN TestSubdirectoryFromLocationURI/EFS_URI_top_level === RUN TestSubdirectoryFromLocationURI/EFS_URI_one_level === RUN TestSubdirectoryFromLocationURI/EFS_URI_two_levels === RUN TestSubdirectoryFromLocationURI/NFS_URI_top_level === RUN TestSubdirectoryFromLocationURI/NFS_URI_one_level === RUN TestSubdirectoryFromLocationURI/NFS_URI_two_levels === RUN TestSubdirectoryFromLocationURI/SMB_URI_top_level === RUN TestSubdirectoryFromLocationURI/SMB_URI_one_level === RUN TestSubdirectoryFromLocationURI/SMB_URI_two_levels === RUN TestSubdirectoryFromLocationURI/FSx_Windows_URI_top_level === RUN TestSubdirectoryFromLocationURI/FSx_Windows_URI_one_level === RUN TestSubdirectoryFromLocationURI/FSx_Windows_URI_two_levels --- PASS: TestSubdirectoryFromLocationURI (0.00s) --- PASS: TestSubdirectoryFromLocationURI/empty_URI (0.00s) --- PASS: TestSubdirectoryFromLocationURI/invalid_URI_scheme (0.00s) --- PASS: TestSubdirectoryFromLocationURI/S3_bucket_URI_no_bucket_name_(1) (0.00s) --- PASS: TestSubdirectoryFromLocationURI/S3_bucket_URI_no_bucket_name_(2) (0.00s) --- PASS: TestSubdirectoryFromLocationURI/S3_bucket_URI_top_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/S3_bucket_URI_one_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/S3_bucket_URI_two_levels (0.00s) --- PASS: TestSubdirectoryFromLocationURI/S3_Outposts_ARN_URI_top_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/S3_Outposts_ARN_URI_one_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/S3_Outposts_ARN_URI_two_levels (0.00s) --- PASS: TestSubdirectoryFromLocationURI/EFS_URI_top_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/EFS_URI_one_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/EFS_URI_two_levels (0.00s) --- PASS: TestSubdirectoryFromLocationURI/NFS_URI_top_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/NFS_URI_one_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/NFS_URI_two_levels (0.00s) --- PASS: TestSubdirectoryFromLocationURI/SMB_URI_top_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/SMB_URI_one_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/SMB_URI_two_levels (0.00s) --- PASS: TestSubdirectoryFromLocationURI/FSx_Windows_URI_top_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/FSx_Windows_URI_one_level (0.00s) --- PASS: TestSubdirectoryFromLocationURI/FSx_Windows_URI_two_levels (0.00s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync 3.695s --- aws/internal/service/datasync/uri.go | 45 +++++++ aws/internal/service/datasync/uri_test.go | 145 ++++++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 aws/internal/service/datasync/uri.go create mode 100644 aws/internal/service/datasync/uri_test.go diff --git a/aws/internal/service/datasync/uri.go b/aws/internal/service/datasync/uri.go new file mode 100644 index 000000000000..bac9e606a8eb --- /dev/null +++ b/aws/internal/service/datasync/uri.go @@ -0,0 +1,45 @@ +package datasync + +import ( + "fmt" + "regexp" + + "github.com/aws/aws-sdk-go/aws/arn" +) + +var ( + locationURIPattern = regexp.MustCompile(`^(efs|nfs|s3|smb|fsxw)://(.+)$`) + locationURIGlobalIDAndSubdirPattern = regexp.MustCompile(`^([a-zA-Z0-9.\-]+)(/.*)$`) + s3OutpostsAccessPointARNResourcePattern = regexp.MustCompile(`^outpost/.*/accesspoint/.*?(/.*)$`) +) + +// SubdirectoryFromLocationURI extracts the subdirectory from a location URI. +// https://docs.aws.amazon.com/datasync/latest/userguide/API_LocationListEntry.html#DataSync-Type-LocationListEntry-LocationUri +func SubdirectoryFromLocationURI(uri string) (string, error) { + submatches := locationURIPattern.FindStringSubmatch(uri) + + if len(submatches) != 3 { + return "", fmt.Errorf("location URI (%s) does not match pattern %q", uri, locationURIPattern) + } + + globalIDAndSubdir := submatches[2] + parsedARN, err := arn.Parse(globalIDAndSubdir) + + if err == nil { + submatches = s3OutpostsAccessPointARNResourcePattern.FindStringSubmatch(parsedARN.Resource) + + if len(submatches) != 2 { + return "", fmt.Errorf("location URI S3 on Outposts access point ARN resource (%s) does not match pattern %q", parsedARN.Resource, s3OutpostsAccessPointARNResourcePattern) + } + + return submatches[1], nil + } + + submatches = locationURIGlobalIDAndSubdirPattern.FindStringSubmatch(globalIDAndSubdir) + + if len(submatches) != 3 { + return "", fmt.Errorf("location URI global ID and subdirectory (%s) does not match pattern %q", globalIDAndSubdir, locationURIGlobalIDAndSubdirPattern) + } + + return submatches[2], nil +} diff --git a/aws/internal/service/datasync/uri_test.go b/aws/internal/service/datasync/uri_test.go new file mode 100644 index 000000000000..6c90cf99a04f --- /dev/null +++ b/aws/internal/service/datasync/uri_test.go @@ -0,0 +1,145 @@ +package datasync_test + +import ( + "testing" + + tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync" +) + +func TestSubdirectoryFromLocationURI(t *testing.T) { + testCases := []struct { + TestName string + InputURI string + ExpectedError bool + ExpectedSubdirectory string + }{ + { + TestName: "empty URI", + InputURI: "", + ExpectedError: true, + }, + { + TestName: "invalid URI scheme", + InputURI: "test://testing/", + ExpectedError: true, + }, + { + TestName: "S3 bucket URI no bucket name (1)", + InputURI: "s3://", + ExpectedError: true, + }, + { + TestName: "S3 bucket URI no bucket name (2)", + InputURI: "s3:///", + ExpectedError: true, + }, + { + TestName: "S3 bucket URI top level", + InputURI: "s3://bucket/", + ExpectedSubdirectory: "/", + }, + { + TestName: "S3 bucket URI one level", + InputURI: "s3://bucket/my-folder-1/", + ExpectedSubdirectory: "/my-folder-1/", + }, + { + TestName: "S3 bucket URI two levels", + InputURI: "s3://bucket/my-folder-1/my-folder-2", + ExpectedSubdirectory: "/my-folder-1/my-folder-2", + }, + { + TestName: "S3 Outposts ARN URI top level", + InputURI: "s3://arn:aws:s3-outposts:eu-west-3:123456789012:outpost/op-YYYYYYYYYY/accesspoint/my-access-point/", + ExpectedSubdirectory: "/", + }, + { + TestName: "S3 Outposts ARN URI one level", + InputURI: "s3://arn:aws:s3-outposts:eu-west-3:123456789012:outpost/op-YYYYYYYYYY/accesspoint/my-access-point/my-folder-1/", + ExpectedSubdirectory: "/my-folder-1/", + }, + { + TestName: "S3 Outposts ARN URI two levels", + InputURI: "s3://arn:aws:s3-outposts:eu-west-3:123456789012:outpost/op-YYYYYYYYYY/accesspoint/my-access-point/my-folder-1/my-folder-2", + ExpectedSubdirectory: "/my-folder-1/my-folder-2", + }, + { + TestName: "EFS URI top level", + InputURI: "efs://us-west-2.fs-abcdef01/", + ExpectedSubdirectory: "/", + }, + { + TestName: "EFS URI one level", + InputURI: "efs://us-west-2.fs-abcdef01/my-folder-1/", + ExpectedSubdirectory: "/my-folder-1/", + }, + { + TestName: "EFS URI two levels", + InputURI: "efs://us-west-2.fs-abcdef01/my-folder-1/my-folder-2", + ExpectedSubdirectory: "/my-folder-1/my-folder-2", + }, + { + TestName: "NFS URI top level", + InputURI: "nfs://example.com/", + ExpectedSubdirectory: "/", + }, + { + TestName: "NFS URI one level", + InputURI: "nfs://example.com/my-folder-1/", + ExpectedSubdirectory: "/my-folder-1/", + }, + { + TestName: "NFS URI two levels", + InputURI: "nfs://example.com/my-folder-1/my-folder-2", + ExpectedSubdirectory: "/my-folder-1/my-folder-2", + }, + { + TestName: "SMB URI top level", + InputURI: "smb://192.168.1.1/", + ExpectedSubdirectory: "/", + }, + { + TestName: "SMB URI one level", + InputURI: "smb://192.168.1.1/my-folder-1/", + ExpectedSubdirectory: "/my-folder-1/", + }, + { + TestName: "SMB URI two levels", + InputURI: "smb://192.168.1.1/my-folder-1/my-folder-2", + ExpectedSubdirectory: "/my-folder-1/my-folder-2", + }, + { + TestName: "FSx Windows URI top level", + InputURI: "fsxw://us-west-2.fs-abcdef012345678901/", + ExpectedSubdirectory: "/", + }, + { + TestName: "FSx Windows URI one level", + InputURI: "fsxw://us-west-2.fs-abcdef012345678901/my-folder-1/", + ExpectedSubdirectory: "/my-folder-1/", + }, + { + TestName: "FSx Windows URI two levels", + InputURI: "fsxw://us-west-2.fs-abcdef012345678901/my-folder-1/my-folder-2", + ExpectedSubdirectory: "/my-folder-1/my-folder-2", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.TestName, func(t *testing.T) { + got, err := tfdatasync.SubdirectoryFromLocationURI(testCase.InputURI) + + if err == nil && testCase.ExpectedError { + t.Fatalf("expected error") + } + + if err != nil && !testCase.ExpectedError { + t.Fatalf("unexpected error: %s", err) + } + + if got != testCase.ExpectedSubdirectory { + t.Errorf("got %s, expected %s", got, testCase.ExpectedSubdirectory) + } + }) + } +} From 5882630cb5b04c7d8020052022b4626e134945c2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 10:45:20 -0400 Subject: [PATCH 1048/1208] Replace 'dataSyncParseLocationURI' with 'SubdirectoryFromLocationURI'. --- aws/datasync.go | 12 ----- aws/datasync_test.go | 47 ------------------- aws/resource_aws_datasync_location_efs.go | 5 +- ...tasync_location_fsx_windows_file_system.go | 5 +- aws/resource_aws_datasync_location_nfs.go | 5 +- aws/resource_aws_datasync_location_s3.go | 5 +- aws/resource_aws_datasync_location_smb.go | 5 +- 7 files changed, 15 insertions(+), 69 deletions(-) delete mode 100644 aws/datasync_test.go diff --git a/aws/datasync.go b/aws/datasync.go index 117ede5c4efc..ec7e10887b4e 100644 --- a/aws/datasync.go +++ b/aws/datasync.go @@ -1,23 +1,11 @@ package aws import ( - "net/url" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/datasync" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSyncParseLocationURI(uri string) (string, error) { - parsedURL, err := url.ParseRequestURI(uri) - - if err != nil { - return "", err - } - - return parsedURL.Path, nil -} - func expandDataSyncEc2Config(l []interface{}) *datasync.Ec2Config { if len(l) == 0 || l[0] == nil { return nil diff --git a/aws/datasync_test.go b/aws/datasync_test.go deleted file mode 100644 index f56cf7484fc5..000000000000 --- a/aws/datasync_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package aws - -import ( - "testing" -) - -func TestDataSyncParseLocationURI(t *testing.T) { - testCases := []struct { - LocationURI string - Subdirectory string - }{ - { - LocationURI: "efs://us-east-2.fs-abcd1234/", // lintignore:AWSAT003 - Subdirectory: "/", - }, - { - LocationURI: "efs://us-east-2.fs-abcd1234/path", // lintignore:AWSAT003 - Subdirectory: "/path", - }, - { - LocationURI: "nfs://example.com/", - Subdirectory: "/", - }, - { - LocationURI: "nfs://example.com/path", - Subdirectory: "/path", - }, - { - LocationURI: "s3://myBucket/", - Subdirectory: "/", - }, - { - LocationURI: "s3://myBucket/path", - Subdirectory: "/path", - }, - } - - for i, tc := range testCases { - subdirectory, err := dataSyncParseLocationURI(tc.LocationURI) - if err != nil { - t.Fatalf("%d: received error parsing (%s): %s", i, tc.LocationURI, err) - } - if subdirectory != tc.Subdirectory { - t.Fatalf("%d: expected subdirectory (%s), received: %s", i, tc.Subdirectory, subdirectory) - } - } -} diff --git a/aws/resource_aws_datasync_location_efs.go b/aws/resource_aws_datasync_location_efs.go index a8dc8f9782fb..45bba3607891 100644 --- a/aws/resource_aws_datasync_location_efs.go +++ b/aws/resource_aws_datasync_location_efs.go @@ -10,6 +10,7 @@ import ( "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" + tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync" ) func resourceAwsDataSyncLocationEfs() *schema.Resource { @@ -128,10 +129,10 @@ func resourceAwsDataSyncLocationEfsRead(d *schema.ResourceData, meta interface{} return fmt.Errorf("error reading DataSync Location EFS (%s): %s", d.Id(), err) } - subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri)) + subdirectory, err := tfdatasync.SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri)) if err != nil { - return fmt.Errorf("error parsing Location EFS (%s) URI (%s): %s", d.Id(), aws.StringValue(output.LocationUri), err) + return err } d.Set("arn", output.LocationArn) diff --git a/aws/resource_aws_datasync_location_fsx_windows_file_system.go b/aws/resource_aws_datasync_location_fsx_windows_file_system.go index b2e1651d7936..95b5ed9697c0 100644 --- a/aws/resource_aws_datasync_location_fsx_windows_file_system.go +++ b/aws/resource_aws_datasync_location_fsx_windows_file_system.go @@ -11,6 +11,7 @@ import ( "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" + tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync" ) func resourceAwsDataSyncLocationFsxWindowsFileSystem() *schema.Resource { @@ -155,10 +156,10 @@ func resourceAwsDataSyncLocationFsxWindowsFileSystemRead(d *schema.ResourceData, return fmt.Errorf("error reading DataSync Location Fsx Windows (%s): %w", d.Id(), err) } - subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri)) + subdirectory, err := tfdatasync.SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri)) if err != nil { - return fmt.Errorf("error parsing Location Fsx Windows File System (%s) URI (%s): %w", d.Id(), aws.StringValue(output.LocationUri), err) + return err } d.Set("arn", output.LocationArn) diff --git a/aws/resource_aws_datasync_location_nfs.go b/aws/resource_aws_datasync_location_nfs.go index 33a48542a068..fd00dceccb88 100644 --- a/aws/resource_aws_datasync_location_nfs.go +++ b/aws/resource_aws_datasync_location_nfs.go @@ -10,6 +10,7 @@ import ( "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" + tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync" ) func resourceAwsDataSyncLocationNfs() *schema.Resource { @@ -144,10 +145,10 @@ func resourceAwsDataSyncLocationNfsRead(d *schema.ResourceData, meta interface{} return fmt.Errorf("error reading DataSync Location NFS (%s): %w", d.Id(), err) } - subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri)) + subdirectory, err := tfdatasync.SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri)) if err != nil { - return fmt.Errorf("error parsing Location NFS (%s) URI (%s): %w", d.Id(), aws.StringValue(output.LocationUri), err) + return err } d.Set("arn", output.LocationArn) diff --git a/aws/resource_aws_datasync_location_s3.go b/aws/resource_aws_datasync_location_s3.go index 8fa5bf11f882..27bb510e251b 100644 --- a/aws/resource_aws_datasync_location_s3.go +++ b/aws/resource_aws_datasync_location_s3.go @@ -11,6 +11,7 @@ import ( "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" + tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync" iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" ) @@ -172,10 +173,10 @@ func resourceAwsDataSyncLocationS3Read(d *schema.ResourceData, meta interface{}) return fmt.Errorf("error reading DataSync Location S3 (%s): %s", d.Id(), err) } - subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri)) + subdirectory, err := tfdatasync.SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri)) if err != nil { - return fmt.Errorf("error parsing Location S3 (%s) URI (%s): %s", d.Id(), aws.StringValue(output.LocationUri), err) + return err } d.Set("agent_arns", flattenStringSet(output.AgentArns)) diff --git a/aws/resource_aws_datasync_location_smb.go b/aws/resource_aws_datasync_location_smb.go index ed0a76cb264d..211520eb7d4f 100644 --- a/aws/resource_aws_datasync_location_smb.go +++ b/aws/resource_aws_datasync_location_smb.go @@ -9,6 +9,7 @@ import ( "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" + tfdatasync "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/datasync" ) func resourceAwsDataSyncLocationSmb() *schema.Resource { @@ -164,10 +165,10 @@ func resourceAwsDataSyncLocationSmbRead(d *schema.ResourceData, meta interface{} return fmt.Errorf("error reading DataSync Location SMB (%s) tags: %w", d.Id(), err) } - subdirectory, err := dataSyncParseLocationURI(aws.StringValue(output.LocationUri)) + subdirectory, err := tfdatasync.SubdirectoryFromLocationURI(aws.StringValue(output.LocationUri)) if err != nil { - return fmt.Errorf("error parsing Location SMB (%s) URI (%s): %w", d.Id(), aws.StringValue(output.LocationUri), err) + return err } d.Set("agent_arns", flattenStringSet(output.AgentArns)) From 8cc7cd9cc5a46213760d542b6e67155061969db1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 17 Jun 2021 10:49:49 -0400 Subject: [PATCH 1049/1208] Add CHANGELOG entry. --- .changelog/19859.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19859.txt diff --git a/.changelog/19859.txt b/.changelog/19859.txt new file mode 100644 index 000000000000..92976607dfcf --- /dev/null +++ b/.changelog/19859.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_datasync_location_s3: Correctly parse S3 on Outposts location URI +``` \ No newline at end of file From 41c9ab8189cd39fda0d5f75ad4a2695edd0e6b3a Mon Sep 17 00:00:00 2001 From: Corentin Debains Date: Tue, 24 Mar 2020 18:50:26 -0700 Subject: [PATCH 1050/1208] RDS Bugfix - Replica creation with Allocated Storage and IOPS Ignore allocated storage while creating a Read Replica * Fixes Issue #12493 Tests: * The acceptance test (allocatedStorageAndIops that would be previously failing), shows the bug by setting up a Replica DB with both IOPS and Allocated storage. * Also Added an acceptance test for Iops modification to confirm code is ok because of the returned error message in the issue. Didn't show failures previously. Fix: * Ignore allocated storage when creating a read replica as this value cannot be different from the primary. * Update doc to reflect param handling difference. --- aws/resource_aws_db_instance.go | 8 +- aws/resource_aws_db_instance_test.go | 104 +++++++++++++++++++++++ website/docs/r/db_instance.html.markdown | 2 +- 3 files changed, 110 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index 91e5e0bd92f7..4d1ac5e39ab2 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -583,9 +583,11 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error Tags: tags.IgnoreAws().RdsTags(), } - if attr, ok := d.GetOk("allocated_storage"); ok { - modifyDbInstanceInput.AllocatedStorage = aws.Int64(int64(attr.(int))) - requiresModifyDbInstance = true + if _, ok := d.GetOk("allocated_storage"); ok { + log.Printf("[INFO] allocated_storage was ignored for DB Instance (%s) because it inherits the primary's and cannot be changed at creation.", d.Id()) + // RDS doesn't allow modifying the storage of a replica within the first 6h of creation. + // allocated_storage is inherited from the primary so only the same value or no value is correct; a different value would fail the creation. + // A different value is possible, granted: the value is higher than the current, there has been 6h between } if attr, ok := d.GetOk("availability_zone"); ok { diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 22130346aeb7..5d59b8a29b90 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -649,6 +649,57 @@ func TestAccAWSDBInstance_ReplicateSourceDb_AllocatedStorage(t *testing.T) { }) } +func TestAccAWSDBInstance_ReplicateSourceDb_Iops(t *testing.T) { + var dbInstance, sourceDbInstance rds.DBInstance + + rName := acctest.RandomWithPrefix("tf-acc-test") + sourceResourceName := "aws_db_instance.source" + resourceName := "aws_db_instance.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDBInstanceConfig_ReplicateSourceDb_Iops(rName, 1000), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists(sourceResourceName, &sourceDbInstance), + testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), + testAccCheckAWSDBInstanceReplicaAttributes(&sourceDbInstance, &dbInstance), + resource.TestCheckResourceAttr(resourceName, "iops", "1000"), + ), + }, + }, + }) +} + +func TestAccAWSDBInstance_ReplicateSourceDb_AllocatedStorageAndIops(t *testing.T) { + var dbInstance, sourceDbInstance rds.DBInstance + + rName := acctest.RandomWithPrefix("tf-acc-test") + sourceResourceName := "aws_db_instance.source" + resourceName := "aws_db_instance.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDBInstanceConfig_ReplicateSourceDb_AllocatedStorageAndIops(rName, 220, 2200), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists(sourceResourceName, &sourceDbInstance), + testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), + testAccCheckAWSDBInstanceReplicaAttributes(&sourceDbInstance, &dbInstance), + resource.TestCheckResourceAttr(resourceName, "allocated_storage", "220"), + resource.TestCheckResourceAttr(resourceName, "iops", "2200"), + ), + }, + }, + }) +} + func TestAccAWSDBInstance_ReplicateSourceDb_AllowMajorVersionUpgrade(t *testing.T) { var dbInstance, sourceDbInstance rds.DBInstance @@ -5387,6 +5438,59 @@ resource "aws_db_instance" "test" { `, rName, allocatedStorage)) } +func testAccAWSDBInstanceConfig_ReplicateSourceDb_Iops(rName string, iops int) string { + return fmt.Sprintf(` +resource "aws_db_instance" "source" { + allocated_storage = 200 + backup_retention_period = 1 + engine = "mysql" + identifier = "%s-source" + instance_class = "db.t2.micro" + password = "avoid-plaintext-passwords" + username = "tfacctest" + skip_final_snapshot = true + iops = 1100 + storage_type = "io1" +} + +resource "aws_db_instance" "test" { + identifier = %q + instance_class = "${aws_db_instance.source.instance_class}" + replicate_source_db = "${aws_db_instance.source.id}" + skip_final_snapshot = true + iops = %d + storage_type = "io1" +} +`, rName, rName, iops) +} + +func testAccAWSDBInstanceConfig_ReplicateSourceDb_AllocatedStorageAndIops(rName string, allocatedStorage, iops int) string { + return fmt.Sprintf(` +resource "aws_db_instance" "source" { + allocated_storage = %[2]d + backup_retention_period = 1 + engine = "mysql" + identifier = "%[1]s-source" + instance_class = "db.t2.micro" + password = "avoid-plaintext-passwords" + username = "tfacctest" + skip_final_snapshot = true + iops = 1000 + storage_type = "io1" +} + +resource "aws_db_instance" "test" { + allocated_storage = %[2]d + identifier = %[1]q + instance_class = "${aws_db_instance.source.instance_class}" + replicate_source_db = "${aws_db_instance.source.id}" + skip_final_snapshot = true + iops = %[3]d + storage_type = "io1" +} +`, rName, allocatedStorage, iops) +} + func testAccAWSDBInstanceConfig_ReplicateSourceDb_AllowMajorVersionUpgrade(rName string, allowMajorVersionUpgrade bool) string { return composeConfig(testAccAWSDBInstanceConfig_orderableClassMysql(), fmt.Sprintf(` resource "aws_db_instance" "source" { diff --git a/website/docs/r/db_instance.html.markdown b/website/docs/r/db_instance.html.markdown index d24318f255d1..174ef4258555 100644 --- a/website/docs/r/db_instance.html.markdown +++ b/website/docs/r/db_instance.html.markdown @@ -74,7 +74,7 @@ documentation](http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_Crea The following arguments are supported: -* `allocated_storage` - (Required unless a `snapshot_identifier` or `replicate_source_db` is provided) The allocated storage in gibibytes. If `max_allocated_storage` is configured, this argument represents the initial storage allocation and differences from the configuration will be ignored automatically when Storage Autoscaling occurs. +* `allocated_storage` - (Required unless a `snapshot_identifier` or `replicate_source_db` is provided) The allocated storage in gibibytes. If `max_allocated_storage` is configured, this argument represents the initial storage allocation and differences from the configuration will be ignored automatically when Storage Autoscaling occurs. If `replicate_source_db` is set, the value is ignored during the creation of the instance. * `allow_major_version_upgrade` - (Optional) Indicates that major version upgrades are allowed. Changing this parameter does not result in an outage and the change is asynchronously applied as soon as possible. From 7b2203ed051e3ee63db6d2b6e1e8568b4cd89633 Mon Sep 17 00:00:00 2001 From: Corentin Debains Date: Thu, 26 Mar 2020 16:33:58 -0700 Subject: [PATCH 1051/1208] Update aws/resource_aws_db_instance.go Co-Authored-By: Muffy Barkocy --- aws/resource_aws_db_instance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index 4d1ac5e39ab2..a9c2ed0be761 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -584,7 +584,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } if _, ok := d.GetOk("allocated_storage"); ok { - log.Printf("[INFO] allocated_storage was ignored for DB Instance (%s) because it inherits the primary's and cannot be changed at creation.", d.Id()) + log.Printf("[INFO] allocated_storage was ignored for DB Instance (%s) because a replica inherits the primary's allocated_storage and this cannot be changed at creation.", d.Id()) // RDS doesn't allow modifying the storage of a replica within the first 6h of creation. // allocated_storage is inherited from the primary so only the same value or no value is correct; a different value would fail the creation. // A different value is possible, granted: the value is higher than the current, there has been 6h between From 3030e8e48ccceeb73593459d31ef874f20844bab Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Thu, 8 Jul 2021 22:39:05 -0400 Subject: [PATCH 1052/1208] enhanced error with client handler and minor updates --- aws/config.go | 5 +- aws/configservice.go | 72 ++++++++++++++----- ...ws_config_organization_conformance_pack.go | 32 +++------ ...nfig_organization_conformance_pack_test.go | 14 ++-- ...rganization_conformance_pack.html.markdown | 1 + 5 files changed, 77 insertions(+), 47 deletions(-) diff --git a/aws/config.go b/aws/config.go index cf4a742d3632..56cc8b205bc1 100644 --- a/aws/config.go +++ b/aws/config.go @@ -729,8 +729,11 @@ func (c *Config) Client() (interface{}, error) { } else { r.Retryable = aws.Bool(false) } - case "PutOrganizationConformancePack", "DeleteOrganizationConformancePack", "DescribeOrganizationConformancePackStatuses": + case "DeleteOrganizationConformancePack", "DescribeOrganizationConformancePacks", "DescribeOrganizationConformancePackStatuses", "PutOrganizationConformancePack": if !tfawserr.ErrCodeEquals(r.Error, configservice.ErrCodeOrganizationAccessDeniedException) { + if r.Operation.Name == "DeleteOrganizationConformancePack" && tfawserr.ErrCodeEquals(err, configservice.ErrCodeResourceInUseException) { + r.Retryable = aws.Bool(true) + } return } diff --git a/aws/configservice.go b/aws/configservice.go index 124a5728c9a7..9170c2af1492 100644 --- a/aws/configservice.go +++ b/aws/configservice.go @@ -17,7 +17,7 @@ const ( ConfigOrganizationConformancePackCreateTimeout = 10 * time.Minute ConfigOrganizationConformancePackUpdateTimeout = 10 * time.Minute - ConfigOrganizationConformancePackDeleteTimeout = 10 * time.Minute + ConfigOrganizationConformancePackDeleteTimeout = 20 * time.Minute ConfigConformancePackStatusNotFound = "NotFound" ConfigConformancePackStatusUnknown = "Unknown" @@ -310,10 +310,16 @@ func configRefreshOrganizationConfigRuleStatus(conn *configservice.ConfigService } } -func configRefreshOrganizationConformancePackStatus(conn *configservice.ConfigService, name string) resource.StateRefreshFunc { +func configRefreshOrganizationConformancePackCreationStatus(conn *configservice.ConfigService, name string) resource.StateRefreshFunc { return func() (interface{}, string, error) { status, err := configDescribeOrganizationConformancePackStatus(conn, name) + // Transient ResourceDoesNotExist error after creation caught here + // in cases where the StateChangeConf's delay time is not sufficient + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchOrganizationConformancePackException) { + return nil, "", nil + } + if err != nil { return nil, "", err } @@ -326,28 +332,56 @@ func configRefreshOrganizationConformancePackStatus(conn *configservice.ConfigSe return status, aws.StringValue(status.Status), fmt.Errorf("%s: %s", aws.StringValue(status.ErrorCode), aws.StringValue(status.ErrorMessage)) } - switch aws.StringValue(status.Status) { + switch s := aws.StringValue(status.Status); s { case configservice.OrganizationResourceStatusCreateFailed, configservice.OrganizationResourceStatusDeleteFailed, configservice.OrganizationResourceStatusUpdateFailed: - // Display detailed errors for failed member accounts - memberAccountStatuses, err := configGetOrganizationConformancePackDetailedStatus(conn, name, aws.StringValue(status.Status)) + return status, s, configOrganizationConformancePackDetailedStatusError(conn, name, s) + } - if err != nil { - return status, aws.StringValue(status.Status), fmt.Errorf("unable to get Config Organization Conformance Pack detailed status for showing member account errors: %w", err) - } + return status, aws.StringValue(status.Status), nil + } +} - var errBuilder strings.Builder +func configRefreshOrganizationConformancePackStatus(conn *configservice.ConfigService, name string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + status, err := configDescribeOrganizationConformancePackStatus(conn, name) - for _, mas := range memberAccountStatuses { - errBuilder.WriteString(fmt.Sprintf("Account ID (%s): %s: %s\n", aws.StringValue(mas.AccountId), aws.StringValue(mas.ErrorCode), aws.StringValue(mas.ErrorMessage))) - } + if err != nil { + return nil, "", err + } + + if status == nil { + return nil, "", nil + } + + if status.ErrorCode != nil { + return status, aws.StringValue(status.Status), fmt.Errorf("%s: %s", aws.StringValue(status.ErrorCode), aws.StringValue(status.ErrorMessage)) + } - return status, aws.StringValue(status.Status), fmt.Errorf("Failed in %d account(s):\n\n%s", len(memberAccountStatuses), errBuilder.String()) + switch s := aws.StringValue(status.Status); s { + case configservice.OrganizationResourceStatusCreateFailed, configservice.OrganizationResourceStatusDeleteFailed, configservice.OrganizationResourceStatusUpdateFailed: + return status, s, configOrganizationConformancePackDetailedStatusError(conn, name, s) } return status, aws.StringValue(status.Status), nil } } +func configOrganizationConformancePackDetailedStatusError(conn *configservice.ConfigService, name, status string) error { + memberAccountStatuses, err := configGetOrganizationConformancePackDetailedStatus(conn, name, status) + + if err != nil { + return fmt.Errorf("unable to get Config Organization Conformance Pack detailed status for showing member account errors: %w", err) + } + + var errBuilder strings.Builder + + for _, mas := range memberAccountStatuses { + errBuilder.WriteString(fmt.Sprintf("Account ID (%s): %s: %s\n", aws.StringValue(mas.AccountId), aws.StringValue(mas.ErrorCode), aws.StringValue(mas.ErrorMessage))) + } + + return fmt.Errorf("Failed in %d account(s):\n\n%s", len(memberAccountStatuses), errBuilder.String()) +} + func configWaitForConformancePackStateCreateComplete(conn *configservice.ConfigService, name string) error { stateChangeConf := resource.StateChangeConf{ Pending: []string{configservice.ConformancePackStateCreateInProgress}, @@ -358,6 +392,10 @@ func configWaitForConformancePackStateCreateComplete(conn *configservice.ConfigS _, err := stateChangeConf.WaitForState() + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchConformancePackException) { + return nil + } + return err } @@ -384,8 +422,8 @@ func configWaitForOrganizationConformancePackStatusCreateSuccessful(conn *config Pending: []string{configservice.OrganizationResourceStatusCreateInProgress}, Target: []string{configservice.OrganizationResourceStatusCreateSuccessful}, Timeout: ConfigOrganizationConformancePackCreateTimeout, - Refresh: configRefreshOrganizationConformancePackStatus(conn, name), - // Include a Delay to avoid transient error + Refresh: configRefreshOrganizationConformancePackCreationStatus(conn, name), + // Include a delay to help avoid ResourceDoesNotExist errors Delay: 30 * time.Second, } @@ -418,10 +456,6 @@ func configWaitForOrganizationConformancePackStatusDeleteSuccessful(conn *config _, err := stateChangeConf.WaitForState() - if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchOrganizationConformancePackException) { - return nil - } - return err } diff --git a/aws/resource_aws_config_organization_conformance_pack.go b/aws/resource_aws_config_organization_conformance_pack.go index 7f98d636f952..0e888a332633 100644 --- a/aws/resource_aws_config_organization_conformance_pack.go +++ b/aws/resource_aws_config_organization_conformance_pack.go @@ -8,10 +8,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/configservice" "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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/tfresource" ) func resourceAwsConfigOrganizationConformancePack() *schema.Resource { @@ -106,7 +104,8 @@ func resourceAwsConfigOrganizationConformancePackCreate(d *schema.ResourceData, conn := meta.(*AWSClient).configconn name := d.Get("name").(string) - input := configservice.PutOrganizationConformancePackInput{ + + input := &configservice.PutOrganizationConformancePackInput{ OrganizationConformancePackName: aws.String(name), } @@ -134,7 +133,7 @@ func resourceAwsConfigOrganizationConformancePackCreate(d *schema.ResourceData, input.TemplateS3Uri = aws.String(v.(string)) } - _, err := conn.PutOrganizationConformancePack(&input) + _, err := conn.PutOrganizationConformancePack(input) if err != nil { return fmt.Errorf("error creating Config Organization Conformance Pack (%s): %w", name, err) @@ -193,7 +192,7 @@ func resourceAwsConfigOrganizationConformancePackRead(d *schema.ResourceData, me func resourceAwsConfigOrganizationConformancePackUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).configconn - input := configservice.PutOrganizationConformancePackInput{ + input := &configservice.PutOrganizationConformancePackInput{ OrganizationConformancePackName: aws.String(d.Id()), } @@ -221,7 +220,7 @@ func resourceAwsConfigOrganizationConformancePackUpdate(d *schema.ResourceData, input.TemplateS3Uri = aws.String(v.(string)) } - _, err := conn.PutOrganizationConformancePack(&input) + _, err := conn.PutOrganizationConformancePack(input) if err != nil { return fmt.Errorf("error updating Config Organization Conformance Pack (%s): %w", d.Id(), err) @@ -241,23 +240,7 @@ func resourceAwsConfigOrganizationConformancePackDelete(d *schema.ResourceData, OrganizationConformancePackName: aws.String(d.Id()), } - err := resource.Retry(ConfigOrganizationConformancePackDeleteTimeout, func() *resource.RetryError { - _, err := conn.DeleteOrganizationConformancePack(input) - - if err != nil { - if tfawserr.ErrCodeEquals(err, configservice.ErrCodeResourceInUseException) { - return resource.RetryableError(err) - } - - return resource.NonRetryableError(err) - } - - return nil - }) - - if tfresource.TimedOut(err) { - _, err = conn.DeleteOrganizationConformancePack(input) - } + _, err := conn.DeleteOrganizationConformancePack(input) if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchOrganizationConformancePackException) { return nil @@ -268,6 +251,9 @@ func resourceAwsConfigOrganizationConformancePackDelete(d *schema.ResourceData, } if err := configWaitForOrganizationConformancePackStatusDeleteSuccessful(conn, d.Id()); err != nil { + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeNoSuchOrganizationConformancePackException) { + return nil + } return fmt.Errorf("error waiting for Config Organization Conformance Pack (%s) to be deleted: %w", d.Id(), err) } diff --git a/aws/resource_aws_config_organization_conformance_pack_test.go b/aws/resource_aws_config_organization_conformance_pack_test.go index d4ac03ea8d7b..585431da0326 100644 --- a/aws/resource_aws_config_organization_conformance_pack_test.go +++ b/aws/resource_aws_config_organization_conformance_pack_test.go @@ -32,7 +32,7 @@ func testAccConfigOrganizationConformancePack_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", ""), resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", ""), - resource.TestCheckResourceAttr(resourceName, "input_parameters.#", "0"), + resource.TestCheckResourceAttr(resourceName, "input_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "excluded_accounts.#", "0"), ), }, @@ -175,8 +175,8 @@ func testAccConfigOrganizationConformancePack_inputParameters(t *testing.T) { Config: testAccConfigOrganizationConformancePackInputParameterConfig(rName, pKey, pValue), Check: resource.ComposeTestCheckFunc( testAccCheckConfigOrganizationConformancePackExists(resourceName, &pack), - resource.TestCheckResourceAttr(resourceName, "input_parameters.#", "1"), - resource.TestCheckTypeSetElemNestedAttrs(resourceName, "input_parameters.*", map[string]string{ + resource.TestCheckResourceAttr(resourceName, "input_parameter.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "input_parameter.*", map[string]string{ "parameter_name": pKey, "parameter_value": pValue, }), @@ -241,7 +241,7 @@ func testAccConfigOrganizationConformancePack_S3Template(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "delivery_s3_bucket", ""), resource.TestCheckResourceAttr(resourceName, "delivery_s3_key_prefix", ""), - resource.TestCheckResourceAttr(resourceName, "input_parameters.#", "0"), + resource.TestCheckResourceAttr(resourceName, "input_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "excluded_accounts.#", "0"), ), }, @@ -424,6 +424,12 @@ func testAccCheckConfigOrganizationConformancePackDestroy(s *terraform.State) er continue } + // In the event the Organizations Organization is deleted first, its Conformance Packs + // are deleted and we can continue through the loop + if tfawserr.ErrCodeEquals(err, configservice.ErrCodeOrganizationAccessDeniedException) { + continue + } + if err != nil { return fmt.Errorf("error describing Config Organization Conformance Pack (%s): %w", rs.Primary.ID, err) } diff --git a/website/docs/r/config_organization_conformance_pack.html.markdown b/website/docs/r/config_organization_conformance_pack.html.markdown index b37989965586..27d5ba5adf88 100644 --- a/website/docs/r/config_organization_conformance_pack.html.markdown +++ b/website/docs/r/config_organization_conformance_pack.html.markdown @@ -107,6 +107,7 @@ The `input_parameter` configuration block supports the following arguments: In addition to all arguments above, the following attributes are exported: * `arn` - Amazon Resource Name (ARN) of the organization conformance pack. +* `id` - The name of the organization conformance pack. ## Import From 3a527d4ecab7d0716d3c1bbcc009810578e72bc3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Jul 2021 06:09:33 +0000 Subject: [PATCH 1053/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.39.2 to 1.39.3. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.39.2...v1.39.3) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 +-- .../aws/aws-sdk-go/aws/endpoints/defaults.go | 30 +++++++++++++++++-- .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index bdd8e8498288..c457e5dd1a16 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.39.2 + github.com/aws/aws-sdk-go v1.39.3 github.com/bflad/tfproviderlint v0.27.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 834e806f661f..4816e45d0e37 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -70,8 +70,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.39.2 h1:t+n2j0QfAmGqSQVb1VIGulhSMjfaZ/RqSGlcRKGED9Y= -github.com/aws/aws-sdk-go v1.39.2/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go v1.39.3 h1:JMDk7p+AV89MdVy/ZcFWAGivWIE3vXOsRriFjFWVcIY= +github.com/aws/aws-sdk-go v1.39.3/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.27.0 h1:KXF+dYaWJ/OSVyWIrk2NIYgQBMDDSOC4VQB/P+P5nhI= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index ec4a25cd3f32..cebbe397201a 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -648,9 +648,33 @@ var awsPartition = partition{ "eu-north-1": endpoint{}, "eu-west-1": endpoint{}, "eu-west-2": endpoint{}, - "us-east-1": endpoint{}, - "us-east-2": endpoint{}, - "us-west-2": endpoint{}, + "fips-ca-central-1": endpoint{ + Hostname: "api.fleethub.iot-fips.ca-central-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "ca-central-1", + }, + }, + "fips-us-east-1": endpoint{ + Hostname: "api.fleethub.iot-fips.us-east-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-1", + }, + }, + "fips-us-east-2": endpoint{ + Hostname: "api.fleethub.iot-fips.us-east-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-east-2", + }, + }, + "fips-us-west-2": endpoint{ + Hostname: "api.fleethub.iot-fips.us-west-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-west-2", + }, + }, + "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-2": endpoint{}, }, }, "api.mediatailor": service{ diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index 3fb3be1d54d9..19a602480f06 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.39.2" +const SDKVersion = "1.39.3" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 87f7b43fbb1c..6f58fbb8f972 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.39.2 +# github.com/aws/aws-sdk-go v1.39.3 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 4711564e98cc51efba4e08430f8b0bfead1db445 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Jul 2021 06:12:30 +0000 Subject: [PATCH 1054/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.39.2 to 1.39.3 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.39.2 to 1.39.3. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.39.2...v1.39.3) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f8902716b7cf..4e23c51ff636 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect - github.com/aws/aws-sdk-go v1.39.2 + github.com/aws/aws-sdk-go v1.39.3 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index d87b7997d6f8..c0acb2cd1b68 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.39.2 h1:t+n2j0QfAmGqSQVb1VIGulhSMjfaZ/RqSGlcRKGED9Y= -github.com/aws/aws-sdk-go v1.39.2/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go v1.39.3 h1:JMDk7p+AV89MdVy/ZcFWAGivWIE3vXOsRriFjFWVcIY= +github.com/aws/aws-sdk-go v1.39.3/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 1914930b037d0d275abd7f099f4c92af55a7c543 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 9 Jul 2021 11:41:17 -0400 Subject: [PATCH 1055/1208] r/aws_directory_service_directory: Add and use internal finder and waiter packages. --- .../service/directoryservice/finder/finder.go | 48 ++++++++++ .../service/directoryservice/waiter/status.go | 25 +++++ .../service/directoryservice/waiter/waiter.go | 54 +++++++++++ ...esource_aws_directory_service_directory.go | 93 ++++--------------- 4 files changed, 143 insertions(+), 77 deletions(-) create mode 100644 aws/internal/service/directoryservice/finder/finder.go create mode 100644 aws/internal/service/directoryservice/waiter/status.go create mode 100644 aws/internal/service/directoryservice/waiter/waiter.go diff --git a/aws/internal/service/directoryservice/finder/finder.go b/aws/internal/service/directoryservice/finder/finder.go new file mode 100644 index 000000000000..3ce7a870786b --- /dev/null +++ b/aws/internal/service/directoryservice/finder/finder.go @@ -0,0 +1,48 @@ +package finder + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/directoryservice" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func DirectoryByID(conn *directoryservice.DirectoryService, id string) (*directoryservice.DirectoryDescription, error) { + input := &directoryservice.DescribeDirectoriesInput{ + DirectoryIds: aws.StringSlice([]string{id}), + } + + output, err := conn.DescribeDirectories(input) + + if tfawserr.ErrCodeEquals(err, directoryservice.ErrCodeEntityDoesNotExistException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || len(output.DirectoryDescriptions) == 0 || output.DirectoryDescriptions[0] == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + // TODO Check for multiple results. + // TODO https://github.com/hashicorp/terraform-provider-aws/pull/17613. + + directory := output.DirectoryDescriptions[0] + + if stage := aws.StringValue(directory.Stage); stage == directoryservice.DirectoryStageDeleted { + return nil, &resource.NotFoundError{ + Message: stage, + LastRequest: input, + } + } + + return directory, nil +} diff --git a/aws/internal/service/directoryservice/waiter/status.go b/aws/internal/service/directoryservice/waiter/status.go new file mode 100644 index 000000000000..7f6796238b25 --- /dev/null +++ b/aws/internal/service/directoryservice/waiter/status.go @@ -0,0 +1,25 @@ +package waiter + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/directoryservice" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directoryservice/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func DirectoryStage(conn *directoryservice.DirectoryService, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.DirectoryByID(conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.Stage), nil + } +} diff --git a/aws/internal/service/directoryservice/waiter/waiter.go b/aws/internal/service/directoryservice/waiter/waiter.go new file mode 100644 index 000000000000..47ad07a5606b --- /dev/null +++ b/aws/internal/service/directoryservice/waiter/waiter.go @@ -0,0 +1,54 @@ +package waiter + +import ( + "errors" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/directoryservice" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +const ( + DirectoryCreatedTimeout = 60 * time.Minute + DirectoryDeletedTimeout = 60 * time.Minute +) + +func DirectoryCreated(conn *directoryservice.DirectoryService, id string) (*directoryservice.DirectoryDescription, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{directoryservice.DirectoryStageRequested, directoryservice.DirectoryStageCreating, directoryservice.DirectoryStageCreated}, + Target: []string{directoryservice.DirectoryStageActive}, + Refresh: DirectoryStage(conn, id), + Timeout: DirectoryCreatedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*directoryservice.DirectoryDescription); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StageReason))) + + return output, err + } + + return nil, err +} + +func DirectoryDeleted(conn *directoryservice.DirectoryService, id string) (*directoryservice.DirectoryDescription, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{directoryservice.DirectoryStageActive, directoryservice.DirectoryStageDeleting}, + Target: []string{}, + Refresh: DirectoryStage(conn, id), + Timeout: DirectoryDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*directoryservice.DirectoryDescription); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.StageReason))) + + return output, err + } + + return nil, err +} diff --git a/aws/resource_aws_directory_service_directory.go b/aws/resource_aws_directory_service_directory.go index ca74e62535e0..ba64d8030083 100644 --- a/aws/resource_aws_directory_service_directory.go +++ b/aws/resource_aws_directory_service_directory.go @@ -3,15 +3,16 @@ package aws import ( "fmt" "log" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directoryservice" "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directoryservice/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/directoryservice/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsDirectoryServiceDirectory() *schema.Resource { @@ -387,35 +388,10 @@ func resourceAwsDirectoryServiceDirectoryCreate(d *schema.ResourceData, meta int d.SetId(directoryId) - // Wait for creation - log.Printf("[DEBUG] Waiting for DS (%q) to become available", d.Id()) - stateConf := &resource.StateChangeConf{ - Pending: []string{ - directoryservice.DirectoryStageRequested, - directoryservice.DirectoryStageCreating, - directoryservice.DirectoryStageCreated, - }, - Target: []string{directoryservice.DirectoryStageActive}, - Refresh: func() (interface{}, string, error) { - resp, err := dsconn.DescribeDirectories(&directoryservice.DescribeDirectoriesInput{ - DirectoryIds: []*string{aws.String(d.Id())}, - }) - if err != nil { - log.Printf("Error during creation of DS: %q", err.Error()) - return nil, "", err - } - - ds := resp.DirectoryDescriptions[0] - log.Printf("[DEBUG] Creation of DS %q is in following stage: %q.", - d.Id(), *ds.Stage) - return ds, *ds.Stage, nil - }, - Timeout: 60 * time.Minute, - } - if _, err := stateConf.WaitForState(); err != nil { - return fmt.Errorf( - "Error waiting for Directory Service (%s) to become available: %s", - d.Id(), err) + _, err = waiter.DirectoryCreated(dsconn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for Directory Service Directory (%s) to create: %w", d.Id(), err) } if v, ok := d.GetOk("alias"); ok { @@ -468,22 +444,18 @@ func resourceAwsDirectoryServiceDirectoryRead(d *schema.ResourceData, meta inter defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - input := directoryservice.DescribeDirectoriesInput{ - DirectoryIds: []*string{aws.String(d.Id())}, - } - out, err := dsconn.DescribeDirectories(&input) - if err != nil { - return err - - } + dir, err := finder.DirectoryByID(dsconn, d.Id()) - if len(out.DirectoryDescriptions) == 0 { - log.Printf("[WARN] Directory %s not found", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Directory Service Directory (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - dir := out.DirectoryDescriptions[0] + if err != nil { + return fmt.Errorf("error reading Directory Service Directory (%s): %w", d.Id(), err) + } + log.Printf("[DEBUG] Received DS directory: %s", dir) d.Set("access_url", dir.AccessUrl) @@ -554,44 +526,11 @@ func resourceAwsDirectoryServiceDirectoryDelete(d *schema.ResourceData, meta int return fmt.Errorf("error deleting Directory Service Directory (%s): %w", d.Id(), err) } - err = waitForDirectoryServiceDirectoryDeletion(conn, d.Id()) + _, err = waiter.DirectoryDeleted(conn, d.Id()) if err != nil { - return fmt.Errorf("error waiting for Directory Service (%s) to be deleted: %w", d.Id(), err) + return fmt.Errorf("error waiting for Directory Service Directory (%s) to delete: %w", d.Id(), err) } return nil } - -func waitForDirectoryServiceDirectoryDeletion(conn *directoryservice.DirectoryService, directoryID string) error { - stateConf := &resource.StateChangeConf{ - Pending: []string{ - directoryservice.DirectoryStageActive, - directoryservice.DirectoryStageDeleting, - }, - Target: []string{directoryservice.DirectoryStageDeleted}, - Refresh: func() (interface{}, string, error) { - resp, err := conn.DescribeDirectories(&directoryservice.DescribeDirectoriesInput{ - DirectoryIds: []*string{aws.String(directoryID)}, - }) - if err != nil { - if isAWSErr(err, directoryservice.ErrCodeEntityDoesNotExistException, "") { - return 42, directoryservice.DirectoryStageDeleted, nil - } - return nil, "error", err - } - - if len(resp.DirectoryDescriptions) == 0 || resp.DirectoryDescriptions[0] == nil { - return 42, directoryservice.DirectoryStageDeleted, nil - } - - ds := resp.DirectoryDescriptions[0] - log.Printf("[DEBUG] Deletion of Directory Service Directory %q is in following stage: %q.", directoryID, aws.StringValue(ds.Stage)) - return ds, aws.StringValue(ds.Stage), nil - }, - Timeout: 60 * time.Minute, - } - _, err := stateConf.WaitForState() - - return err -} From e75ba1b21cc08e273c8734cb42e1f746064baff6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 9 Jul 2021 11:46:58 -0400 Subject: [PATCH 1056/1208] Configuration changes for 'TestAccAwsDxGatewayAssociation_recreateProposal'. --- ...ws_dx_gateway_association_proposal_test.go | 10 ------ ...esource_aws_dx_gateway_association_test.go | 32 +++++++++++++++++-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index 700ae9ec673f..5cc620a05208 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -351,16 +351,6 @@ func testAccCheckAwsDxGatewayAssociationProposalRecreated(old, new *directconnec } } -// func testAccCheckAwsDxGatewayAssociationProposalNotRecreated(old, new *directconnect.GatewayAssociationProposal) resource.TestCheckFunc { -// return func(s *terraform.State) error { -// if old, new := aws.StringValue(old.ProposalId), aws.StringValue(new.ProposalId); old != new { -// return fmt.Errorf("Direct Connect Gateway Association Proposal (%s) recreated (%s)", old, new) -// } - -// return nil -// } -// } - func testAccCheckAwsDxGatewayAssociationProposalAccepted(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] diff --git a/aws/resource_aws_dx_gateway_association_test.go b/aws/resource_aws_dx_gateway_association_test.go index 6578f18265e0..9a72d222fea8 100644 --- a/aws/resource_aws_dx_gateway_association_test.go +++ b/aws/resource_aws_dx_gateway_association_test.go @@ -463,7 +463,6 @@ func TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewayCrossAccount(t *tes func TestAccAwsDxGatewayAssociation_recreateProposal(t *testing.T) { var providers []*schema.Provider resourceName := "aws_dx_gateway_association.test" - resourceNameProposal := "aws_dx_gateway_association_proposal.test" rName := acctest.RandomWithPrefix("tf-acc-test") rBgpAsn := acctest.RandIntRange(64512, 65534) var ga1, ga2 directconnect.GatewayAssociation @@ -482,13 +481,12 @@ func TestAccAwsDxGatewayAssociation_recreateProposal(t *testing.T) { ), }, { - Config: testAccDxGatewayAssociationConfig_basicVpnGatewayCrossAccount(rName, rBgpAsn), + Config: testAccDxGatewayAssociationConfig_basicVpnGatewayCrossAccountUpdatedProposal(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName, &ga2, &gap2), testAccCheckAwsDxGatewayAssociationNotRecreated(&ga1, &ga2), testAccCheckAwsDxGatewayAssociationProposalRecreated(&gap1, &gap2), ), - Taint: []string{resourceNameProposal}, }, }, }) @@ -701,6 +699,34 @@ resource "aws_dx_gateway_association" "test" { `) } +func testAccDxGatewayAssociationConfig_basicVpnGatewayCrossAccountUpdatedProposal(rName string, rBgpAsn int) string { + return composeConfig( + testAccDxGatewayAssociationConfigBase_vpnGatewayCrossAccount(rName, rBgpAsn), + ` +# Creator +resource "aws_dx_gateway_association_proposal" "test" { + dx_gateway_id = aws_dx_gateway.test.id + dx_gateway_owner_account_id = aws_dx_gateway.test.owner_account_id + associated_gateway_id = aws_vpn_gateway_attachment.test.vpn_gateway_id +} + +resource "aws_dx_gateway_association_proposal" "test2" { + dx_gateway_id = aws_dx_gateway.test.id + dx_gateway_owner_account_id = aws_dx_gateway.test.owner_account_id + associated_gateway_id = aws_vpn_gateway_attachment.test.vpn_gateway_id + } + +# Accepter +resource "aws_dx_gateway_association" "test" { + provider = "awsalternate" + + proposal_id = aws_dx_gateway_association_proposal.test2.id + dx_gateway_id = aws_dx_gateway.test.id + associated_gateway_owner_account_id = data.aws_caller_identity.creator.account_id +} +`) +} + func testAccDxGatewayAssociationConfig_basicTransitGatewaySingleAccount(rName string, rBgpAsn int) string { return fmt.Sprintf(` resource "aws_dx_gateway" "test" { From 27618a9b5b573e9bf85635ec6ba7f724bdf0796f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 9 Jul 2021 12:07:08 -0400 Subject: [PATCH 1057/1208] Add CHANGELOG entry. --- .changelog/20031.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changelog/20031.txt diff --git a/.changelog/20031.txt b/.changelog/20031.txt new file mode 100644 index 000000000000..833dab213509 --- /dev/null +++ b/.changelog/20031.txt @@ -0,0 +1,11 @@ +```release-note:bug +resource/aws_cognito_user_pool_client: Retry on `ConcurrentModificationException` +``` + +```release-note:bug +resource/aws_cognito_user_pool_client: Allow the `default_redirect_uri` argument value to be an empty string +``` + +```release-note:enhancement +resource/aws_cognito_user_pool_client: Add the `enable_token_revocation` argument to support targeted sign out +``` \ No newline at end of file From 1983631376fc8eb37a8a627bd225b70b44df3c7f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 9 Jul 2021 12:23:58 -0400 Subject: [PATCH 1058/1208] r/db_instance: Clean up arguments --- aws/resource_aws_db_instance.go | 450 ++++++++++++++------------------ 1 file changed, 196 insertions(+), 254 deletions(-) diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index a9c2ed0be761..79458ce4c7ad 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -44,36 +44,137 @@ func resourceAwsDbInstance() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { + "address": { Type: schema.TypeString, - Optional: true, Computed: true, - ForceNew: true, }, + "allocated_storage": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + mas := d.Get("max_allocated_storage").(int) + + newInt, err := strconv.Atoi(new) + if err != nil { + return false + } + + oldInt, err := strconv.Atoi(old) + + if err != nil { + return false + } + + // Allocated is higher than the configuration + // and autoscaling is enabled + if oldInt > newInt && mas > newInt { + return true + } + + return false + }, + }, + "allow_major_version_upgrade": { + Type: schema.TypeBool, + Optional: true, + }, + // apply_immediately is used to determine when the update modifications + // take place. + // See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html + "apply_immediately": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, "arn": { Type: schema.TypeString, Computed: true, }, - - "username": { + "auto_minor_version_upgrade": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "availability_zone": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, - - "password": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, + "backup_retention_period": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "backup_window": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validateOnceADayWindowFormat, + }, + "ca_cert_identifier": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "character_set_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "copy_tags_to_snapshot": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "db_subnet_group_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "delete_automated_backups": { + Type: schema.TypeBool, + Optional: true, + Default: true, }, - "deletion_protection": { Type: schema.TypeBool, Optional: true, }, - + "domain": { + Type: schema.TypeString, + Optional: true, + }, + "domain_iam_role_name": { + Type: schema.TypeString, + Optional: true, + }, + "enabled_cloudwatch_logs_exports": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + "agent", + "alert", + "audit", + "error", + "general", + "listener", + "slowquery", + "trace", + "postgresql", + "upgrade", + }, false), + }, + }, + "endpoint": { + Type: schema.TypeString, + Computed: true, + }, "engine": { Type: schema.TypeString, Optional: true, @@ -84,68 +185,30 @@ func resourceAwsDbInstance() *schema.Resource { return strings.ToLower(value) }, }, - "engine_version": { Type: schema.TypeString, Optional: true, Computed: true, DiffSuppressFunc: suppressAwsDbEngineVersionDiffs, }, - - "ca_cert_identifier": { + "final_snapshot_identifier": { Type: schema.TypeString, Optional: true, - Computed: true, + ValidateFunc: validation.All( + validation.StringMatch(regexp.MustCompile(`^[A-Za-z]`), "must begin with alphabetic character"), + validation.StringMatch(regexp.MustCompile(`^[0-9A-Za-z-]+$`), "must only contain alphanumeric characters and hyphens"), + validation.StringDoesNotMatch(regexp.MustCompile(`--`), "cannot contain two consecutive hyphens"), + validation.StringDoesNotMatch(regexp.MustCompile(`-$`), "cannot end in a hyphen"), + ), }, - - "character_set_name": { + "hosted_zone_id": { Type: schema.TypeString, - Optional: true, Computed: true, - ForceNew: true, }, - - "storage_encrypted": { + "iam_database_authentication_enabled": { Type: schema.TypeBool, Optional: true, - ForceNew: true, - }, - - "allocated_storage": { - Type: schema.TypeInt, - Optional: true, - Computed: true, - DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { - mas := d.Get("max_allocated_storage").(int) - - newInt, err := strconv.Atoi(new) - - if err != nil { - return false - } - - oldInt, err := strconv.Atoi(old) - - if err != nil { - return false - } - - // Allocated is higher than the configuration - // and autoscaling is enabled - if oldInt > newInt && mas > newInt { - return true - } - - return false - }, - }, - - "storage_type": { - Type: schema.TypeString, - Optional: true, - Computed: true, }, - "identifier": { Type: schema.TypeString, Optional: true, @@ -161,48 +224,30 @@ func resourceAwsDbInstance() *schema.Resource { ForceNew: true, ValidateFunc: validateRdsIdentifierPrefix, }, - "instance_class": { Type: schema.TypeString, Required: true, }, - - "availability_zone": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, - - "backup_retention_period": { + "iops": { Type: schema.TypeInt, Optional: true, - Computed: true, }, - - "backup_window": { + "kms_key_id": { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: validateOnceADayWindowFormat, - }, - - "iops": { - Type: schema.TypeInt, - Optional: true, + ForceNew: true, + ValidateFunc: validateArn, }, - "latest_restorable_time": { Type: schema.TypeString, Computed: true, }, - "license_model": { Type: schema.TypeString, Optional: true, Computed: true, }, - "maintenance_window": { Type: schema.TypeString, Optional: true, @@ -216,7 +261,6 @@ func resourceAwsDbInstance() *schema.Resource { }, ValidateFunc: validateOnceAWeekWindowFormat, }, - "max_allocated_storage": { Type: schema.TypeInt, Optional: true, @@ -227,51 +271,81 @@ func resourceAwsDbInstance() *schema.Resource { return false }, }, - + "monitoring_interval": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + }, + "monitoring_role_arn": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, "multi_az": { Type: schema.TypeBool, Optional: true, Computed: true, }, - + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "option_group_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "parameter_group_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "password": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + "performance_insights_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "performance_insights_kms_key_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validateArn, + }, + "performance_insights_retention_period": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, "port": { Type: schema.TypeInt, Optional: true, Computed: true, }, - "publicly_accessible": { Type: schema.TypeBool, Optional: true, Default: false, }, - - "vpc_security_group_ids": { - Type: schema.TypeSet, - Optional: true, + "replicas": { + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, - - "security_group_names": { - Type: schema.TypeSet, + "replicate_source_db": { + Type: schema.TypeString, Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, - - "final_snapshot_identifier": { + "resource_id": { Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.All( - validation.StringMatch(regexp.MustCompile(`^[A-Za-z]`), "must begin with alphabetic character"), - validation.StringMatch(regexp.MustCompile(`^[0-9A-Za-z-]+$`), "must only contain alphanumeric characters and hyphens"), - validation.StringDoesNotMatch(regexp.MustCompile(`--`), "cannot contain two consecutive hyphens"), - validation.StringDoesNotMatch(regexp.MustCompile(`-$`), "cannot end in a hyphen"), - ), + Computed: true, }, - "restore_to_point_in_time": { Type: schema.TypeList, Optional: true, @@ -309,7 +383,6 @@ func resourceAwsDbInstance() *schema.Resource { }, }, }, - "s3_import": { Type: schema.TypeList, Optional: true, @@ -348,189 +421,58 @@ func resourceAwsDbInstance() *schema.Resource { }, }, }, - - "skip_final_snapshot": { - Type: schema.TypeBool, + "security_group_names": { + Type: schema.TypeSet, Optional: true, - Default: false, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, }, - - "copy_tags_to_snapshot": { + "skip_final_snapshot": { Type: schema.TypeBool, Optional: true, Default: false, }, - - "db_subnet_group_name": { + "snapshot_identifier": { Type: schema.TypeString, - Optional: true, Computed: true, - }, - - "parameter_group_name": { - Type: schema.TypeString, Optional: true, - Computed: true, - }, - - "address": { - Type: schema.TypeString, - Computed: true, - }, - - "endpoint": { - Type: schema.TypeString, - Computed: true, - }, - - "hosted_zone_id": { - Type: schema.TypeString, - Computed: true, + ForceNew: true, }, - "status": { Type: schema.TypeString, Computed: true, }, - - // apply_immediately is used to determine when the update modifications - // take place. - // See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html - "apply_immediately": { + "storage_encrypted": { Type: schema.TypeBool, Optional: true, - Computed: true, - }, - - "replicate_source_db": { - Type: schema.TypeString, - Optional: true, - }, - - "replicas": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - - "snapshot_identifier": { - Type: schema.TypeString, - Computed: true, - Optional: true, ForceNew: true, }, - - "auto_minor_version_upgrade": { - Type: schema.TypeBool, - Optional: true, - Default: true, - }, - - "allow_major_version_upgrade": { - Type: schema.TypeBool, - Optional: true, - }, - - "monitoring_role_arn": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - - "monitoring_interval": { - Type: schema.TypeInt, - Optional: true, - Default: 0, - }, - - "option_group_name": { + "storage_type": { Type: schema.TypeString, Optional: true, Computed: true, }, - - "kms_key_id": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ValidateFunc: validateArn, - }, - + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), "timezone": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, - - "iam_database_authentication_enabled": { - Type: schema.TypeBool, - Optional: true, - }, - - "resource_id": { + "username": { Type: schema.TypeString, + Optional: true, Computed: true, + ForceNew: true, }, - - "enabled_cloudwatch_logs_exports": { + "vpc_security_group_ids": { Type: schema.TypeSet, Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - "agent", - "alert", - "audit", - "error", - "general", - "listener", - "slowquery", - "trace", - "postgresql", - "upgrade", - }, false), - }, - }, - - "domain": { - Type: schema.TypeString, - Optional: true, - }, - - "domain_iam_role_name": { - Type: schema.TypeString, - Optional: true, - }, - - "performance_insights_enabled": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - - "performance_insights_kms_key_id": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validateArn, - }, - - "performance_insights_retention_period": { - Type: schema.TypeInt, - Optional: true, Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, }, - - "delete_automated_backups": { - Type: schema.TypeBool, - Optional: true, - Default: true, - }, - - "tags": tagsSchema(), - "tags_all": tagsSchemaComputed(), }, CustomizeDiff: SetTagsDiff, From abaa2d775fba8b739b0faa6d65b8899a0ace0f41 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 9 Jul 2021 12:26:06 -0400 Subject: [PATCH 1059/1208] tests/r/db_instance: Clean interpolation only --- aws/resource_aws_db_instance_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 5d59b8a29b90..6cb4e3d8d673 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -5455,8 +5455,8 @@ resource "aws_db_instance" "source" { resource "aws_db_instance" "test" { identifier = %q - instance_class = "${aws_db_instance.source.instance_class}" - replicate_source_db = "${aws_db_instance.source.id}" + instance_class = aws_db_instance.source.instance_class + replicate_source_db = aws_db_instance.source.id skip_final_snapshot = true iops = %d storage_type = "io1" @@ -5482,8 +5482,8 @@ resource "aws_db_instance" "source" { resource "aws_db_instance" "test" { allocated_storage = %[2]d identifier = %[1]q - instance_class = "${aws_db_instance.source.instance_class}" - replicate_source_db = "${aws_db_instance.source.id}" + instance_class = aws_db_instance.source.instance_class + replicate_source_db = aws_db_instance.source.id skip_final_snapshot = true iops = %[3]d storage_type = "io1" From 7fefe9f9e157fb4262b4af90fd19a1a6d846bfc4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 9 Jul 2021 13:47:33 -0400 Subject: [PATCH 1060/1208] tests/r/db_instance: Add errorchecks --- aws/resource_aws_db_instance_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 6cb4e3d8d673..f6728e1b2f44 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -658,6 +658,7 @@ func TestAccAWSDBInstance_ReplicateSourceDb_Iops(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSDBInstanceDestroy, Steps: []resource.TestStep{ @@ -683,6 +684,7 @@ func TestAccAWSDBInstance_ReplicateSourceDb_AllocatedStorageAndIops(t *testing.T resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, rds.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSDBInstanceDestroy, Steps: []resource.TestStep{ From e2fb6ed3e0b30495f1dfa5e2887218f6d91951c2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 9 Jul 2021 13:49:37 -0400 Subject: [PATCH 1061/1208] Report any FailureDetails. --- aws/fsx.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/aws/fsx.go b/aws/fsx.go index 7aa5d9896982..9e4cc968e8a5 100644 --- a/aws/fsx.go +++ b/aws/fsx.go @@ -1,11 +1,13 @@ package aws import ( + "errors" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/fsx" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func describeFsxFileSystem(conn *fsx.FSx, id string) (*fsx.FileSystem, error) { @@ -87,7 +89,13 @@ func waitForFsxFileSystemCreation(conn *fsx.FSx, id string, timeout time.Duratio Delay: 30 * time.Second, } - _, err := stateConf.WaitForState() + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*fsx.FileSystem); ok { + if output.FailureDetails != nil { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.FailureDetails.Message))) + } + } return err } @@ -101,7 +109,13 @@ func waitForFsxFileSystemDeletion(conn *fsx.FSx, id string, timeout time.Duratio Delay: 30 * time.Second, } - _, err := stateConf.WaitForState() + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*fsx.FileSystem); ok { + if output.FailureDetails != nil { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.FailureDetails.Message))) + } + } return err } From b565d310616793cbc0792d249bfa341f21ffef61 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Fri, 9 Jul 2021 13:56:21 -0400 Subject: [PATCH 1062/1208] r/db_instance: Add changelog --- .changelog/12548.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/12548.txt diff --git a/.changelog/12548.txt b/.changelog/12548.txt new file mode 100644 index 000000000000..83b4cd6d85af --- /dev/null +++ b/.changelog/12548.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_db_instance: Ignore allocated_storage for replica at creation time +``` \ No newline at end of file From 8270c7a9d28f5b0c396022c80cf1937fe3c07e07 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Fri, 9 Jul 2021 18:22:03 +0000 Subject: [PATCH 1063/1208] Update CHANGELOG.md for #20114 --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64ba9062ffd5..1588887e9750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,19 @@ ## 3.50.0 (Unreleased) + +FEATURES: + +* **New Resource:** `aws_config_organization_conformance_pack` ([#17298](https://github.com/hashicorp/terraform-provider-aws/issues/17298)) + +ENHANCEMENTS: + +* resource/aws_cognito_user_pool_client: Add the `enable_token_revocation` argument to support targeted sign out ([#20031](https://github.com/hashicorp/terraform-provider-aws/issues/20031)) +* resource/fsx_windows_file_system: Add `aliases` argument. ([#20054](https://github.com/hashicorp/terraform-provider-aws/issues/20054)) + +BUG FIXES: + +* resource/aws_cognito_user_pool_client: Allow the `default_redirect_uri` argument value to be an empty string ([#20031](https://github.com/hashicorp/terraform-provider-aws/issues/20031)) +* resource/aws_cognito_user_pool_client: Retry on `ConcurrentModificationException` ([#20031](https://github.com/hashicorp/terraform-provider-aws/issues/20031)) + ## 3.49.0 (July 08, 2021) FEATURES: From bfcec117ee00e9183bfce0a6bcb4c8d9d65f556e Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 25 Jun 2021 12:42:46 -0700 Subject: [PATCH 1064/1208] Removes `terraformtest.com` domain names from API Gateway acceptance tests --- aws/data_source_aws_api_gateway_domain_name_test.go | 3 +-- aws/provider_test.go | 12 ++++++++++++ ...esource_aws_api_gateway_base_path_mapping_test.go | 9 ++++----- aws/resource_aws_api_gateway_domain_name_test.go | 12 ++++++------ 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/aws/data_source_aws_api_gateway_domain_name_test.go b/aws/data_source_aws_api_gateway_domain_name_test.go index a415f2becc0b..a2bab5406a71 100644 --- a/aws/data_source_aws_api_gateway_domain_name_test.go +++ b/aws/data_source_aws_api_gateway_domain_name_test.go @@ -5,14 +5,13 @@ import ( "testing" "github.com/aws/aws-sdk-go/service/apigateway" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccDataSourceAwsApiGatewayDomainName_basic(t *testing.T) { resourceName := "aws_api_gateway_domain_name.test" dataSourceName := "data.aws_api_gateway_domain_name.test" - rName := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8)) + rName := testAccRandomSubdomain() key := tlsRsaPrivateKeyPem(2048) certificate := tlsRsaX509SelfSignedCertificatePem(key, rName) diff --git a/aws/provider_test.go b/aws/provider_test.go index de8c51422524..c0a96b2a3534 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -19,6 +19,7 @@ import ( "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/organizations" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "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/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" @@ -2283,3 +2284,14 @@ func composeConfig(config ...string) string { return str.String() } + +const defaultRootLevelDomain = "example.com" +const defaultRootLevelDomainWildcard = "*." + defaultRootLevelDomain + +// testAccRandomSubdomain creates a random three-level domain name of the form +// ".example.com" +// The second level domain name "example.com" is reserved by IANA for testing and +// documentation purposes: https://datatracker.ietf.org/doc/html/rfc2606 +func testAccRandomSubdomain() string { + return fmt.Sprintf("%s.%s", acctest.RandString(8), defaultRootLevelDomain) +} diff --git a/aws/resource_aws_api_gateway_base_path_mapping_test.go b/aws/resource_aws_api_gateway_base_path_mapping_test.go index 0462b29e55ed..3adfd1eebfa2 100644 --- a/aws/resource_aws_api_gateway_base_path_mapping_test.go +++ b/aws/resource_aws_api_gateway_base_path_mapping_test.go @@ -6,7 +6,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/apigateway" - "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" ) @@ -66,7 +65,7 @@ func TestDecodeApiGatewayBasePathMappingId(t *testing.T) { func TestAccAWSAPIGatewayBasePathMapping_basic(t *testing.T) { var conf apigateway.BasePathMapping - name := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8)) + name := testAccRandomSubdomain() key := tlsRsaPrivateKeyPem(2048) certificate := tlsRsaX509SelfSignedCertificatePem(key, name) @@ -96,7 +95,7 @@ func TestAccAWSAPIGatewayBasePathMapping_basic(t *testing.T) { func TestAccAWSAPIGatewayBasePathMapping_BasePath_Empty(t *testing.T) { var conf apigateway.BasePathMapping - name := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8)) + name := testAccRandomSubdomain() key := tlsRsaPrivateKeyPem(2048) certificate := tlsRsaX509SelfSignedCertificatePem(key, name) @@ -125,7 +124,7 @@ func TestAccAWSAPIGatewayBasePathMapping_BasePath_Empty(t *testing.T) { func TestAccAWSAPIGatewayBasePathMapping_updates(t *testing.T) { var confFirst, conf apigateway.BasePathMapping resourceName := "aws_api_gateway_base_path_mapping.test" - name := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8)) + name := testAccRandomSubdomain() key := tlsRsaPrivateKeyPem(2048) certificate := tlsRsaX509SelfSignedCertificatePem(key, name) @@ -175,7 +174,7 @@ func TestAccAWSAPIGatewayBasePathMapping_updates(t *testing.T) { func TestAccAWSAPIGatewayBasePathMapping_disappears(t *testing.T) { var conf apigateway.BasePathMapping - name := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8)) + name := testAccRandomSubdomain() resourceName := "aws_api_gateway_base_path_mapping.test" key := tlsRsaPrivateKeyPem(2048) diff --git a/aws/resource_aws_api_gateway_domain_name_test.go b/aws/resource_aws_api_gateway_domain_name_test.go index b0e7e33dcd45..523329aeda7e 100644 --- a/aws/resource_aws_api_gateway_domain_name_test.go +++ b/aws/resource_aws_api_gateway_domain_name_test.go @@ -115,7 +115,7 @@ func TestAccAWSAPIGatewayDomainName_CertificateName(t *testing.T) { func TestAccAWSAPIGatewayDomainName_RegionalCertificateArn(t *testing.T) { var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" - rName := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8)) + rName := testAccRandomSubdomain() key := tlsRsaPrivateKeyPem(2048) certificate := tlsRsaX509SelfSignedCertificatePem(key, rName) @@ -157,12 +157,12 @@ func TestAccAWSAPIGatewayDomainName_RegionalCertificateName(t *testing.T) { var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" - rName := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8)) + rName := testAccRandomSubdomain() caKey := tlsRsaPrivateKeyPem(2048) caCertificate := tlsRsaX509SelfSignedCaCertificatePem(caKey) key := tlsRsaPrivateKeyPem(2048) - certificate := tlsRsaX509LocallySignedCertificatePem(caKey, caCertificate, key, "*.terraformtest.com") + certificate := tlsRsaX509LocallySignedCertificatePem(caKey, caCertificate, key, defaultRootLevelDomainWildcard) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -192,7 +192,7 @@ func TestAccAWSAPIGatewayDomainName_RegionalCertificateName(t *testing.T) { func TestAccAWSAPIGatewayDomainName_SecurityPolicy(t *testing.T) { var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" - rName := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8)) + rName := testAccRandomSubdomain() key := tlsRsaPrivateKeyPem(2048) certificate := tlsRsaX509SelfSignedCertificatePem(key, rName) @@ -222,7 +222,7 @@ func TestAccAWSAPIGatewayDomainName_SecurityPolicy(t *testing.T) { func TestAccAWSAPIGatewayDomainName_Tags(t *testing.T) { var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" - rName := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8)) + rName := testAccRandomSubdomain() key := tlsRsaPrivateKeyPem(2048) certificate := tlsRsaX509SelfSignedCertificatePem(key, rName) @@ -270,7 +270,7 @@ func TestAccAWSAPIGatewayDomainName_Tags(t *testing.T) { func TestAccAWSAPIGatewayDomainName_disappears(t *testing.T) { var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" - rName := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8)) + rName := testAccRandomSubdomain() key := tlsRsaPrivateKeyPem(2048) certificate := tlsRsaX509SelfSignedCertificatePem(key, rName) From a9dcf6d752a70026211c72d9afc3b745828d7a91 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 25 Jun 2021 15:23:01 -0700 Subject: [PATCH 1065/1208] Removes domain names from Glue connection acceptance tests --- aws/provider_test.go | 9 ++ aws/resource_aws_glue_connection_test.go | 138 +++++++++++++---------- 2 files changed, 85 insertions(+), 62 deletions(-) diff --git a/aws/provider_test.go b/aws/provider_test.go index c0a96b2a3534..dd41f9e39fe1 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -2287,6 +2287,7 @@ func composeConfig(config ...string) string { const defaultRootLevelDomain = "example.com" const defaultRootLevelDomainWildcard = "*." + defaultRootLevelDomain +const testingTopLevelDomain = "test" // testAccRandomSubdomain creates a random three-level domain name of the form // ".example.com" @@ -2295,3 +2296,11 @@ const defaultRootLevelDomainWildcard = "*." + defaultRootLevelDomain func testAccRandomSubdomain() string { return fmt.Sprintf("%s.%s", acctest.RandString(8), defaultRootLevelDomain) } + +// testAccRandomDomainName creates a random second level domain name in the form +// ".test" +// The top level domain ".test" is reserved by IANA for testing purposes: +// https://datatracker.ietf.org/doc/html/rfc6761 +func testAccRandomDomainName() string { + return fmt.Sprintf("%s.%s", acctest.RandString(8), testingTopLevelDomain) +} diff --git a/aws/resource_aws_glue_connection_test.go b/aws/resource_aws_glue_connection_test.go index 8c25778feac6..e099b273cbe9 100644 --- a/aws/resource_aws_glue_connection_test.go +++ b/aws/resource_aws_glue_connection_test.go @@ -60,9 +60,11 @@ func testSweepGlueConnections(region string) error { func TestAccAWSGlueConnection_basic(t *testing.T) { var connection glue.Connection - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_connection.test" + jdbcConnectionUrl := fmt.Sprintf("jdbc:mysql://%s/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -70,12 +72,12 @@ func TestAccAWSGlueConnection_basic(t *testing.T) { CheckDestroy: testAccCheckAWSGlueConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSGlueConnectionConfig_Required(rName), + Config: testAccAWSGlueConnectionConfig_Required(rName, jdbcConnectionUrl), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueConnectionExists(resourceName, &connection), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "glue", fmt.Sprintf("connection/%s", rName)), resource.TestCheckResourceAttr(resourceName, "connection_properties.%", "3"), - resource.TestCheckResourceAttr(resourceName, "connection_properties.JDBC_CONNECTION_URL", "jdbc:mysql://terraformacctesting.com/testdatabase"), + resource.TestCheckResourceAttr(resourceName, "connection_properties.JDBC_CONNECTION_URL", jdbcConnectionUrl), resource.TestCheckResourceAttr(resourceName, "connection_properties.PASSWORD", "testpassword"), resource.TestCheckResourceAttr(resourceName, "connection_properties.USERNAME", "testusername"), resource.TestCheckResourceAttr(resourceName, "match_criteria.#", "0"), @@ -94,9 +96,11 @@ func TestAccAWSGlueConnection_basic(t *testing.T) { func TestAccAWSGlueConnection_MongoDB(t *testing.T) { var connection glue.Connection - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_connection.test" + connectionUrl := fmt.Sprintf("mongodb://%s:27017/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -104,11 +108,11 @@ func TestAccAWSGlueConnection_MongoDB(t *testing.T) { CheckDestroy: testAccCheckAWSGlueConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSGlueConnectionConfig_MongoDB(rName), + Config: testAccAWSGlueConnectionConfig_MongoDB(rName, connectionUrl), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueConnectionExists(resourceName, &connection), resource.TestCheckResourceAttr(resourceName, "connection_properties.%", "3"), - resource.TestCheckResourceAttr(resourceName, "connection_properties.CONNECTION_URL", "mongodb://testdb.com:27017/databasename"), + resource.TestCheckResourceAttr(resourceName, "connection_properties.CONNECTION_URL", connectionUrl), resource.TestCheckResourceAttr(resourceName, "connection_properties.USERNAME", "testusername"), resource.TestCheckResourceAttr(resourceName, "connection_properties.PASSWORD", "testpassword"), resource.TestCheckResourceAttr(resourceName, "connection_type", "MONGODB"), @@ -128,9 +132,11 @@ func TestAccAWSGlueConnection_MongoDB(t *testing.T) { func TestAccAWSGlueConnection_Kafka(t *testing.T) { var connection glue.Connection - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_connection.test" + bootstrapServers := fmt.Sprintf("%s:9094,%s:9094", testAccRandomDomainName(), testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -138,11 +144,11 @@ func TestAccAWSGlueConnection_Kafka(t *testing.T) { CheckDestroy: testAccCheckAWSGlueConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSGlueConnectionConfig_Kafka(rName), + Config: testAccAWSGlueConnectionConfig_Kafka(rName, bootstrapServers), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueConnectionExists(resourceName, &connection), resource.TestCheckResourceAttr(resourceName, "connection_properties.%", "1"), - resource.TestCheckResourceAttr(resourceName, "connection_properties.KAFKA_BOOTSTRAP_SERVERS", "a.terraformtest.com:9094,b.terraformtest.com:9094"), + resource.TestCheckResourceAttr(resourceName, "connection_properties.KAFKA_BOOTSTRAP_SERVERS", bootstrapServers), resource.TestCheckResourceAttr(resourceName, "connection_type", "KAFKA"), resource.TestCheckResourceAttr(resourceName, "match_criteria.#", "0"), resource.TestCheckResourceAttr(resourceName, "physical_connection_requirements.#", "0"), @@ -160,7 +166,7 @@ func TestAccAWSGlueConnection_Kafka(t *testing.T) { func TestAccAWSGlueConnection_Network(t *testing.T) { var connection glue.Connection - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_connection.test" resource.ParallelTest(t, resource.TestCase{ @@ -194,9 +200,11 @@ func TestAccAWSGlueConnection_Network(t *testing.T) { func TestAccAWSGlueConnection_Description(t *testing.T) { var connection glue.Connection - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_connection.test" + jdbcConnectionUrl := fmt.Sprintf("jdbc:mysql://%s/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -204,14 +212,14 @@ func TestAccAWSGlueConnection_Description(t *testing.T) { CheckDestroy: testAccCheckAWSGlueConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSGlueConnectionConfig_Description(rName, "First Description"), + Config: testAccAWSGlueConnectionConfig_Description(rName, jdbcConnectionUrl, "First Description"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueConnectionExists(resourceName, &connection), resource.TestCheckResourceAttr(resourceName, "description", "First Description"), ), }, { - Config: testAccAWSGlueConnectionConfig_Description(rName, "Second Description"), + Config: testAccAWSGlueConnectionConfig_Description(rName, jdbcConnectionUrl, "Second Description"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueConnectionExists(resourceName, &connection), resource.TestCheckResourceAttr(resourceName, "description", "Second Description"), @@ -229,9 +237,11 @@ func TestAccAWSGlueConnection_Description(t *testing.T) { func TestAccAWSGlueConnection_MatchCriteria(t *testing.T) { var connection glue.Connection - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_connection.test" + jdbcConnectionUrl := fmt.Sprintf("jdbc:mysql://%s/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -239,7 +249,7 @@ func TestAccAWSGlueConnection_MatchCriteria(t *testing.T) { CheckDestroy: testAccCheckAWSGlueConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSGlueConnectionConfig_MatchCriteria_First(rName), + Config: testAccAWSGlueConnectionConfig_MatchCriteria_First(rName, jdbcConnectionUrl), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueConnectionExists(resourceName, &connection), resource.TestCheckResourceAttr(resourceName, "match_criteria.#", "4"), @@ -250,7 +260,7 @@ func TestAccAWSGlueConnection_MatchCriteria(t *testing.T) { ), }, { - Config: testAccAWSGlueConnectionConfig_MatchCriteria_Second(rName), + Config: testAccAWSGlueConnectionConfig_MatchCriteria_Second(rName, jdbcConnectionUrl), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueConnectionExists(resourceName, &connection), resource.TestCheckResourceAttr(resourceName, "match_criteria.#", "1"), @@ -258,7 +268,7 @@ func TestAccAWSGlueConnection_MatchCriteria(t *testing.T) { ), }, { - Config: testAccAWSGlueConnectionConfig_MatchCriteria_Third(rName), + Config: testAccAWSGlueConnectionConfig_MatchCriteria_Third(rName, jdbcConnectionUrl), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueConnectionExists(resourceName, &connection), resource.TestCheckResourceAttr(resourceName, "match_criteria.#", "3"), @@ -279,7 +289,7 @@ func TestAccAWSGlueConnection_MatchCriteria(t *testing.T) { func TestAccAWSGlueConnection_PhysicalConnectionRequirements(t *testing.T) { var connection glue.Connection - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_connection.test" resource.ParallelTest(t, resource.TestCase{ @@ -316,9 +326,11 @@ func TestAccAWSGlueConnection_PhysicalConnectionRequirements(t *testing.T) { func TestAccAWSGlueConnection_disappears(t *testing.T) { var connection glue.Connection - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_connection.test" + jdbcConnectionUrl := fmt.Sprintf("jdbc:mysql://%s/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -326,7 +338,7 @@ func TestAccAWSGlueConnection_disappears(t *testing.T) { CheckDestroy: testAccCheckAWSGlueConnectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSGlueConnectionConfig_Required(rName), + Config: testAccAWSGlueConnectionConfig_Required(rName, jdbcConnectionUrl), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueConnectionExists(resourceName, &connection), testAccCheckResourceDisappears(testAccProvider, resourceAwsGlueConnection(), resourceName), @@ -410,64 +422,68 @@ func testAccCheckAWSGlueConnectionDestroy(s *terraform.State) error { return nil } -func testAccAWSGlueConnectionConfig_Description(rName, description string) string { +func testAccAWSGlueConnectionConfig_Description(rName, jdbcConnectionUrl, description string) string { return fmt.Sprintf(` resource "aws_glue_connection" "test" { + name = %[1]q + description = %[2]q + connection_properties = { - JDBC_CONNECTION_URL = "jdbc:mysql://terraformacctesting.com/testdatabase" + JDBC_CONNECTION_URL = %[3]q PASSWORD = "testpassword" USERNAME = "testusername" } - description = "%[1]s" - name = "%[2]s" } -`, description, rName) +`, rName, description, jdbcConnectionUrl) } -func testAccAWSGlueConnectionConfig_MatchCriteria_First(rName string) string { +func testAccAWSGlueConnectionConfig_MatchCriteria_First(rName, jdbcConnectionUrl string) string { return fmt.Sprintf(` resource "aws_glue_connection" "test" { + name = %[1]q + + match_criteria = ["criteria1", "criteria2", "criteria3", "criteria4"] + connection_properties = { - JDBC_CONNECTION_URL = "jdbc:mysql://terraformacctesting.com/testdatabase" + JDBC_CONNECTION_URL = %[2]q PASSWORD = "testpassword" USERNAME = "testusername" } - - match_criteria = ["criteria1", "criteria2", "criteria3", "criteria4"] - name = "%s" } -`, rName) +`, rName, jdbcConnectionUrl) } -func testAccAWSGlueConnectionConfig_MatchCriteria_Second(rName string) string { +func testAccAWSGlueConnectionConfig_MatchCriteria_Second(rName, jdbcConnectionUrl string) string { return fmt.Sprintf(` resource "aws_glue_connection" "test" { + name = %[1]q + + match_criteria = ["criteria1"] + connection_properties = { - JDBC_CONNECTION_URL = "jdbc:mysql://terraformacctesting.com/testdatabase" + JDBC_CONNECTION_URL = %[2]q PASSWORD = "testpassword" USERNAME = "testusername" } - - match_criteria = ["criteria1"] - name = "%s" } -`, rName) +`, rName, jdbcConnectionUrl) } -func testAccAWSGlueConnectionConfig_MatchCriteria_Third(rName string) string { +func testAccAWSGlueConnectionConfig_MatchCriteria_Third(rName, jdbcConnectionUrl string) string { return fmt.Sprintf(` resource "aws_glue_connection" "test" { + name = "%s" + + match_criteria = ["criteria2", "criteria3", "criteria4"] + connection_properties = { - JDBC_CONNECTION_URL = "jdbc:mysql://terraformacctesting.com/testdatabase" + JDBC_CONNECTION_URL = %[2]q PASSWORD = "testpassword" USERNAME = "testusername" } - - match_criteria = ["criteria2", "criteria3", "criteria4"] - name = "%s" } -`, rName) +`, rName, jdbcConnectionUrl) } func testAccAWSGlueConnectionConfig_PhysicalConnectionRequirements(rName string) string { @@ -555,48 +571,46 @@ resource "aws_glue_connection" "test" { `, rName) } -func testAccAWSGlueConnectionConfig_Required(rName string) string { +func testAccAWSGlueConnectionConfig_Required(rName, jdbcConnectionUrl string) string { return fmt.Sprintf(` resource "aws_glue_connection" "test" { + name = %[1]q + connection_properties = { - JDBC_CONNECTION_URL = "jdbc:mysql://terraformacctesting.com/testdatabase" + JDBC_CONNECTION_URL = %[2]q PASSWORD = "testpassword" USERNAME = "testusername" } - - name = "%s" } -`, rName) +`, rName, jdbcConnectionUrl) } -func testAccAWSGlueConnectionConfig_MongoDB(rName string) string { +func testAccAWSGlueConnectionConfig_MongoDB(rName, connectionUrl string) string { return fmt.Sprintf(` resource "aws_glue_connection" "test" { + name = %[1]q + + connection_type = "MONGODB" connection_properties = { - CONNECTION_URL = "mongodb://testdb.com:27017/databasename" + CONNECTION_URL = %[2]q PASSWORD = "testpassword" USERNAME = "testusername" } - - connection_type = "MONGODB" - - name = "%s" } -`, rName) +`, rName, connectionUrl) } -func testAccAWSGlueConnectionConfig_Kafka(rName string) string { +func testAccAWSGlueConnectionConfig_Kafka(rName, bootstrapServers string) string { return fmt.Sprintf(` resource "aws_glue_connection" "test" { - connection_properties = { - KAFKA_BOOTSTRAP_SERVERS = "a.terraformtest.com:9094,b.terraformtest.com:9094" - } + name = %[1]q connection_type = "KAFKA" - - name = "%s" + connection_properties = { + KAFKA_BOOTSTRAP_SERVERS = %[2]q + } } -`, rName) +`, rName, bootstrapServers) } func testAccAWSGlueConnectionConfig_Network(rName string) string { From cf99d59c52355ba77cba93d53fcd10b903499bb7 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 28 Jun 2021 13:02:46 -0700 Subject: [PATCH 1066/1208] Removes hard-coded domain names from Route 53 resources --- aws/provider_test.go | 16 +++--- ...source_aws_api_gateway_domain_name_test.go | 6 ++- ...esource_aws_route53_delegation_set_test.go | 20 +++---- ...rce_aws_route53_hosted_zone_dnssec_test.go | 31 ++++++----- ...source_aws_route53_key_signing_key_test.go | 30 ++++++----- aws/resource_aws_route53_zone_test.go | 54 +++++++++---------- 6 files changed, 83 insertions(+), 74 deletions(-) diff --git a/aws/provider_test.go b/aws/provider_test.go index dd41f9e39fe1..a9dcaccf772e 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -2285,16 +2285,14 @@ func composeConfig(config ...string) string { return str.String() } -const defaultRootLevelDomain = "example.com" -const defaultRootLevelDomainWildcard = "*." + defaultRootLevelDomain const testingTopLevelDomain = "test" -// testAccRandomSubdomain creates a random three-level domain name of the form -// ".example.com" -// The second level domain name "example.com" is reserved by IANA for testing and -// documentation purposes: https://datatracker.ietf.org/doc/html/rfc2606 +// testAccRandomSubdomain creates a random three-level domain name in the form +// "..test" +// The top level domain ".test" is reserved by IANA for testing purposes: +// https://datatracker.ietf.org/doc/html/rfc6761 func testAccRandomSubdomain() string { - return fmt.Sprintf("%s.%s", acctest.RandString(8), defaultRootLevelDomain) + return testAccSubdomainWithRandomSecondLevel(acctest.RandString(8)) } // testAccRandomDomainName creates a random second level domain name in the form @@ -2304,3 +2302,7 @@ func testAccRandomSubdomain() string { func testAccRandomDomainName() string { return fmt.Sprintf("%s.%s", acctest.RandString(8), testingTopLevelDomain) } + +func testAccSubdomainWithRandomSecondLevel(thing string) string { + return fmt.Sprintf("%s.%s", thing, testAccRandomDomainName()) +} diff --git a/aws/resource_aws_api_gateway_domain_name_test.go b/aws/resource_aws_api_gateway_domain_name_test.go index 523329aeda7e..3e74b4925f29 100644 --- a/aws/resource_aws_api_gateway_domain_name_test.go +++ b/aws/resource_aws_api_gateway_domain_name_test.go @@ -157,12 +157,14 @@ func TestAccAWSAPIGatewayDomainName_RegionalCertificateName(t *testing.T) { var domainName apigateway.DomainName resourceName := "aws_api_gateway_domain_name.test" - rName := testAccRandomSubdomain() + domain := testAccRandomDomainName() + domainWildcard := fmt.Sprintf("*.%s", domain) + rName := fmt.Sprintf("%s.%s", acctest.RandString(8), domain) caKey := tlsRsaPrivateKeyPem(2048) caCertificate := tlsRsaX509SelfSignedCaCertificatePem(caKey) key := tlsRsaPrivateKeyPem(2048) - certificate := tlsRsaX509LocallySignedCertificatePem(caKey, caCertificate, key, defaultRootLevelDomainWildcard) + certificate := tlsRsaX509LocallySignedCertificatePem(caKey, caCertificate, key, domainWildcard) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/aws/resource_aws_route53_delegation_set_test.go b/aws/resource_aws_route53_delegation_set_test.go index 542f1a8f6374..f29310b795c9 100644 --- a/aws/resource_aws_route53_delegation_set_test.go +++ b/aws/resource_aws_route53_delegation_set_test.go @@ -13,8 +13,7 @@ import ( ) func TestAccAWSRoute53DelegationSet_basic(t *testing.T) { - rString := acctest.RandString(8) - refName := fmt.Sprintf("tf_acc_%s", rString) + refName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_route53_delegation_set.test" resource.ParallelTest(t, resource.TestCase{ @@ -42,11 +41,12 @@ func TestAccAWSRoute53DelegationSet_basic(t *testing.T) { func TestAccAWSRoute53DelegationSet_withZones(t *testing.T) { var zone route53.GetHostedZoneOutput - rString := acctest.RandString(8) - refName := fmt.Sprintf("tf_acc_%s", rString) + refName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_route53_delegation_set.test" - zoneName1 := fmt.Sprintf("%s-primary.terraformtest.com", rString) - zoneName2 := fmt.Sprintf("%s-secondary.terraformtest.com", rString) + + domain := testAccRandomDomainName() + zoneName1 := fmt.Sprintf("primary.%s", domain) + zoneName2 := fmt.Sprintf("secondary.%s", domain) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -156,7 +156,7 @@ func testAccCheckRoute53NameServersMatch(delegationSetName, zoneName string) res func testAccRoute53DelegationSetConfig(refName string) string { return fmt.Sprintf(` resource "aws_route53_delegation_set" "test" { - reference_name = "%s" + reference_name = %[1]q } `, refName) } @@ -164,16 +164,16 @@ resource "aws_route53_delegation_set" "test" { func testAccRoute53DelegationSetWithZonesConfig(refName, zoneName1, zoneName2 string) string { return fmt.Sprintf(` resource "aws_route53_delegation_set" "test" { - reference_name = "%s" + reference_name = %[1]q } resource "aws_route53_zone" "primary" { - name = "%s" + name = %[2]q delegation_set_id = aws_route53_delegation_set.test.id } resource "aws_route53_zone" "secondary" { - name = "%s" + name = %[3]q delegation_set_id = aws_route53_delegation_set.test.id } `, refName, zoneName1, zoneName2) diff --git a/aws/resource_aws_route53_hosted_zone_dnssec_test.go b/aws/resource_aws_route53_hosted_zone_dnssec_test.go index 98864244204a..a381e3ff39e3 100644 --- a/aws/resource_aws_route53_hosted_zone_dnssec_test.go +++ b/aws/resource_aws_route53_hosted_zone_dnssec_test.go @@ -19,6 +19,8 @@ func TestAccAwsRoute53HostedZoneDnssec_basic(t *testing.T) { resourceName := "aws_route53_hosted_zone_dnssec.test" rName := acctest.RandomWithPrefix("tf-acc-test") + domainName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckRoute53KeySigningKey(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -26,7 +28,7 @@ func TestAccAwsRoute53HostedZoneDnssec_basic(t *testing.T) { CheckDestroy: testAccCheckAwsRoute53HostedZoneDnssecDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsRoute53HostedZoneDnssecConfig(rName), + Config: testAccAwsRoute53HostedZoneDnssecConfig(rName, domainName), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsRoute53HostedZoneDnssecExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "hosted_zone_id", route53ZoneResourceName, "id"), @@ -46,6 +48,8 @@ func TestAccAwsRoute53HostedZoneDnssec_disappears(t *testing.T) { resourceName := "aws_route53_hosted_zone_dnssec.test" rName := acctest.RandomWithPrefix("tf-acc-test") + domainName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckRoute53KeySigningKey(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -53,7 +57,7 @@ func TestAccAwsRoute53HostedZoneDnssec_disappears(t *testing.T) { CheckDestroy: testAccCheckAwsRoute53HostedZoneDnssecDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsRoute53HostedZoneDnssecConfig(rName), + Config: testAccAwsRoute53HostedZoneDnssecConfig(rName, domainName), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsRoute53HostedZoneDnssecExists(resourceName), testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53HostedZoneDnssec(), resourceName), @@ -68,6 +72,8 @@ func TestAccAwsRoute53HostedZoneDnssec_SigningStatus(t *testing.T) { resourceName := "aws_route53_hosted_zone_dnssec.test" rName := acctest.RandomWithPrefix("tf-acc-test") + domainName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckRoute53KeySigningKey(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -75,7 +81,7 @@ func TestAccAwsRoute53HostedZoneDnssec_SigningStatus(t *testing.T) { CheckDestroy: testAccCheckAwsRoute53HostedZoneDnssecDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsRoute53HostedZoneDnssecConfig_SigningStatus(rName, tfroute53.ServeSignatureNotSigning), + Config: testAccAwsRoute53HostedZoneDnssecConfig_SigningStatus(rName, domainName, tfroute53.ServeSignatureNotSigning), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsRoute53HostedZoneDnssecExists(resourceName), resource.TestCheckResourceAttr(resourceName, "signing_status", tfroute53.ServeSignatureNotSigning), @@ -87,14 +93,14 @@ func TestAccAwsRoute53HostedZoneDnssec_SigningStatus(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAwsRoute53HostedZoneDnssecConfig_SigningStatus(rName, tfroute53.ServeSignatureSigning), + Config: testAccAwsRoute53HostedZoneDnssecConfig_SigningStatus(rName, domainName, tfroute53.ServeSignatureSigning), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsRoute53HostedZoneDnssecExists(resourceName), resource.TestCheckResourceAttr(resourceName, "signing_status", tfroute53.ServeSignatureSigning), ), }, { - Config: testAccAwsRoute53HostedZoneDnssecConfig_SigningStatus(rName, tfroute53.ServeSignatureNotSigning), + Config: testAccAwsRoute53HostedZoneDnssecConfig_SigningStatus(rName, domainName, tfroute53.ServeSignatureNotSigning), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsRoute53HostedZoneDnssecExists(resourceName), resource.TestCheckResourceAttr(resourceName, "signing_status", tfroute53.ServeSignatureNotSigning), @@ -162,7 +168,7 @@ func testAccAwsRoute53HostedZoneDnssecExists(resourceName string) resource.TestC } } -func testAccAwsRoute53HostedZoneDnssecConfig_Base(rName string) string { +func testAccAwsRoute53HostedZoneDnssecConfig_Base(rName, domainName string) string { return composeConfig( testAccRoute53KeySigningKeyRegionProviderConfig(), fmt.Sprintf(` @@ -199,7 +205,7 @@ resource "aws_kms_key" "test" { } resource "aws_route53_zone" "test" { - name = "%[1]s.terraformtest.com" + name = %[2]q } resource "aws_route53_key_signing_key" "test" { @@ -207,22 +213,21 @@ resource "aws_route53_key_signing_key" "test" { key_management_service_arn = aws_kms_key.test.arn name = %[1]q } -`, rName)) +`, rName, domainName)) } -func testAccAwsRoute53HostedZoneDnssecConfig(rName string) string { +func testAccAwsRoute53HostedZoneDnssecConfig(rName, domainName string) string { return composeConfig( - testAccAwsRoute53HostedZoneDnssecConfig_Base(rName), - ` + testAccAwsRoute53HostedZoneDnssecConfig_Base(rName, domainName), ` resource "aws_route53_hosted_zone_dnssec" "test" { hosted_zone_id = aws_route53_key_signing_key.test.hosted_zone_id } `) } -func testAccAwsRoute53HostedZoneDnssecConfig_SigningStatus(rName string, signingStatus string) string { +func testAccAwsRoute53HostedZoneDnssecConfig_SigningStatus(rName, domainName, signingStatus string) string { return composeConfig( - testAccAwsRoute53HostedZoneDnssecConfig_Base(rName), + testAccAwsRoute53HostedZoneDnssecConfig_Base(rName, domainName), fmt.Sprintf(` resource "aws_route53_hosted_zone_dnssec" "test" { hosted_zone_id = aws_route53_key_signing_key.test.hosted_zone_id diff --git a/aws/resource_aws_route53_key_signing_key_test.go b/aws/resource_aws_route53_key_signing_key_test.go index 4da3e7331781..0d1e122047bf 100644 --- a/aws/resource_aws_route53_key_signing_key_test.go +++ b/aws/resource_aws_route53_key_signing_key_test.go @@ -113,6 +113,8 @@ func TestAccAwsRoute53KeySigningKey_basic(t *testing.T) { resourceName := "aws_route53_key_signing_key.test" rName := acctest.RandomWithPrefix("tf-acc-test") + domainName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckRoute53KeySigningKey(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -120,7 +122,7 @@ func TestAccAwsRoute53KeySigningKey_basic(t *testing.T) { CheckDestroy: testAccCheckAwsRoute53KeySigningKeyDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsRoute53KeySigningKeyConfig_Name(rName), + Config: testAccAwsRoute53KeySigningKeyConfig_Name(rName, domainName), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsRoute53KeySigningKeyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "digest_algorithm_mnemonic", "SHA-256"), @@ -152,6 +154,8 @@ func TestAccAwsRoute53KeySigningKey_disappears(t *testing.T) { resourceName := "aws_route53_key_signing_key.test" rName := acctest.RandomWithPrefix("tf-acc-test") + domainName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckRoute53KeySigningKey(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -159,7 +163,7 @@ func TestAccAwsRoute53KeySigningKey_disappears(t *testing.T) { CheckDestroy: testAccCheckAwsRoute53KeySigningKeyDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsRoute53KeySigningKeyConfig_Name(rName), + Config: testAccAwsRoute53KeySigningKeyConfig_Name(rName, domainName), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsRoute53KeySigningKeyExists(resourceName), testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53KeySigningKey(), resourceName), @@ -174,6 +178,8 @@ func TestAccAwsRoute53KeySigningKey_Status(t *testing.T) { resourceName := "aws_route53_key_signing_key.test" rName := acctest.RandomWithPrefix("tf-acc-test") + domainName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckRoute53KeySigningKey(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -181,7 +187,7 @@ func TestAccAwsRoute53KeySigningKey_Status(t *testing.T) { CheckDestroy: testAccCheckAwsRoute53KeySigningKeyDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsRoute53KeySigningKeyConfig_Status(rName, tfroute53.KeySigningKeyStatusInactive), + Config: testAccAwsRoute53KeySigningKeyConfig_Status(rName, domainName, tfroute53.KeySigningKeyStatusInactive), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsRoute53KeySigningKeyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "status", tfroute53.KeySigningKeyStatusInactive), @@ -193,14 +199,14 @@ func TestAccAwsRoute53KeySigningKey_Status(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAwsRoute53KeySigningKeyConfig_Status(rName, tfroute53.KeySigningKeyStatusActive), + Config: testAccAwsRoute53KeySigningKeyConfig_Status(rName, domainName, tfroute53.KeySigningKeyStatusActive), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsRoute53KeySigningKeyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "status", tfroute53.KeySigningKeyStatusActive), ), }, { - Config: testAccAwsRoute53KeySigningKeyConfig_Status(rName, tfroute53.KeySigningKeyStatusInactive), + Config: testAccAwsRoute53KeySigningKeyConfig_Status(rName, domainName, tfroute53.KeySigningKeyStatusInactive), Check: resource.ComposeAggregateTestCheckFunc( testAccAwsRoute53KeySigningKeyExists(resourceName), resource.TestCheckResourceAttr(resourceName, "status", tfroute53.KeySigningKeyStatusInactive), @@ -268,7 +274,7 @@ func testAccAwsRoute53KeySigningKeyExists(resourceName string) resource.TestChec } } -func testAccAwsRoute53KeySigningKeyConfig_Base(rName string) string { +func testAccAwsRoute53KeySigningKeyConfig_Base(rName, domainName string) string { return composeConfig( testAccRoute53KeySigningKeyRegionProviderConfig(), fmt.Sprintf(` @@ -305,14 +311,14 @@ resource "aws_kms_key" "test" { } resource "aws_route53_zone" "test" { - name = "%[1]s.terraformtest.com" + name = %[2]q } -`, rName)) +`, rName, domainName)) } -func testAccAwsRoute53KeySigningKeyConfig_Name(rName string) string { +func testAccAwsRoute53KeySigningKeyConfig_Name(rName, domainName string) string { return composeConfig( - testAccAwsRoute53KeySigningKeyConfig_Base(rName), + testAccAwsRoute53KeySigningKeyConfig_Base(rName, domainName), fmt.Sprintf(` resource "aws_route53_key_signing_key" "test" { hosted_zone_id = aws_route53_zone.test.id @@ -322,9 +328,9 @@ resource "aws_route53_key_signing_key" "test" { `, rName)) } -func testAccAwsRoute53KeySigningKeyConfig_Status(rName string, status string) string { +func testAccAwsRoute53KeySigningKeyConfig_Status(rName, domainName, status string) string { return composeConfig( - testAccAwsRoute53KeySigningKeyConfig_Base(rName), + testAccAwsRoute53KeySigningKeyConfig_Base(rName, domainName), fmt.Sprintf(` resource "aws_route53_key_signing_key" "test" { hosted_zone_id = aws_route53_zone.test.id diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index 8e39e13afb7c..f19b8275a85b 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -98,7 +98,6 @@ func hostedZonesToPreserve() []string { "tfacc.hashicorptest.com", "aws.tfacc.hashicorptest.com", "hashicorp.com", - "terraformtest.com", "terraform-provider-aws-acctest-acm.com", } } @@ -167,9 +166,8 @@ func testSweepRoute53Zones(region string) error { func TestAccAWSRoute53Zone_basic(t *testing.T) { var zone route53.GetHostedZoneOutput - rString := acctest.RandString(8) resourceName := "aws_route53_zone.test" - zoneName := fmt.Sprintf("%s.terraformtest.com", rString) + zoneName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -200,9 +198,8 @@ func TestAccAWSRoute53Zone_basic(t *testing.T) { func TestAccAWSRoute53Zone_disappears(t *testing.T) { var zone route53.GetHostedZoneOutput - rString := acctest.RandString(8) resourceName := "aws_route53_zone.test" - zoneName := fmt.Sprintf("%s.terraformtest.com", rString) + zoneName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -225,6 +222,8 @@ func TestAccAWSRoute53Zone_disappears(t *testing.T) { func TestAccAWSRoute53Zone_multiple(t *testing.T) { var zone0, zone1, zone2, zone3, zone4 route53.GetHostedZoneOutput + domainName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -232,18 +231,18 @@ func TestAccAWSRoute53Zone_multiple(t *testing.T) { CheckDestroy: testAccCheckRoute53ZoneDestroy, Steps: []resource.TestStep{ { - Config: testAccRoute53ZoneConfigMultiple(), + Config: testAccRoute53ZoneConfigMultiple(domainName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ZoneExists("aws_route53_zone.test.0", &zone0), - testAccCheckDomainName(&zone0, "subdomain0.terraformtest.com."), + testAccCheckDomainName(&zone0, fmt.Sprintf("subdomain0.%s.", domainName)), testAccCheckRoute53ZoneExists("aws_route53_zone.test.1", &zone1), - testAccCheckDomainName(&zone1, "subdomain1.terraformtest.com."), + testAccCheckDomainName(&zone1, fmt.Sprintf("subdomain1.%s.", domainName)), testAccCheckRoute53ZoneExists("aws_route53_zone.test.2", &zone2), - testAccCheckDomainName(&zone2, "subdomain2.terraformtest.com."), + testAccCheckDomainName(&zone2, fmt.Sprintf("subdomain2.%s.", domainName)), testAccCheckRoute53ZoneExists("aws_route53_zone.test.3", &zone3), - testAccCheckDomainName(&zone3, "subdomain3.terraformtest.com."), + testAccCheckDomainName(&zone3, fmt.Sprintf("subdomain3.%s.", domainName)), testAccCheckRoute53ZoneExists("aws_route53_zone.test.4", &zone4), - testAccCheckDomainName(&zone4, "subdomain4.terraformtest.com."), + testAccCheckDomainName(&zone4, fmt.Sprintf("subdomain4.%s.", domainName)), ), }, }, @@ -253,9 +252,8 @@ func TestAccAWSRoute53Zone_multiple(t *testing.T) { func TestAccAWSRoute53Zone_Comment(t *testing.T) { var zone route53.GetHostedZoneOutput - rString := acctest.RandString(8) resourceName := "aws_route53_zone.test" - zoneName := fmt.Sprintf("%s.terraformtest.com", rString) + zoneName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -290,10 +288,9 @@ func TestAccAWSRoute53Zone_Comment(t *testing.T) { func TestAccAWSRoute53Zone_DelegationSetID(t *testing.T) { var zone route53.GetHostedZoneOutput - rString := acctest.RandString(8) delegationSetResourceName := "aws_route53_delegation_set.test" resourceName := "aws_route53_zone.test" - zoneName := fmt.Sprintf("%s.terraformtest.com", rString) + zoneName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -321,9 +318,8 @@ func TestAccAWSRoute53Zone_DelegationSetID(t *testing.T) { func TestAccAWSRoute53Zone_ForceDestroy(t *testing.T) { var zone route53.GetHostedZoneOutput - rString := acctest.RandString(8) resourceName := "aws_route53_zone.test" - zoneName := fmt.Sprintf("%s.terraformtest.com", rString) + zoneName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -347,9 +343,8 @@ func TestAccAWSRoute53Zone_ForceDestroy(t *testing.T) { func TestAccAWSRoute53Zone_ForceDestroy_TrailingPeriod(t *testing.T) { var zone route53.GetHostedZoneOutput - rString := acctest.RandString(8) resourceName := "aws_route53_zone.test" - zoneName := fmt.Sprintf("%s.terraformtest.com", rString) + zoneName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -373,9 +368,8 @@ func TestAccAWSRoute53Zone_ForceDestroy_TrailingPeriod(t *testing.T) { func TestAccAWSRoute53Zone_Tags(t *testing.T) { var zone route53.GetHostedZoneOutput - rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_route53_zone.test" - zoneName := fmt.Sprintf("%s.terraformtest.com", rName) + zoneName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -424,7 +418,7 @@ func TestAccAWSRoute53Zone_VPC_Single(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_route53_zone.test" vpcResourceName := "aws_vpc.test1" - zoneName := fmt.Sprintf("%s.terraformtest.com", rName) + zoneName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -457,7 +451,7 @@ func TestAccAWSRoute53Zone_VPC_Multiple(t *testing.T) { resourceName := "aws_route53_zone.test" vpcResourceName1 := "aws_vpc.test1" vpcResourceName2 := "aws_vpc.test2" - zoneName := fmt.Sprintf("%s.terraformtest.com", rName) + zoneName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -491,7 +485,7 @@ func TestAccAWSRoute53Zone_VPC_Updates(t *testing.T) { resourceName := "aws_route53_zone.test" vpcResourceName1 := "aws_vpc.test1" vpcResourceName2 := "aws_vpc.test2" - zoneName := fmt.Sprintf("%s.terraformtest.com", rName) + zoneName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -696,14 +690,14 @@ resource "aws_route53_zone" "test" { `, zoneName) } -func testAccRoute53ZoneConfigMultiple() string { - return ` +func testAccRoute53ZoneConfigMultiple(domainName string) string { + return fmt.Sprintf(` resource "aws_route53_zone" "test" { count = 5 - name = "subdomain${count.index}.terraformtest.com" + name = "subdomain${count.index}.%[1]s" } -` +`, domainName) } func testAccRoute53ZoneConfigComment(zoneName, comment string) string { @@ -775,12 +769,12 @@ resource "aws_vpc" "test1" { cidr_block = "10.1.0.0/16" tags = { - Name = %q + Name = %[1]q } } resource "aws_route53_zone" "test" { - name = "%s." + name = "%[2]s." vpc { vpc_id = aws_vpc.test1.id From c7922a300f243dc402281754ab7afd5bbfb3fbd7 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 28 Jun 2021 15:19:09 -0700 Subject: [PATCH 1067/1208] Removes more domain names from API Gateway acceptance tests --- aws/resource_aws_api_gateway_rest_api_test.go | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/aws/resource_aws_api_gateway_rest_api_test.go b/aws/resource_aws_api_gateway_rest_api_test.go index 7c788fbaafaa..fba3ed46a5c6 100644 --- a/aws/resource_aws_api_gateway_rest_api_test.go +++ b/aws/resource_aws_api_gateway_rest_api_test.go @@ -1377,7 +1377,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -1418,7 +1418,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -1620,7 +1620,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -1702,7 +1702,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -1829,7 +1829,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -1868,7 +1868,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -1917,7 +1917,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -1956,7 +1956,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -1995,7 +1995,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -2044,7 +2044,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -2083,7 +2083,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -2131,7 +2131,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -2170,7 +2170,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -2217,7 +2217,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -2256,7 +2256,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -2298,7 +2298,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } @@ -2355,7 +2355,7 @@ resource "aws_api_gateway_rest_api" "test" { statusCode = 200 } } - uri = "https://aws.amazon.com/" + uri = "https://api.example.com/" } } } From 0ad26f26d174e4e78e45d3f2b14d1c5f79c66cc5 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 28 Jun 2021 15:55:10 -0700 Subject: [PATCH 1068/1208] Removes more domain names from Glue acceptance tests --- aws/data_source_aws_glue_connection_test.go | 15 +- aws/resource_aws_glue_crawler_test.go | 216 +++++++++++--------- 2 files changed, 123 insertions(+), 108 deletions(-) diff --git a/aws/data_source_aws_glue_connection_test.go b/aws/data_source_aws_glue_connection_test.go index b9d99ad7bad4..a62255c814cb 100644 --- a/aws/data_source_aws_glue_connection_test.go +++ b/aws/data_source_aws_glue_connection_test.go @@ -13,7 +13,9 @@ import ( func TestAccDataSourceAwsGlueConnection_basic(t *testing.T) { resourceName := "aws_glue_connection.test" datasourceName := "data.aws_glue_connection.test" - rName := fmt.Sprintf("tf-testacc-glue-connection-%s", acctest.RandString(13)) + rName := acctest.RandomWithPrefix("tf-acc-test") + + jdbcConnectionUrl := fmt.Sprintf("jdbc:mysql://%s/testdatabase", testAccRandomDomainName()) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -21,7 +23,7 @@ func TestAccDataSourceAwsGlueConnection_basic(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsGlueConnectionConfig(rName), + Config: testAccDataSourceAwsGlueConnectionConfig(rName, jdbcConnectionUrl), Check: resource.ComposeTestCheckFunc( testAccDataSourceAwsGlueConnectionCheck(datasourceName), resource.TestCheckResourceAttrPair(datasourceName, "catalog_id", resourceName, "catalog_id"), @@ -49,20 +51,21 @@ func testAccDataSourceAwsGlueConnectionCheck(name string) resource.TestCheckFunc } } -func testAccDataSourceAwsGlueConnectionConfig(rName string) string { +func testAccDataSourceAwsGlueConnectionConfig(rName, jdbcConnectionUrl string) string { return fmt.Sprintf(` resource "aws_glue_connection" "test" { + name = %[1]q + connection_properties = { - JDBC_CONNECTION_URL = "jdbc:mysql://terraformacctesting.com/testdatabase" + JDBC_CONNECTION_URL = %[2]q PASSWORD = "testpassword" USERNAME = "testusername" } - name = "%s" } data "aws_glue_connection" "test" { id = aws_glue_connection.test.id } -`, rName) +`, rName, jdbcConnectionUrl) } diff --git a/aws/resource_aws_glue_crawler_test.go b/aws/resource_aws_glue_crawler_test.go index bc59b615e491..2233738d4eb9 100644 --- a/aws/resource_aws_glue_crawler_test.go +++ b/aws/resource_aws_glue_crawler_test.go @@ -220,6 +220,8 @@ func TestAccAWSGlueCrawler_JdbcTarget(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_crawler.test" + jdbcConnectionUrl := fmt.Sprintf("jdbc:mysql://%s/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -227,7 +229,7 @@ func TestAccAWSGlueCrawler_JdbcTarget(t *testing.T) { CheckDestroy: testAccCheckAWSGlueCrawlerDestroy, Steps: []resource.TestStep{ { - Config: testAccGlueCrawlerConfig_JdbcTarget(rName, "database-name/%"), + Config: testAccGlueCrawlerConfig_JdbcTarget(rName, jdbcConnectionUrl, "database-name/%"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "glue", fmt.Sprintf("crawler/%s", rName)), @@ -252,7 +254,7 @@ func TestAccAWSGlueCrawler_JdbcTarget(t *testing.T) { ), }, { - Config: testAccGlueCrawlerConfig_JdbcTarget(rName, "database-name/table-name"), + Config: testAccGlueCrawlerConfig_JdbcTarget(rName, jdbcConnectionUrl, "database-name/table-name"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "glue", fmt.Sprintf("crawler/%s", rName)), @@ -290,6 +292,8 @@ func TestAccAWSGlueCrawler_JdbcTarget_Exclusions(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_crawler.test" + jdbcConnectionUrl := fmt.Sprintf("jdbc:mysql://%s/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -297,7 +301,7 @@ func TestAccAWSGlueCrawler_JdbcTarget_Exclusions(t *testing.T) { CheckDestroy: testAccCheckAWSGlueCrawlerDestroy, Steps: []resource.TestStep{ { - Config: testAccGlueCrawlerConfig_JdbcTarget_Exclusions2(rName, "exclusion1", "exclusion2"), + Config: testAccGlueCrawlerConfig_JdbcTarget_Exclusions2(rName, jdbcConnectionUrl, "exclusion1", "exclusion2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "glue", fmt.Sprintf("crawler/%s", rName)), @@ -308,7 +312,7 @@ func TestAccAWSGlueCrawler_JdbcTarget_Exclusions(t *testing.T) { ), }, { - Config: testAccGlueCrawlerConfig_JdbcTarget_Exclusions1(rName, "exclusion1"), + Config: testAccGlueCrawlerConfig_JdbcTarget_Exclusions1(rName, jdbcConnectionUrl, "exclusion1"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "glue", fmt.Sprintf("crawler/%s", rName)), @@ -331,6 +335,8 @@ func TestAccAWSGlueCrawler_JdbcTarget_Multiple(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_crawler.test" + jdbcConnectionUrl := fmt.Sprintf("jdbc:mysql://%s/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -338,7 +344,7 @@ func TestAccAWSGlueCrawler_JdbcTarget_Multiple(t *testing.T) { CheckDestroy: testAccCheckAWSGlueCrawlerDestroy, Steps: []resource.TestStep{ { - Config: testAccGlueCrawlerConfig_JdbcTarget_Multiple(rName, "database-name/table1", "database-name/table2"), + Config: testAccGlueCrawlerConfig_JdbcTarget_Multiple(rName, jdbcConnectionUrl, "database-name/table1", "database-name/table2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "glue", fmt.Sprintf("crawler/%s", rName)), @@ -352,7 +358,7 @@ func TestAccAWSGlueCrawler_JdbcTarget_Multiple(t *testing.T) { ), }, { - Config: testAccGlueCrawlerConfig_JdbcTarget(rName, "database-name/table1"), + Config: testAccGlueCrawlerConfig_JdbcTarget(rName, jdbcConnectionUrl, "database-name/table1"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "glue", fmt.Sprintf("crawler/%s", rName)), @@ -363,7 +369,7 @@ func TestAccAWSGlueCrawler_JdbcTarget_Multiple(t *testing.T) { ), }, { - Config: testAccGlueCrawlerConfig_JdbcTarget_Multiple(rName, "database-name/table1", "database-name/table2"), + Config: testAccGlueCrawlerConfig_JdbcTarget_Multiple(rName, jdbcConnectionUrl, "database-name/table1", "database-name/table2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), resource.TestCheckResourceAttr(resourceName, "jdbc_target.#", "2"), @@ -390,6 +396,8 @@ func TestAccAWSGlueCrawler_mongoDBTarget(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_crawler.test" + connectionUrl := fmt.Sprintf("mongodb://%s:27017/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -397,7 +405,7 @@ func TestAccAWSGlueCrawler_mongoDBTarget(t *testing.T) { CheckDestroy: testAccCheckAWSGlueCrawlerDestroy, Steps: []resource.TestStep{ { - Config: testAccGlueCrawlerConfigMongoDBTarget(rName, "database-name/%"), + Config: testAccGlueCrawlerConfigMongoDBTarget(rName, connectionUrl, "database-name/%"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), resource.TestCheckResourceAttr(resourceName, "mongodb_target.#", "1"), @@ -412,7 +420,7 @@ func TestAccAWSGlueCrawler_mongoDBTarget(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccGlueCrawlerConfigMongoDBTarget(rName, "database-name/table-name"), + Config: testAccGlueCrawlerConfigMongoDBTarget(rName, connectionUrl, "database-name/table-name"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), resource.TestCheckResourceAttr(resourceName, "mongodb_target.#", "1"), @@ -430,6 +438,8 @@ func TestAccAWSGlueCrawler_mongoDBTarget_scan_all(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_crawler.test" + connectionUrl := fmt.Sprintf("mongodb://%s:27017/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -437,7 +447,7 @@ func TestAccAWSGlueCrawler_mongoDBTarget_scan_all(t *testing.T) { CheckDestroy: testAccCheckAWSGlueCrawlerDestroy, Steps: []resource.TestStep{ { - Config: testAccGlueCrawlerConfigMongoDBTargetScanAll(rName, false), + Config: testAccGlueCrawlerConfigMongoDBTargetScanAll(rName, connectionUrl, false), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), resource.TestCheckResourceAttr(resourceName, "mongodb_target.#", "1"), @@ -452,7 +462,7 @@ func TestAccAWSGlueCrawler_mongoDBTarget_scan_all(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccGlueCrawlerConfigMongoDBTargetScanAll(rName, true), + Config: testAccGlueCrawlerConfigMongoDBTargetScanAll(rName, connectionUrl, true), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), resource.TestCheckResourceAttr(resourceName, "mongodb_target.#", "1"), @@ -462,7 +472,7 @@ func TestAccAWSGlueCrawler_mongoDBTarget_scan_all(t *testing.T) { ), }, { - Config: testAccGlueCrawlerConfigMongoDBTargetScanAll(rName, false), + Config: testAccGlueCrawlerConfigMongoDBTargetScanAll(rName, connectionUrl, false), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), resource.TestCheckResourceAttr(resourceName, "mongodb_target.#", "1"), @@ -480,6 +490,8 @@ func TestAccAWSGlueCrawler_mongoDBTarget_multiple(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_crawler.test" + connectionUrl := fmt.Sprintf("mongodb://%s:27017/testdatabase", testAccRandomDomainName()) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, glue.EndpointsID), @@ -487,7 +499,7 @@ func TestAccAWSGlueCrawler_mongoDBTarget_multiple(t *testing.T) { CheckDestroy: testAccCheckAWSGlueCrawlerDestroy, Steps: []resource.TestStep{ { - Config: testAccGlueCrawlerConfigMongoDBMultiple(rName, "database-name/table1", "database-name/table2"), + Config: testAccGlueCrawlerConfigMongoDBMultiple(rName, connectionUrl, "database-name/table1", "database-name/table2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), resource.TestCheckResourceAttr(resourceName, "mongodb_target.#", "2"), @@ -505,7 +517,7 @@ func TestAccAWSGlueCrawler_mongoDBTarget_multiple(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccGlueCrawlerConfigMongoDBTarget(rName, "database-name/%"), + Config: testAccGlueCrawlerConfigMongoDBTarget(rName, connectionUrl, "database-name/%"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), resource.TestCheckResourceAttr(resourceName, "mongodb_target.#", "1"), @@ -515,7 +527,7 @@ func TestAccAWSGlueCrawler_mongoDBTarget_multiple(t *testing.T) { ), }, { - Config: testAccGlueCrawlerConfigMongoDBMultiple(rName, "database-name/table1", "database-name/table2"), + Config: testAccGlueCrawlerConfigMongoDBMultiple(rName, connectionUrl, "database-name/table1", "database-name/table2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueCrawlerExists(resourceName, &crawler), resource.TestCheckResourceAttr(resourceName, "mongodb_target.#", "2"), @@ -1697,17 +1709,17 @@ resource "aws_glue_crawler" "test" { `, rName, path, scanRate) } -func testAccGlueCrawlerConfig_JdbcTarget(rName, path string) string { +func testAccGlueCrawlerConfig_JdbcTarget(rName, jdbcConnectionUrl, path string) string { return testAccGlueCrawlerConfig_Base(rName) + fmt.Sprintf(` resource "aws_glue_catalog_database" "test" { - name = %q + name = %[1]q } resource "aws_glue_connection" "test" { - name = %q + name = %[1]q connection_properties = { - JDBC_CONNECTION_URL = "jdbc:mysql://terraformacctesting.com/testdatabase" + JDBC_CONNECTION_URL = %[1]q PASSWORD = "testpassword" USERNAME = "testusername" } @@ -1717,28 +1729,28 @@ resource "aws_glue_crawler" "test" { depends_on = [aws_iam_role_policy_attachment.test-AWSGlueServiceRole] database_name = aws_glue_catalog_database.test.name - name = %q + name = %[1]q role = aws_iam_role.test.name jdbc_target { connection_name = aws_glue_connection.test.name - path = %q + path = %[3]q } } -`, rName, rName, rName, path) +`, rName, jdbcConnectionUrl, path) } -func testAccGlueCrawlerConfig_JdbcTarget_Exclusions1(rName, exclusion1 string) string { +func testAccGlueCrawlerConfig_JdbcTarget_Exclusions1(rName, jdbcConnectionUrl, exclusion1 string) string { return testAccGlueCrawlerConfig_Base(rName) + fmt.Sprintf(` resource "aws_glue_catalog_database" "test" { - name = %q + name = %[1]q } resource "aws_glue_connection" "test" { - name = %q + name = %[1]q connection_properties = { - JDBC_CONNECTION_URL = "jdbc:mysql://terraformacctesting.com/testdatabase" + JDBC_CONNECTION_URL = %[2]q PASSWORD = "testpassword" USERNAME = "testusername" } @@ -1748,29 +1760,29 @@ resource "aws_glue_crawler" "test" { depends_on = [aws_iam_role_policy_attachment.test-AWSGlueServiceRole] database_name = aws_glue_catalog_database.test.name - name = %q + name = %[1]q role = aws_iam_role.test.name jdbc_target { connection_name = aws_glue_connection.test.name - exclusions = [%q] + exclusions = [%[3]q] path = "database-name/table1" } } -`, rName, rName, rName, exclusion1) +`, rName, jdbcConnectionUrl, exclusion1) } -func testAccGlueCrawlerConfig_JdbcTarget_Exclusions2(rName, exclusion1, exclusion2 string) string { +func testAccGlueCrawlerConfig_JdbcTarget_Exclusions2(rName, jdbcConnectionUrl, exclusion1, exclusion2 string) string { return testAccGlueCrawlerConfig_Base(rName) + fmt.Sprintf(` resource "aws_glue_catalog_database" "test" { - name = %q + name = %[1]q } resource "aws_glue_connection" "test" { - name = %q + name = %[1]q connection_properties = { - JDBC_CONNECTION_URL = "jdbc:mysql://terraformacctesting.com/testdatabase" + JDBC_CONNECTION_URL = %[2]q PASSWORD = "testpassword" USERNAME = "testusername" } @@ -1780,29 +1792,29 @@ resource "aws_glue_crawler" "test" { depends_on = [aws_iam_role_policy_attachment.test-AWSGlueServiceRole] database_name = aws_glue_catalog_database.test.name - name = %q + name = %[1]q role = aws_iam_role.test.name jdbc_target { connection_name = aws_glue_connection.test.name - exclusions = [%q, %q] + exclusions = [%[3]q, %[4]q] path = "database-name/table1" } } -`, rName, rName, rName, exclusion1, exclusion2) +`, rName, jdbcConnectionUrl, exclusion1, exclusion2) } -func testAccGlueCrawlerConfig_JdbcTarget_Multiple(rName, path1, path2 string) string { +func testAccGlueCrawlerConfig_JdbcTarget_Multiple(rName, jdbcConnectionUrl, path1, path2 string) string { return testAccGlueCrawlerConfig_Base(rName) + fmt.Sprintf(` resource "aws_glue_catalog_database" "test" { - name = %q + name = %[1]q } resource "aws_glue_connection" "test" { - name = %q + name = %[1]q connection_properties = { - JDBC_CONNECTION_URL = "jdbc:mysql://terraformacctesting.com/testdatabase" + JDBC_CONNECTION_URL = %[2]q PASSWORD = "testpassword" USERNAME = "testusername" } @@ -1812,40 +1824,40 @@ resource "aws_glue_crawler" "test" { depends_on = [aws_iam_role_policy_attachment.test-AWSGlueServiceRole] database_name = aws_glue_catalog_database.test.name - name = %q + name = %[1]q role = aws_iam_role.test.name jdbc_target { connection_name = aws_glue_connection.test.name - path = %q + path = %[3]q } jdbc_target { connection_name = aws_glue_connection.test.name - path = %q + path = %[4]q } } -`, rName, rName, rName, path1, path2) +`, rName, jdbcConnectionUrl, path1, path2) } func testAccGlueCrawlerConfig_Role_ARN_NoPath(rName string) string { return testAccGlueCrawlerConfig_Base(rName) + fmt.Sprintf(` resource "aws_glue_catalog_database" "test" { - name = %q + name = %[1]q } resource "aws_glue_crawler" "test" { depends_on = [aws_iam_role_policy_attachment.test-AWSGlueServiceRole] database_name = aws_glue_catalog_database.test.name - name = %q + name = %[1]q role = aws_iam_role.test.arn s3_target { path = "s3://bucket-name" } } -`, rName, rName) +`, rName) } func testAccGlueCrawlerConfig_Role_ARN_Path(rName string) string { @@ -1853,7 +1865,7 @@ func testAccGlueCrawlerConfig_Role_ARN_Path(rName string) string { data "aws_partition" "current" {} resource "aws_iam_role" "test" { - name = %q + name = %[1]q path = "/path/" assume_role_policy = < Date: Tue, 29 Jun 2021 12:34:31 -0700 Subject: [PATCH 1069/1208] Removes more hard-coded domain names from Route 53 acceptance tests --- aws/data_source_aws_route53_zone_test.go | 42 ++-- aws/provider_test.go | 36 +++- aws/resource_aws_route53_health_check_test.go | 22 +- aws/resource_aws_route53_query_log_test.go | 15 +- ...esource_aws_route53_record_migrate_test.go | 8 +- aws/resource_aws_route53_record_test.go | 190 +++++++++--------- ...te53_resolver_firewall_domain_list_test.go | 11 +- ...ource_aws_route53_zone_association_test.go | 62 +++--- 8 files changed, 214 insertions(+), 172 deletions(-) diff --git a/aws/data_source_aws_route53_zone_test.go b/aws/data_source_aws_route53_zone_test.go index dcdcc6063135..9f130db6f352 100644 --- a/aws/data_source_aws_route53_zone_test.go +++ b/aws/data_source_aws_route53_zone_test.go @@ -10,10 +10,11 @@ import ( ) func TestAccAWSRoute53ZoneDataSource_id(t *testing.T) { - rInt := acctest.RandInt() resourceName := "aws_route53_zone.test" dataSourceName := "data.aws_route53_zone.test" + fqdn := testAccRandomFQDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -21,7 +22,7 @@ func TestAccAWSRoute53ZoneDataSource_id(t *testing.T) { CheckDestroy: testAccCheckRoute53ZoneDestroy, Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsRoute53ZoneConfigId(rInt), + Config: testAccDataSourceAwsRoute53ZoneConfigId(fqdn), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "id", dataSourceName, "id"), resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), @@ -34,10 +35,11 @@ func TestAccAWSRoute53ZoneDataSource_id(t *testing.T) { } func TestAccAWSRoute53ZoneDataSource_name(t *testing.T) { - rInt := acctest.RandInt() resourceName := "aws_route53_zone.test" dataSourceName := "data.aws_route53_zone.test" + fqdn := testAccRandomFQDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -45,7 +47,7 @@ func TestAccAWSRoute53ZoneDataSource_name(t *testing.T) { CheckDestroy: testAccCheckRoute53ZoneDestroy, Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsRoute53ZoneConfigName(rInt), + Config: testAccDataSourceAwsRoute53ZoneConfigName(fqdn), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "id", dataSourceName, "id"), resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), @@ -62,6 +64,8 @@ func TestAccAWSRoute53ZoneDataSource_tags(t *testing.T) { resourceName := "aws_route53_zone.test" dataSourceName := "data.aws_route53_zone.test" + fqdn := testAccRandomFQDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -69,7 +73,7 @@ func TestAccAWSRoute53ZoneDataSource_tags(t *testing.T) { CheckDestroy: testAccCheckRoute53ZoneDestroy, Steps: []resource.TestStep{ { - Config: testAccDataSourceAwsRoute53ZoneConfigTagsPrivate(rInt), + Config: testAccDataSourceAwsRoute53ZoneConfigTagsPrivate(fqdn, rInt), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "id", dataSourceName, "id"), resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), @@ -128,50 +132,46 @@ func TestAccAWSRoute53ZoneDataSource_serviceDiscovery(t *testing.T) { }) } -func testAccDataSourceAwsRoute53ZoneConfigId(rInt int) string { +func testAccDataSourceAwsRoute53ZoneConfigId(fqdn string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { - name = "terraformtestacchz-%[1]d.com." + name = %[1]q } data "aws_route53_zone" "test" { zone_id = aws_route53_zone.test.zone_id } -`, rInt) +`, fqdn) } -func testAccDataSourceAwsRoute53ZoneConfigName(rInt int) string { +func testAccDataSourceAwsRoute53ZoneConfigName(fqdn string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { - name = "terraformtestacchz-%[1]d.com." + name = %[1]q } data "aws_route53_zone" "test" { name = aws_route53_zone.test.name } -`, rInt) +`, fqdn) } -func testAccDataSourceAwsRoute53ZoneConfigTagsPrivate(rInt int) string { +func testAccDataSourceAwsRoute53ZoneConfigTagsPrivate(fqdn string, rInt int) string { return fmt.Sprintf(` resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" - - tags = { - Name = "terraform-testacc-r53-zone-data-source-%[1]d" - } } resource "aws_route53_zone" "test" { - name = "terraformtestacchz-%[1]d.com." + name = %[1]q vpc { vpc_id = aws_vpc.test.id } tags = { - Environment = "tf-acc-test-%[1]d" - Name = "tf-acc-test-%[1]d" + Environment = "tf-acc-test-%[2]d" + Name = "tf-acc-test-%[2]d" } } @@ -181,10 +181,10 @@ data "aws_route53_zone" "test" { vpc_id = aws_vpc.test.id tags = { - Environment = "tf-acc-test-%[1]d" + Environment = "tf-acc-test-%[2]d" } } -`, rInt) +`, fqdn, rInt) } func testAccDataSourceAwsRoute53ZoneConfigVpc(rInt int) string { diff --git a/aws/provider_test.go b/aws/provider_test.go index a9dcaccf772e..c7ac625ea757 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -2285,24 +2285,48 @@ func composeConfig(config ...string) string { return str.String() } -const testingTopLevelDomain = "test" +type domainName string + +// The top level domain ".test" is reserved by IANA for testing purposes: +// https://datatracker.ietf.org/doc/html/rfc6761 +const domainNameTestTopLevelDomain domainName = "test" // testAccRandomSubdomain creates a random three-level domain name in the form // "..test" // The top level domain ".test" is reserved by IANA for testing purposes: // https://datatracker.ietf.org/doc/html/rfc6761 func testAccRandomSubdomain() string { - return testAccSubdomainWithRandomSecondLevel(acctest.RandString(8)) + return string(testAccRandomDomain().RandomSubdomain()) } -// testAccRandomDomainName creates a random second level domain name in the form +// testAccRandomDomainName creates a random two-level domain name in the form // ".test" // The top level domain ".test" is reserved by IANA for testing purposes: // https://datatracker.ietf.org/doc/html/rfc6761 func testAccRandomDomainName() string { - return fmt.Sprintf("%s.%s", acctest.RandString(8), testingTopLevelDomain) + return string(testAccRandomDomain()) +} + +// testAccRandomFQDomainName creates a random fully-qualified two-level domain name in the form +// ".test." +// The top level domain ".test" is reserved by IANA for testing purposes: +// https://datatracker.ietf.org/doc/html/rfc6761 +func testAccRandomFQDomainName() string { + return string(testAccRandomDomain().FQDN()) +} + +func (d domainName) Subdomain(name string) domainName { + return domainName(fmt.Sprintf("%s.%s", name, d)) +} + +func (d domainName) RandomSubdomain() domainName { + return d.Subdomain(acctest.RandString(8)) +} + +func (d domainName) FQDN() domainName { + return domainName(fmt.Sprintf("%s.", d)) } -func testAccSubdomainWithRandomSecondLevel(thing string) string { - return fmt.Sprintf("%s.%s", thing, testAccRandomDomainName()) +func testAccRandomDomain() domainName { + return domainNameTestTopLevelDomain.RandomSubdomain() } diff --git a/aws/resource_aws_route53_health_check_test.go b/aws/resource_aws_route53_health_check_test.go index 097674d50771..15a0ca31866d 100644 --- a/aws/resource_aws_route53_health_check_test.go +++ b/aws/resource_aws_route53_health_check_test.go @@ -429,7 +429,7 @@ func testAccCheckRoute53HealthCheckDisappears(hCheck *route53.HealthCheck) resou const testAccRoute53HealthCheckConfig = ` resource "aws_route53_health_check" "test" { - fqdn = "dev.notexample.com" + fqdn = "dev.example.com" port = 80 type = "HTTP" resource_path = "/" @@ -443,7 +443,7 @@ resource "aws_route53_health_check" "test" { func testAccRoute53HealthCheckConfigTags1(tag1Key, tag1Value string) string { return fmt.Sprintf(` resource "aws_route53_health_check" "test" { - fqdn = "dev.notexample.com" + fqdn = "dev.example.com" port = 80 type = "HTTP" resource_path = "/" @@ -462,7 +462,7 @@ resource "aws_route53_health_check" "test" { func testAccRoute53HealthCheckConfigTags2(tag1Key, tag1Value, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_route53_health_check" "test" { - fqdn = "dev.notexample.com" + fqdn = "dev.example.com" port = 80 type = "HTTP" resource_path = "/" @@ -481,7 +481,7 @@ resource "aws_route53_health_check" "test" { const testAccRoute53HealthCheckConfigUpdate = ` resource "aws_route53_health_check" "test" { - fqdn = "dev.notexample.com" + fqdn = "dev.example.com" port = 80 type = "HTTP" resource_path = "/" @@ -539,7 +539,7 @@ resource "aws_route53_health_check" "test" { const testAccRoute53HealthCheckConfig_withChildHealthChecks = ` resource "aws_route53_health_check" "child1" { - fqdn = "child1.notexample.com" + fqdn = "child1.example.com" port = 80 type = "HTTP" resource_path = "/" @@ -602,7 +602,7 @@ resource "aws_route53_health_check" "test" { const testAccRoute53HealthCheckConfigWithSearchString = ` resource "aws_route53_health_check" "test" { - fqdn = "dev.notexample.com" + fqdn = "dev.example.com" port = 80 type = "HTTP_STR_MATCH" resource_path = "/" @@ -620,7 +620,7 @@ resource "aws_route53_health_check" "test" { const testAccRoute53HealthCheckConfigWithSearchStringUpdate = ` resource "aws_route53_health_check" "test" { - fqdn = "dev.notexample.com" + fqdn = "dev.example.com" port = 80 type = "HTTP_STR_MATCH" resource_path = "/" @@ -638,7 +638,7 @@ resource "aws_route53_health_check" "test" { const testAccRoute53HealthCheckConfigWithoutSNI = ` resource "aws_route53_health_check" "test" { - fqdn = "dev.notexample.com" + fqdn = "dev.example.com" port = 443 type = "HTTPS" resource_path = "/" @@ -655,7 +655,7 @@ resource "aws_route53_health_check" "test" { const testAccRoute53HealthCheckConfigWithSNI = ` resource "aws_route53_health_check" "test" { - fqdn = "dev.notexample.com" + fqdn = "dev.example.com" port = 443 type = "HTTPS" resource_path = "/" @@ -673,7 +673,7 @@ resource "aws_route53_health_check" "test" { const testAccRoute53HealthCheckConfigWithSNIDisabled = ` resource "aws_route53_health_check" "test" { - fqdn = "dev.notexample.com" + fqdn = "dev.example.com" port = 443 type = "HTTPS" resource_path = "/" @@ -694,7 +694,7 @@ func testAccRoute53HealthCheckConfigDisabled(disabled bool) string { resource "aws_route53_health_check" "test" { disabled = %[1]t failure_threshold = "2" - fqdn = "dev.notexample.com" + fqdn = "dev.example.com" port = 80 request_interval = "30" resource_path = "/" diff --git a/aws/resource_aws_route53_query_log_test.go b/aws/resource_aws_route53_query_log_test.go index 05e02070dede..dc6c45b622d9 100644 --- a/aws/resource_aws_route53_query_log_test.go +++ b/aws/resource_aws_route53_query_log_test.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "strings" "testing" "github.com/aws/aws-sdk-go/aws" @@ -72,7 +71,9 @@ func TestAccAWSRoute53QueryLog_basic(t *testing.T) { cloudwatchLogGroupResourceName := "aws_cloudwatch_log_group.test" resourceName := "aws_route53_query_log.test" route53ZoneResourceName := "aws_route53_zone.test" - rName := strings.ToLower(fmt.Sprintf("%s-%s", t.Name(), acctest.RandString(5))) + + rName := acctest.RandomWithPrefix("tf-acc-test") + domainName := testAccRandomDomainName() var queryLoggingConfig route53.QueryLoggingConfig resource.ParallelTest(t, resource.TestCase{ @@ -82,7 +83,7 @@ func TestAccAWSRoute53QueryLog_basic(t *testing.T) { CheckDestroy: testAccCheckRoute53QueryLogDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckAWSRoute53QueryLogResourceConfigBasic1(rName), + Config: testAccCheckAWSRoute53QueryLogResourceConfigBasic1(rName, domainName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53QueryLogExists(resourceName, &queryLoggingConfig), resource.TestCheckResourceAttrPair(resourceName, "cloudwatch_log_group_arn", cloudwatchLogGroupResourceName, "arn"), @@ -154,7 +155,7 @@ func testAccCheckRoute53QueryLogDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSRoute53QueryLogResourceConfigBasic1(rName string) string { +func testAccCheckAWSRoute53QueryLogResourceConfigBasic1(rName, domainName string) string { return composeConfig( testAccRoute53QueryLogRegionProviderConfig(), fmt.Sprintf(` @@ -182,12 +183,12 @@ data "aws_iam_policy_document" "test" { } resource "aws_cloudwatch_log_resource_policy" "test" { - policy_name = "%[1]s" + policy_name = %[1]q policy_document = data.aws_iam_policy_document.test.json } resource "aws_route53_zone" "test" { - name = "%[1]s.com" + name = %[2]q } resource "aws_route53_query_log" "test" { @@ -196,5 +197,5 @@ resource "aws_route53_query_log" "test" { cloudwatch_log_group_arn = aws_cloudwatch_log_group.test.arn zone_id = aws_route53_zone.test.zone_id } -`, rName)) +`, rName, domainName)) } diff --git a/aws/resource_aws_route53_record_migrate_test.go b/aws/resource_aws_route53_record_migrate_test.go index 69b4dfdb7225..8d7176e8c254 100644 --- a/aws/resource_aws_route53_record_migrate_test.go +++ b/aws/resource_aws_route53_record_migrate_test.go @@ -26,17 +26,17 @@ func TestAWSRoute53RecordMigrateState(t *testing.T) { StateVersion: 0, ID: "some_id", Attributes: map[string]string{ - "name": "www.notdomain.com.", + "name": "www.example.com.", }, - Expected: "www.notdomain.com", + Expected: "www.example.com", }, "v0_2": { StateVersion: 0, ID: "some_id", Attributes: map[string]string{ - "name": "www.notdomain.com", + "name": "www.example.com", }, - Expected: "www.notdomain.com", + Expected: "www.example.com", }, } diff --git a/aws/resource_aws_route53_record_test.go b/aws/resource_aws_route53_record_test.go index bbaa1c6cec99..9315da491f31 100644 --- a/aws/resource_aws_route53_record_test.go +++ b/aws/resource_aws_route53_record_test.go @@ -23,11 +23,11 @@ func TestCleanRecordName(t *testing.T) { cases := []struct { Input, Output string }{ - {"www.nonexample.com", "www.nonexample.com"}, - {"\\052.nonexample.com", "*.nonexample.com"}, - {"\\100.nonexample.com", "@.nonexample.com"}, - {"\\043.nonexample.com", "#.nonexample.com"}, - {"nonexample.com", "nonexample.com"}, + {"www.example.com", "www.example.com"}, + {"\\052.example.com", "*.example.com"}, + {"\\100.example.com", "@.example.com"}, + {"\\043.example.com", "#.example.com"}, + {"example.com", "example.com"}, } for _, tc := range cases { @@ -42,16 +42,16 @@ func TestExpandRecordName(t *testing.T) { cases := []struct { Input, Output string }{ - {"www", "www.nonexample.com"}, - {"www.", "www.nonexample.com"}, - {"dev.www", "dev.www.nonexample.com"}, - {"*", "*.nonexample.com"}, - {"nonexample.com", "nonexample.com"}, - {"test.nonexample.com", "test.nonexample.com"}, - {"test.nonexample.com.", "test.nonexample.com"}, + {"www", "www.example.com"}, + {"www.", "www.example.com"}, + {"dev.www", "dev.www.example.com"}, + {"*", "*.example.com"}, + {"example.com", "example.com"}, + {"test.example.com", "test.example.com"}, + {"test.example.com.", "test.example.com"}, } - zone_name := "nonexample.com" + zone_name := "example.com" for _, tc := range cases { actual := expandRecordName(tc.Input, zone_name) if actual != tc.Output { @@ -64,11 +64,11 @@ func TestNormalizeAwsAliasName(t *testing.T) { cases := []struct { Input, Output string }{ - {"www.nonexample.com", "www.nonexample.com"}, - {"www.nonexample.com.", "www.nonexample.com"}, + {"www.example.com", "www.example.com"}, + {"www.example.com.", "www.example.com"}, {"dualstack.name-123456789.region.elb.amazonaws.com", "name-123456789.region.elb.amazonaws.com"}, {"dualstack.test-987654321.region.elb.amazonaws.com", "test-987654321.region.elb.amazonaws.com"}, - {"dualstacktest.com", "dualstacktest.com"}, + {"dualstacktest.test", "dualstacktest.test"}, {"NAME-123456789.region.elb.amazonaws.com", "name-123456789.region.elb.amazonaws.com"}, } @@ -84,11 +84,11 @@ func TestParseRecordId(t *testing.T) { cases := []struct { Input, Zone, Name, Type, Set string }{ - {"ABCDEF_test.notexample.com_A", "ABCDEF", "test.notexample.com", "A", ""}, - {"ABCDEF_test.notexample.com._A", "ABCDEF", "test.notexample.com", "A", ""}, - {"ABCDEF_test.notexample.com_A_set1", "ABCDEF", "test.notexample.com", "A", "set1"}, - {"ABCDEF__underscore.notexample.com_A", "ABCDEF", "_underscore.notexample.com", "A", ""}, - {"ABCDEF__underscore.notexample.com_A_set1", "ABCDEF", "_underscore.notexample.com", "A", "set1"}, + {"ABCDEF_test.example.com_A", "ABCDEF", "test.example.com", "A", ""}, + {"ABCDEF_test.example.com._A", "ABCDEF", "test.example.com", "A", ""}, + {"ABCDEF_test.example.com_A_set1", "ABCDEF", "test.example.com", "A", "set1"}, + {"ABCDEF__underscore.example.com_A", "ABCDEF", "_underscore.example.com", "A", ""}, + {"ABCDEF__underscore.example.com_A_set1", "ABCDEF", "_underscore.example.com", "A", "set1"}, } for _, tc := range cases { @@ -318,7 +318,7 @@ func TestAccAWSRoute53Record_spfSupport(t *testing.T) { Config: testAccRoute53RecordConfigSPF, Check: resource.ComposeTestCheckFunc( testAccCheckRoute53RecordExists(resourceName, &record1), - resource.TestCheckTypeSetElemAttr(resourceName, "records.*", "include:notexample.com"), + resource.TestCheckTypeSetElemAttr(resourceName, "records.*", "include:domain.test"), ), }, { @@ -345,7 +345,7 @@ func TestAccAWSRoute53Record_caaSupport(t *testing.T) { Config: testAccRoute53RecordConfigCAA, Check: resource.ComposeTestCheckFunc( testAccCheckRoute53RecordExists(resourceName, &record1), - resource.TestCheckTypeSetElemAttr(resourceName, "records.*", "0 issue \"exampleca.com;\""), + resource.TestCheckTypeSetElemAttr(resourceName, "records.*", "0 issue \"domainca.test;\""), ), }, { @@ -1069,7 +1069,7 @@ func testAccAWSRoute53RecordOverwriteExpectErrorCheck(t *testing.T) resource.Err t.Fatalf("Expected an error but got none") } - re := regexp.MustCompile(`Tried to create resource record set \[name='www.notexample.com.', type='A'] but it already exists`) + re := regexp.MustCompile(`Tried to create resource record set \[name='www.domain.test.', type='A'] but it already exists`) if !re.MatchString(err.Error()) { t.Fatalf("Expected an error with pattern, no match on: %s", err) } @@ -1090,7 +1090,7 @@ func testAccCheckRoute53RecordDestroy(s *terraform.State) error { name := parts[1] rType := parts[2] - en := expandRecordName(name, "notexample.com") + en := expandRecordName(name, "domain.test") lopts := &route53.ListResourceRecordSetsInput{ HostedZoneId: aws.String(cleanZoneID(zone)), @@ -1171,7 +1171,7 @@ func testAccCheckRoute53RecordExists(n string, resourceRecordSet *route53.Resour name := parts[1] rType := parts[2] - en := expandRecordName(name, "notexample.com") + en := expandRecordName(name, "domain.test") lopts := &route53.ListResourceRecordSetsInput{ HostedZoneId: aws.String(cleanZoneID(zone)), @@ -1240,12 +1240,12 @@ func testAccCheckRoute53RecordDoesNotExist(zoneResourceName string, recordName s func testAccRoute53RecordConfig_allowOverwrite(allowOverwrite bool) string { return fmt.Sprintf(` resource "aws_route53_zone" "main" { - name = "notexample.com." + name = "domain.test." } resource "aws_route53_record" "default" { zone_id = aws_route53_zone.main.zone_id - name = "www.notexample.com" + name = "www.domain.test" type = "A" ttl = "30" records = ["127.0.0.1"] @@ -1256,7 +1256,7 @@ resource "aws_route53_record" "overwriting" { allow_overwrite = %[1]t zone_id = aws_route53_zone.main.zone_id - name = "www.notexample.com" + name = "www.domain.test" type = "A" ttl = "30" records = ["127.0.0.1"] @@ -1266,12 +1266,12 @@ resource "aws_route53_record" "overwriting" { const testAccRoute53RecordConfig = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { zone_id = aws_route53_zone.main.zone_id - name = "www.NOTexamplE.com" + name = "www.DOmaiN.test" type = "A" ttl = "30" records = ["127.0.0.1", "127.0.0.27"] @@ -1280,12 +1280,12 @@ resource "aws_route53_record" "default" { const testAccRoute53RecordConfig_nameWithTrailingPeriod = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { zone_id = aws_route53_zone.main.zone_id - name = "www.NOTexamplE.com." + name = "www.DOmaiN.test." type = "A" ttl = "30" records = ["127.0.0.1", "127.0.0.27"] @@ -1294,7 +1294,7 @@ resource "aws_route53_record" "default" { const testAccRoute53RecordConfigMultiple = ` resource "aws_route53_zone" "test" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "test" { @@ -1310,12 +1310,12 @@ resource "aws_route53_record" "test" { const testAccRoute53RecordConfig_fqdn = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { zone_id = aws_route53_zone.main.zone_id - name = "www.NOTexamplE.com" + name = "www.DOmaiN.test" type = "A" ttl = "30" records = ["127.0.0.1", "127.0.0.27"] @@ -1328,12 +1328,12 @@ resource "aws_route53_record" "default" { const testAccRoute53RecordConfig_fqdn_no_op = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { zone_id = aws_route53_zone.main.zone_id - name = "www.NOTexamplE.com." + name = "www.DOmaiN.test." type = "A" ttl = "30" records = ["127.0.0.1", "127.0.0.27"] @@ -1346,7 +1346,7 @@ resource "aws_route53_record" "default" { const testAccRoute53RecordConfigSuffix = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { @@ -1360,7 +1360,7 @@ resource "aws_route53_record" "default" { const testAccRoute53WildCardRecordConfig = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { @@ -1373,7 +1373,7 @@ resource "aws_route53_record" "default" { resource "aws_route53_record" "wildcard" { zone_id = aws_route53_zone.main.zone_id - name = "*.notexample.com" + name = "*.domain.test" type = "A" ttl = "30" records = ["127.0.0.1"] @@ -1382,7 +1382,7 @@ resource "aws_route53_record" "wildcard" { const testAccRoute53WildCardRecordConfigUpdate = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { @@ -1395,7 +1395,7 @@ resource "aws_route53_record" "default" { resource "aws_route53_record" "wildcard" { zone_id = aws_route53_zone.main.zone_id - name = "*.notexample.com" + name = "*.domain.test" type = "A" ttl = "60" records = ["127.0.0.1"] @@ -1404,7 +1404,7 @@ resource "aws_route53_record" "wildcard" { const testAccRoute53RecordConfigTXT = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { @@ -1418,7 +1418,7 @@ resource "aws_route53_record" "default" { const testAccRoute53RecordConfigSPF = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { @@ -1426,13 +1426,13 @@ resource "aws_route53_record" "default" { name = "test" type = "SPF" ttl = "30" - records = ["include:notexample.com"] + records = ["include:domain.test"] } ` const testAccRoute53RecordConfigCAA = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { @@ -1441,13 +1441,13 @@ resource "aws_route53_record" "default" { type = "CAA" ttl = "30" - records = ["0 issue \"exampleca.com;\""] + records = ["0 issue \"domainca.test;\""] } ` const testAccRoute53RecordConfigDS = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { @@ -1461,11 +1461,11 @@ resource "aws_route53_record" "default" { const testAccRoute53FailoverCNAMERecord = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_health_check" "foo" { - fqdn = "dev.notexample.com" + fqdn = "dev.domain.test" port = 80 type = "HTTP" resource_path = "/" @@ -1489,7 +1489,7 @@ resource "aws_route53_record" "www-primary" { health_check_id = aws_route53_health_check.foo.id set_identifier = "www-primary" - records = ["primary.notexample.com"] + records = ["primary.domain.test"] } resource "aws_route53_record" "www-secondary" { @@ -1503,13 +1503,13 @@ resource "aws_route53_record" "www-secondary" { } set_identifier = "www-secondary" - records = ["secondary.notexample.com"] + records = ["secondary.domain.test"] } ` const testAccRoute53WeightedCNAMERecord = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "www-dev" { @@ -1523,7 +1523,7 @@ resource "aws_route53_record" "www-dev" { } set_identifier = "dev" - records = ["dev.notexample.com"] + records = ["dev.domain.test"] } resource "aws_route53_record" "www-live" { @@ -1537,7 +1537,7 @@ resource "aws_route53_record" "www-live" { } set_identifier = "live" - records = ["dev.notexample.com"] + records = ["dev.domain.test"] } resource "aws_route53_record" "www-off" { @@ -1551,13 +1551,13 @@ resource "aws_route53_record" "www-off" { } set_identifier = "off" - records = ["dev.notexample.com"] + records = ["dev.domain.test"] } ` const testAccRoute53GeolocationCNAMERecord = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "default" { @@ -1571,7 +1571,7 @@ resource "aws_route53_record" "default" { } set_identifier = "Default" - records = ["dev.notexample.com"] + records = ["dev.domain.test"] } resource "aws_route53_record" "california" { @@ -1586,7 +1586,7 @@ resource "aws_route53_record" "california" { } set_identifier = "California" - records = ["dev.notexample.com"] + records = ["dev.domain.test"] } resource "aws_route53_record" "oceania" { @@ -1600,7 +1600,7 @@ resource "aws_route53_record" "oceania" { } set_identifier = "Oceania" - records = ["dev.notexample.com"] + records = ["dev.domain.test"] } resource "aws_route53_record" "denmark" { @@ -1614,14 +1614,14 @@ resource "aws_route53_record" "denmark" { } set_identifier = "Denmark" - records = ["dev.notexample.com"] + records = ["dev.domain.test"] } ` func testAccRoute53LatencyCNAMERecord(firstRegion, secondRegion, thirdRegion string) string { return fmt.Sprintf(` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "first_region" { @@ -1635,7 +1635,7 @@ resource "aws_route53_record" "first_region" { } set_identifier = %[1]q - records = ["dev.notexample.com"] + records = ["dev.domain.test"] } resource "aws_route53_record" "second_region" { @@ -1649,7 +1649,7 @@ resource "aws_route53_record" "second_region" { } set_identifier = %[2]q - records = ["dev.notexample.com"] + records = ["dev.domain.test"] } resource "aws_route53_record" "third_region" { @@ -1663,7 +1663,7 @@ resource "aws_route53_record" "third_region" { } set_identifier = %[3]q - records = ["dev.notexample.com"] + records = ["dev.domain.test"] } `, firstRegion, secondRegion, thirdRegion) } @@ -1679,7 +1679,7 @@ data "aws_availability_zones" "available" { } resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "alias" { @@ -1718,7 +1718,7 @@ data "aws_availability_zones" "available" { } resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "alias" { @@ -1749,7 +1749,7 @@ resource "aws_elb" "main" { func testAccRoute53RecordConfigAliasS3(rName string) string { return fmt.Sprintf(` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_s3_bucket" "website" { @@ -1779,12 +1779,12 @@ func testAccRoute53RecordConfigHealthCheckIdSetIdentifier(setIdentifier string) return fmt.Sprintf(` resource "aws_route53_zone" "test" { force_destroy = true - name = "notexample.com" + name = "domain.test" } resource "aws_route53_health_check" "test" { failure_threshold = "2" - fqdn = "test.notexample.com" + fqdn = "test.domain.test" port = 80 request_interval = "30" resource_path = "/" @@ -1811,12 +1811,12 @@ func testAccRoute53RecordConfigHealthCheckIdTypeA() string { return ` resource "aws_route53_zone" "test" { force_destroy = true - name = "notexample.com" + name = "domain.test" } resource "aws_route53_health_check" "test" { failure_threshold = "2" - fqdn = "test.notexample.com" + fqdn = "test.domain.test" port = 80 request_interval = "30" resource_path = "/" @@ -1843,12 +1843,12 @@ func testAccRoute53RecordConfigHealthCheckIdTypeCname() string { return ` resource "aws_route53_zone" "test" { force_destroy = true - name = "notexample.com" + name = "domain.test" } resource "aws_route53_health_check" "test" { failure_threshold = "2" - fqdn = "test.notexample.com" + fqdn = "test.domain.test" port = 80 request_interval = "30" resource_path = "/" @@ -1859,7 +1859,7 @@ resource "aws_route53_record" "test" { zone_id = aws_route53_zone.test.zone_id health_check_id = aws_route53_health_check.test.id name = "test" - records = ["test1.notexample.com"] + records = ["test1.domain.test"] set_identifier = "test" ttl = "5" type = "CNAME" @@ -1921,7 +1921,7 @@ resource "aws_vpc_endpoint" "test" { } resource "aws_route53_zone" "test" { - name = "notexample.com" + name = "domain.test" vpc { vpc_id = aws_vpc.test.id @@ -1973,7 +1973,7 @@ data "aws_availability_zones" "available" { } resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_elb" "live" { @@ -2039,7 +2039,7 @@ resource "aws_route53_record" "elb_weighted_alias_dev" { const testAccRoute53WeightedR53AliasRecord = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "blue_origin" { @@ -2097,7 +2097,7 @@ resource "aws_route53_record" "r53_weighted_alias_dev" { const testAccRoute53RecordTypeChangePre = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "sample" { @@ -2111,7 +2111,7 @@ resource "aws_route53_record" "sample" { const testAccRoute53RecordTypeChangePost = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "sample" { @@ -2125,7 +2125,7 @@ resource "aws_route53_record" "sample" { const testAccRoute53RecordNameChangePre = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "sample" { @@ -2139,7 +2139,7 @@ resource "aws_route53_record" "sample" { const testAccRoute53RecordNameChangePost = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "sample" { @@ -2153,7 +2153,7 @@ resource "aws_route53_record" "sample" { const testAccRoute53RecordSetIdentifierChangePre = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "basic_to_weighted" { @@ -2167,7 +2167,7 @@ resource "aws_route53_record" "basic_to_weighted" { const testAccRoute53RecordSetIdentifierChangePost = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "basic_to_weighted" { @@ -2195,7 +2195,7 @@ data "aws_availability_zones" "available" { } resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_elb" "alias_change" { @@ -2225,7 +2225,7 @@ resource "aws_route53_record" "elb_alias_change" { const testAccRoute53RecordAliasChangePost = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "elb_alias_change" { @@ -2239,7 +2239,7 @@ resource "aws_route53_record" "elb_alias_change" { const testAccRoute53RecordConfigEmptyName = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "empty" { @@ -2253,12 +2253,12 @@ resource "aws_route53_record" "empty" { const testAccRoute53RecordConfigLongTxtRecord = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "long_txt" { zone_id = aws_route53_zone.main.zone_id - name = "google.notexample.com" + name = "google.domain.test" type = "TXT" ttl = "30" records = [ @@ -2269,12 +2269,12 @@ resource "aws_route53_record" "long_txt" { const testAccRoute53RecordConfigUnderscoreInName = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "underscore" { zone_id = aws_route53_zone.main.zone_id - name = "_underscore.notexample.com" + name = "_underscore.domain.test" type = "A" ttl = "30" records = ["127.0.0.1"] @@ -2283,7 +2283,7 @@ resource "aws_route53_record" "underscore" { const testAccRoute53MultiValueAnswerARecord = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "www-server1" { @@ -2309,7 +2309,7 @@ resource "aws_route53_record" "www-server2" { const testaccRoute53RecordConfigWithWeightedRoutingPolicy = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "www-server1" { @@ -2329,7 +2329,7 @@ resource "aws_route53_record" "www-server1" { const testaccRoute53RecordConfigWithSimpleRoutingPolicy = ` resource "aws_route53_zone" "main" { - name = "notexample.com" + name = "domain.test" } resource "aws_route53_record" "www-server1" { diff --git a/aws/resource_aws_route53_resolver_firewall_domain_list_test.go b/aws/resource_aws_route53_resolver_firewall_domain_list_test.go index f0897972006d..c076ea850708 100644 --- a/aws/resource_aws_route53_resolver_firewall_domain_list_test.go +++ b/aws/resource_aws_route53_resolver_firewall_domain_list_test.go @@ -99,6 +99,9 @@ func TestAccAWSRoute53ResolverFirewallDomainList_domains(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_route53_resolver_firewall_domain_list.test" + domainName1 := testAccRandomFQDomainName() + domainName2 := testAccRandomFQDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, ErrorCheck: testAccErrorCheck(t, route53resolver.EndpointsID), @@ -106,12 +109,12 @@ func TestAccAWSRoute53ResolverFirewallDomainList_domains(t *testing.T) { CheckDestroy: testAccCheckRoute53ResolverFirewallDomainListDestroy, Steps: []resource.TestStep{ { - Config: testAccRoute53ResolverFirewallDomainListConfigDomains(rName, "foo.com."), + Config: testAccRoute53ResolverFirewallDomainListConfigDomains(rName, domainName1), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverFirewallDomainListExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "domains.#", "1"), - resource.TestCheckTypeSetElemAttr(resourceName, "domains.*", "foo.com."), + resource.TestCheckTypeSetElemAttr(resourceName, "domains.*", domainName1), ), }, { @@ -120,12 +123,12 @@ func TestAccAWSRoute53ResolverFirewallDomainList_domains(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccRoute53ResolverFirewallDomainListConfigDomains(rName, "bar.com."), + Config: testAccRoute53ResolverFirewallDomainListConfigDomains(rName, domainName2), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverFirewallDomainListExists(resourceName, &v), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "domains.#", "1"), - resource.TestCheckTypeSetElemAttr(resourceName, "domains.*", "bar.com."), + resource.TestCheckTypeSetElemAttr(resourceName, "domains.*", domainName2), ), }, { diff --git a/aws/resource_aws_route53_zone_association_test.go b/aws/resource_aws_route53_zone_association_test.go index 9271b6f4b755..3152e20534d6 100644 --- a/aws/resource_aws_route53_zone_association_test.go +++ b/aws/resource_aws_route53_zone_association_test.go @@ -11,7 +11,9 @@ import ( ) func TestAccAWSRoute53ZoneAssociation_basic(t *testing.T) { - resourceName := "aws_route53_zone_association.foobar" + resourceName := "aws_route53_zone_association.test" + + domainName := testAccRandomFQDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -20,7 +22,7 @@ func TestAccAWSRoute53ZoneAssociation_basic(t *testing.T) { CheckDestroy: testAccCheckRoute53ZoneAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRoute53ZoneAssociationConfig, + Config: testAccRoute53ZoneAssociationConfig(domainName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ZoneAssociationExists(resourceName), ), @@ -35,7 +37,9 @@ func TestAccAWSRoute53ZoneAssociation_basic(t *testing.T) { } func TestAccAWSRoute53ZoneAssociation_disappears(t *testing.T) { - resourceName := "aws_route53_zone_association.foobar" + resourceName := "aws_route53_zone_association.test" + + domainName := testAccRandomFQDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -44,7 +48,7 @@ func TestAccAWSRoute53ZoneAssociation_disappears(t *testing.T) { CheckDestroy: testAccCheckRoute53ZoneAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRoute53ZoneAssociationConfig, + Config: testAccRoute53ZoneAssociationConfig(domainName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ZoneAssociationExists(resourceName), testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53ZoneAssociation(), resourceName), @@ -56,9 +60,11 @@ func TestAccAWSRoute53ZoneAssociation_disappears(t *testing.T) { } func TestAccAWSRoute53ZoneAssociation_disappears_VPC(t *testing.T) { - resourceName := "aws_route53_zone_association.foobar" + resourceName := "aws_route53_zone_association.test" vpcResourceName := "aws_vpc.bar" + domainName := testAccRandomFQDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -66,7 +72,7 @@ func TestAccAWSRoute53ZoneAssociation_disappears_VPC(t *testing.T) { CheckDestroy: testAccCheckRoute53ZoneAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRoute53ZoneAssociationConfig, + Config: testAccRoute53ZoneAssociationConfig(domainName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ZoneAssociationExists(resourceName), testAccCheckResourceDisappears(testAccProvider, resourceAwsVpc(), vpcResourceName), @@ -78,9 +84,11 @@ func TestAccAWSRoute53ZoneAssociation_disappears_VPC(t *testing.T) { } func TestAccAWSRoute53ZoneAssociation_disappears_Zone(t *testing.T) { - resourceName := "aws_route53_zone_association.foobar" + resourceName := "aws_route53_zone_association.test" route53ZoneResourceName := "aws_route53_zone.foo" + domainName := testAccRandomFQDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), @@ -88,7 +96,7 @@ func TestAccAWSRoute53ZoneAssociation_disappears_Zone(t *testing.T) { CheckDestroy: testAccCheckRoute53ZoneAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRoute53ZoneAssociationConfig, + Config: testAccRoute53ZoneAssociationConfig(domainName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ZoneAssociationExists(resourceName), testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53Zone(), route53ZoneResourceName), @@ -106,6 +114,8 @@ func TestAccAWSRoute53ZoneAssociation_CrossAccount(t *testing.T) { // check for the instances in each region var providers []*schema.Provider + domainName := testAccRandomFQDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) @@ -116,13 +126,13 @@ func TestAccAWSRoute53ZoneAssociation_CrossAccount(t *testing.T) { CheckDestroy: testAccCheckRoute53ZoneAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRoute53ZoneAssociationCrossAccountConfig(), + Config: testAccRoute53ZoneAssociationCrossAccountConfig(domainName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ZoneAssociationExists(resourceName), ), }, { - Config: testAccRoute53ZoneAssociationCrossAccountConfig(), + Config: testAccRoute53ZoneAssociationCrossAccountConfig(domainName), ResourceName: resourceName, ImportState: true, ImportStateVerify: true, @@ -138,6 +148,8 @@ func TestAccAWSRoute53ZoneAssociation_CrossRegion(t *testing.T) { // check for the instances in each region var providers []*schema.Provider + domainName := testAccRandomFQDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) @@ -148,13 +160,13 @@ func TestAccAWSRoute53ZoneAssociation_CrossRegion(t *testing.T) { CheckDestroy: testAccCheckRoute53ZoneAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccRoute53ZoneAssociationRegionConfig(), + Config: testAccRoute53ZoneAssociationRegionConfig(domainName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ZoneAssociationExists(resourceName), ), }, { - Config: testAccRoute53ZoneAssociationRegionConfig(), + Config: testAccRoute53ZoneAssociationRegionConfig(domainName), ResourceName: resourceName, ImportState: true, ImportStateVerify: true, @@ -226,7 +238,8 @@ func testAccCheckRoute53ZoneAssociationExists(resourceName string) resource.Test } } -const testAccRoute53ZoneAssociationConfig = ` +func testAccRoute53ZoneAssociationConfig(domainName string) string { + return fmt.Sprintf(` resource "aws_vpc" "foo" { cidr_block = "10.6.0.0/16" enable_dns_hostnames = true @@ -248,7 +261,7 @@ resource "aws_vpc" "bar" { } resource "aws_route53_zone" "foo" { - name = "foo.com" + name = %[1]q vpc { vpc_id = aws_vpc.foo.id @@ -259,16 +272,17 @@ resource "aws_route53_zone" "foo" { } } -resource "aws_route53_zone_association" "foobar" { +resource "aws_route53_zone_association" "test" { zone_id = aws_route53_zone.foo.id vpc_id = aws_vpc.bar.id } -` +`, domainName) +} -func testAccRoute53ZoneAssociationCrossAccountConfig() string { +func testAccRoute53ZoneAssociationCrossAccountConfig(domainName string) string { return composeConfig( testAccAlternateAccountProviderConfig(), - ` + fmt.Sprintf(` resource "aws_vpc" "alternate" { provider = "awsalternate" @@ -286,7 +300,7 @@ resource "aws_vpc" "test" { resource "aws_route53_zone" "test" { provider = "awsalternate" - name = "foo.com" + name = %[1]q vpc { vpc_id = aws_vpc.alternate.id @@ -308,13 +322,13 @@ resource "aws_route53_zone_association" "test" { vpc_id = aws_route53_vpc_association_authorization.test.vpc_id zone_id = aws_route53_vpc_association_authorization.test.zone_id } -`) +`, domainName)) } -func testAccRoute53ZoneAssociationRegionConfig() string { +func testAccRoute53ZoneAssociationRegionConfig(domainName string) string { return composeConfig( testAccMultipleRegionProviderConfig(2), - ` + fmt.Sprintf(` data "aws_region" "alternate" { provider = "awsalternate" } @@ -344,7 +358,7 @@ resource "aws_vpc" "alternate" { } resource "aws_route53_zone" "test" { - name = "foo.com" + name = %[1]q vpc { vpc_id = aws_vpc.test.id @@ -361,5 +375,5 @@ resource "aws_route53_zone_association" "test" { vpc_region = data.aws_region.alternate.name zone_id = aws_route53_zone.test.id } -`) +`, domainName)) } From d189f4b8e92f6bec6421bf29f061bc2383274199 Mon Sep 17 00:00:00 2001 From: Ian Dillon Date: Mon, 21 Sep 2020 09:29:34 -0400 Subject: [PATCH 1070/1208] r/aws_guardduty_organization_configuration: Adds datasource/s3_logs auto_enable attribute. --- ...ws_guardduty_organization_configuration.go | 90 ++++++++++++++++++- ...ardduty_organization_configuration_test.go | 71 +++++++++++++++ aws/resource_aws_guardduty_test.go | 3 +- ...y_organization_configuration.html.markdown | 16 ++++ 4 files changed, 177 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_guardduty_organization_configuration.go b/aws/resource_aws_guardduty_organization_configuration.go index 2a1857bb230a..7ca8425503fa 100644 --- a/aws/resource_aws_guardduty_organization_configuration.go +++ b/aws/resource_aws_guardduty_organization_configuration.go @@ -32,6 +32,30 @@ func resourceAwsGuardDutyOrganizationConfiguration() *schema.Resource { ForceNew: true, ValidateFunc: validation.NoZeroValues, }, + "datasources": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "s3_logs": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "auto_enable": { + Type: schema.TypeBool, + Required: true, + }, + }, + }, + }, + }, + }, + }, }, } } @@ -42,8 +66,9 @@ func resourceAwsGuardDutyOrganizationConfigurationUpdate(d *schema.ResourceData, detectorID := d.Get("detector_id").(string) input := &guardduty.UpdateOrganizationConfigurationInput{ - AutoEnable: aws.Bool(d.Get("auto_enable").(bool)), - DetectorId: aws.String(detectorID), + AutoEnable: aws.Bool(d.Get("auto_enable").(bool)), + DetectorId: aws.String(detectorID), + DataSources: expandOrganizationDatasourceConfig(d), } _, err := conn.UpdateOrganizationConfiguration(input) @@ -80,8 +105,69 @@ func resourceAwsGuardDutyOrganizationConfigurationRead(d *schema.ResourceData, m return fmt.Errorf("error reading GuardDuty Organization Configuration (%s): empty response", d.Id()) } + if err := d.Set("datasources", flattenOrganizationDatasourceConfig(output.DataSources)); err != nil { + return fmt.Errorf("error setting datasources: %s", err) + } + d.Set("detector_id", d.Id()) d.Set("auto_enable", output.AutoEnable) return nil } + +func flattenOrganizationDatasourceConfig(dsConfig *guardduty.OrganizationDataSourceConfigurationsResult) []interface{} { + if dsConfig == nil { + return []interface{}{} + } + + values := map[string]interface{}{} + + if v := dsConfig.S3Logs; v != nil { + values["s3_logs"] = flattenOrganizationS3LogsConfig(v) + } + + return []interface{}{values} +} + +func flattenOrganizationS3LogsConfig(s3LogsConfig *guardduty.OrganizationS3LogsConfigurationResult) []interface{} { + values := map[string]interface{}{} + + if s3LogsConfig == nil { + values["auto_enable"] = false + } else { + values["auto_enable"] = aws.BoolValue(s3LogsConfig.AutoEnable) + } + + return []interface{}{values} +} + +func expandOrganizationDatasourceConfig(d *schema.ResourceData) *guardduty.OrganizationDataSourceConfigurations { + dsConfig := &guardduty.OrganizationDataSourceConfigurations{} + + if v, ok := d.GetOk("datasources"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + configList := v.([]interface{}) + data := configList[0].(map[string]interface{}) + + if v, ok := data["s3_logs"]; ok { + dsConfig.S3Logs = expandOrganizationS3LogsConfig(v.([]interface{})) + } + } + + return dsConfig +} + +func expandOrganizationS3LogsConfig(configList []interface{}) *guardduty.OrganizationS3LogsConfiguration { + if len(configList) == 0 || configList[0] == nil { + return nil + } + + data := configList[0].(map[string]interface{}) + + autoEnable := data["auto_enable"].(bool) + + s3LogsConfig := &guardduty.OrganizationS3LogsConfiguration{ + AutoEnable: aws.Bool(autoEnable), + } + + return s3LogsConfig +} diff --git a/aws/resource_aws_guardduty_organization_configuration_test.go b/aws/resource_aws_guardduty_organization_configuration_test.go index 5d31055cf7bb..007759e8bab7 100644 --- a/aws/resource_aws_guardduty_organization_configuration_test.go +++ b/aws/resource_aws_guardduty_organization_configuration_test.go @@ -46,6 +46,43 @@ func testAccAwsGuardDutyOrganizationConfiguration_basic(t *testing.T) { }) } +func testAccAwsGuardDutyOrganizationConfiguration_s3logs(t *testing.T) { + detectorResourceName := "aws_guardduty_detector.test" + resourceName := "aws_guardduty_organization_configuration.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccOrganizationsAccountPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsGuardDutyDetectorDestroy, + Steps: []resource.TestStep{ + { + Config: testAccGuardDutyOrganizationConfigurationConfigS3Logs(true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "auto_enable", "true"), + resource.TestCheckResourceAttrPair(resourceName, "detector_id", detectorResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.0.auto_enable", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccGuardDutyOrganizationConfigurationConfigS3Logs(false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "auto_enable", "true"), + resource.TestCheckResourceAttrPair(resourceName, "detector_id", detectorResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "datasources.0.s3_logs.0.auto_enable", "false"), + ), + }, + }, + }) +} + func testAccGuardDutyOrganizationConfigurationConfigAutoEnable(autoEnable bool) string { return fmt.Sprintf(` data "aws_caller_identity" "current" {} @@ -73,3 +110,37 @@ resource "aws_guardduty_organization_configuration" "test" { } `, autoEnable) } + +func testAccGuardDutyOrganizationConfigurationConfigS3Logs(autoEnable bool) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +data "aws_partition" "current" {} + +resource "aws_organizations_organization" "test" { + aws_service_access_principals = ["guardduty.${data.aws_partition.current.dns_suffix}"] + feature_set = "ALL" +} + +resource "aws_guardduty_detector" "test" {} + +resource "aws_guardduty_organization_admin_account" "test" { + depends_on = [aws_organizations_organization.test] + + admin_account_id = data.aws_caller_identity.current.account_id +} + +resource "aws_guardduty_organization_configuration" "test" { + depends_on = [aws_guardduty_organization_admin_account.test] + + auto_enable = true + detector_id = aws_guardduty_detector.test.id + + datasources { + s3_logs { + auto_enable = %[1]t + } + } +} +`, autoEnable) +} diff --git a/aws/resource_aws_guardduty_test.go b/aws/resource_aws_guardduty_test.go index 596655cb7aaf..fe042b6bea75 100644 --- a/aws/resource_aws_guardduty_test.go +++ b/aws/resource_aws_guardduty_test.go @@ -30,7 +30,8 @@ func TestAccAWSGuardDuty_serial(t *testing.T) { "basic": testAccAwsGuardDutyOrganizationAdminAccount_basic, }, "OrganizationConfiguration": { - "basic": testAccAwsGuardDutyOrganizationConfiguration_basic, + "basic": testAccAwsGuardDutyOrganizationConfiguration_basic, + "s3Logs": testAccAwsGuardDutyOrganizationConfiguration_s3logs, }, "ThreatIntelSet": { "basic": testAccAwsGuardDutyThreatintelset_basic, diff --git a/website/docs/r/guardduty_organization_configuration.html.markdown b/website/docs/r/guardduty_organization_configuration.html.markdown index b972f04cddb3..6a44a467b316 100644 --- a/website/docs/r/guardduty_organization_configuration.html.markdown +++ b/website/docs/r/guardduty_organization_configuration.html.markdown @@ -22,6 +22,12 @@ resource "aws_guardduty_detector" "example" { resource "aws_guardduty_organization_configuration" "example" { auto_enable = true detector_id = aws_guardduty_detector.example.id + + datasources { + s3_logs { + auto_enable = true + } + } } ``` @@ -31,6 +37,16 @@ The following arguments are supported: * `auto_enable` - (Required) When this setting is enabled, all new accounts that are created in, or added to, the organization are added as a member accounts of the organization’s GuardDuty delegated administrator and GuardDuty is enabled in that AWS Region. * `detector_id` - (Required) The detector ID of the GuardDuty account. +* `datasources` - (Optional) Configuration for the collected datasources. + +`datasources` supports the following: + +* `s3_logs` - (Optional) Configuration for the builds to store logs to S3. + +`s3_logs` supports the following: + +* `auto_enable` - (Optional) Set to `true` if you want S3 data event logs to be automatically enabled for new members of the organization. Default: `false` + ## Attributes Reference From 95fd5a8bfe0823c4fed7704f5df0dc4b33f39a4e Mon Sep 17 00:00:00 2001 From: Ian Dillon Date: Mon, 21 Sep 2020 09:50:52 -0400 Subject: [PATCH 1071/1208] Correct tabs -> spaces in aws_guardduty_organization_configuration tests. --- ...esource_aws_guardduty_organization_configuration_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/resource_aws_guardduty_organization_configuration_test.go b/aws/resource_aws_guardduty_organization_configuration_test.go index 007759e8bab7..378a041336ea 100644 --- a/aws/resource_aws_guardduty_organization_configuration_test.go +++ b/aws/resource_aws_guardduty_organization_configuration_test.go @@ -137,9 +137,9 @@ resource "aws_guardduty_organization_configuration" "test" { detector_id = aws_guardduty_detector.test.id datasources { - s3_logs { - auto_enable = %[1]t - } + s3_logs { + auto_enable = %[1]t + } } } `, autoEnable) From d6a6983ee94e31f25a5c459be168d6e67b8514b5 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 9 Jul 2021 15:11:36 -0400 Subject: [PATCH 1072/1208] r/aws_guardduty_organization_configuration: More idiomatic expand/flatten functions. --- ...ws_guardduty_organization_configuration.go | 95 ++++++++++--------- 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/aws/resource_aws_guardduty_organization_configuration.go b/aws/resource_aws_guardduty_organization_configuration.go index 7ca8425503fa..d9d8120eb116 100644 --- a/aws/resource_aws_guardduty_organization_configuration.go +++ b/aws/resource_aws_guardduty_organization_configuration.go @@ -26,12 +26,7 @@ func resourceAwsGuardDutyOrganizationConfiguration() *schema.Resource { Type: schema.TypeBool, Required: true, }, - "detector_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.NoZeroValues, - }, + "datasources": { Type: schema.TypeList, Optional: true, @@ -56,6 +51,13 @@ func resourceAwsGuardDutyOrganizationConfiguration() *schema.Resource { }, }, }, + + "detector_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.NoZeroValues, + }, }, } } @@ -66,9 +68,12 @@ func resourceAwsGuardDutyOrganizationConfigurationUpdate(d *schema.ResourceData, detectorID := d.Get("detector_id").(string) input := &guardduty.UpdateOrganizationConfigurationInput{ - AutoEnable: aws.Bool(d.Get("auto_enable").(bool)), - DetectorId: aws.String(detectorID), - DataSources: expandOrganizationDatasourceConfig(d), + AutoEnable: aws.Bool(d.Get("auto_enable").(bool)), + DetectorId: aws.String(detectorID), + } + + if v, ok := d.GetOk("datasources"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DataSources = expandGuardDutyOrganizationDataSourceConfigurations(v.([]interface{})[0].(map[string]interface{})) } _, err := conn.UpdateOrganizationConfiguration(input) @@ -105,69 +110,73 @@ func resourceAwsGuardDutyOrganizationConfigurationRead(d *schema.ResourceData, m return fmt.Errorf("error reading GuardDuty Organization Configuration (%s): empty response", d.Id()) } - if err := d.Set("datasources", flattenOrganizationDatasourceConfig(output.DataSources)); err != nil { - return fmt.Errorf("error setting datasources: %s", err) + d.Set("auto_enable", output.AutoEnable) + + if output.DataSources != nil { + if err := d.Set("datasources", []interface{}{flattenGuardDutyOrganizationDataSourceConfigurationsResult(output.DataSources)}); err != nil { + return fmt.Errorf("error setting datasources: %w", err) + } + } else { + d.Set("datasources", nil) } d.Set("detector_id", d.Id()) - d.Set("auto_enable", output.AutoEnable) return nil } -func flattenOrganizationDatasourceConfig(dsConfig *guardduty.OrganizationDataSourceConfigurationsResult) []interface{} { - if dsConfig == nil { - return []interface{}{} +func expandGuardDutyOrganizationDataSourceConfigurations(tfMap map[string]interface{}) *guardduty.OrganizationDataSourceConfigurations { + if tfMap == nil { + return nil } - values := map[string]interface{}{} + apiObject := &guardduty.OrganizationDataSourceConfigurations{} - if v := dsConfig.S3Logs; v != nil { - values["s3_logs"] = flattenOrganizationS3LogsConfig(v) + if v, ok := tfMap["s3_logs"].([]interface{}); ok && len(v) > 0 { + apiObject.S3Logs = expandGuardDutyOrganizationS3LogsConfiguration(v[0].(map[string]interface{})) } - return []interface{}{values} + return apiObject } -func flattenOrganizationS3LogsConfig(s3LogsConfig *guardduty.OrganizationS3LogsConfigurationResult) []interface{} { - values := map[string]interface{}{} +func expandGuardDutyOrganizationS3LogsConfiguration(tfMap map[string]interface{}) *guardduty.OrganizationS3LogsConfiguration { + if tfMap == nil { + return nil + } + + apiObject := &guardduty.OrganizationS3LogsConfiguration{} - if s3LogsConfig == nil { - values["auto_enable"] = false - } else { - values["auto_enable"] = aws.BoolValue(s3LogsConfig.AutoEnable) + if v, ok := tfMap["auto_enable"].(bool); ok { + apiObject.AutoEnable = aws.Bool(v) } - return []interface{}{values} + return apiObject } -func expandOrganizationDatasourceConfig(d *schema.ResourceData) *guardduty.OrganizationDataSourceConfigurations { - dsConfig := &guardduty.OrganizationDataSourceConfigurations{} +func flattenGuardDutyOrganizationDataSourceConfigurationsResult(apiObject *guardduty.OrganizationDataSourceConfigurationsResult) map[string]interface{} { + if apiObject == nil { + return nil + } - if v, ok := d.GetOk("datasources"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - configList := v.([]interface{}) - data := configList[0].(map[string]interface{}) + tfMap := map[string]interface{}{} - if v, ok := data["s3_logs"]; ok { - dsConfig.S3Logs = expandOrganizationS3LogsConfig(v.([]interface{})) - } + if v := apiObject.S3Logs; v != nil { + tfMap["s3_logs"] = []interface{}{flattenGuardDutyOrganizationS3LogsConfigurationResult(v)} } - return dsConfig + return tfMap } -func expandOrganizationS3LogsConfig(configList []interface{}) *guardduty.OrganizationS3LogsConfiguration { - if len(configList) == 0 || configList[0] == nil { +func flattenGuardDutyOrganizationS3LogsConfigurationResult(apiObject *guardduty.OrganizationS3LogsConfigurationResult) map[string]interface{} { + if apiObject == nil { return nil } - data := configList[0].(map[string]interface{}) - - autoEnable := data["auto_enable"].(bool) + tfMap := map[string]interface{}{} - s3LogsConfig := &guardduty.OrganizationS3LogsConfiguration{ - AutoEnable: aws.Bool(autoEnable), + if v := apiObject.AutoEnable; v != nil { + tfMap["auto_enable"] = aws.BoolValue(v) } - return s3LogsConfig + return tfMap } From d3c3e3877d9b499002e009d0fcfc1764766d4569 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 9 Jul 2021 15:12:19 -0400 Subject: [PATCH 1073/1208] Add CHANGELOG entry. --- .changelog/15241.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/15241.txt diff --git a/.changelog/15241.txt b/.changelog/15241.txt new file mode 100644 index 000000000000..906ce6da03fd --- /dev/null +++ b/.changelog/15241.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_guardduty_organization_configuration: Add `datasources` argument +``` \ No newline at end of file From 8f969a18805a0cad5096863e23465ead683ab5d6 Mon Sep 17 00:00:00 2001 From: Mark Krant Date: Thu, 13 May 2021 23:30:59 -0700 Subject: [PATCH 1074/1208] Add delete marker replication to s3 v2 config Noted by issue 16250. This adds the option to Enable or Disable delete marker replication when working with v2 S3 replication config. Note that the v1 replication config does not support the ability to toggle delete marker replication; it is always on by default. --- .changelog/19323.txt | 3 + aws/resource_aws_s3_bucket.go | 52 +++++++++++++++- aws/resource_aws_s3_bucket_test.go | 85 +++++++++++++++++++++++++- website/docs/r/s3_bucket.html.markdown | 9 +++ 4 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 .changelog/19323.txt diff --git a/.changelog/19323.txt b/.changelog/19323.txt new file mode 100644 index 000000000000..5dac05347264 --- /dev/null +++ b/.changelog/19323.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_s3_bucket: Add the delete_marker_replication option to s3 bucket replication_configuration v2 rules +``` diff --git a/aws/resource_aws_s3_bucket.go b/aws/resource_aws_s3_bucket.go index 47c868260dcd..839a64a46f0c 100644 --- a/aws/resource_aws_s3_bucket.go +++ b/aws/resource_aws_s3_bucket.go @@ -524,6 +524,21 @@ func resourceAwsS3Bucket() *schema.Resource { }, }, }, + "delete_marker_replication": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Optional: true, + Default: s3.DeleteMarkerReplicationStatusDisabled, + }, + }, + }, + }, }, }, }, @@ -2109,14 +2124,19 @@ func resourceAwsS3BucketReplicationConfigurationUpdate(s3conn *s3.S3, d *schema. } else { rcRule.Filter.Prefix = aws.String(filter["prefix"].(string)) } - rcRule.DeleteMarkerReplication = &s3.DeleteMarkerReplication{ - Status: aws.String(s3.DeleteMarkerReplicationStatusDisabled), - } + } else { // XML schema V1. rcRule.Prefix = aws.String(rr["prefix"].(string)) } + if d, ok := rr["delete_marker_replication"].([]interface{}); ok && len(d) > 0 && d[0] != nil { + dmr := d[0].(map[string]interface{}) + rcRule.DeleteMarkerReplication = &s3.DeleteMarkerReplication{ + Status: aws.String(dmr["status"].(string)), + } + } + rules = append(rules, rcRule) } @@ -2409,6 +2429,14 @@ func flattenAwsS3BucketReplicationConfiguration(r *s3.ReplicationConfiguration) t["filter"] = []interface{}{m} } + if dmr := v.DeleteMarkerReplication; dmr != nil { + m := map[string]interface{}{} + if dmr.Status != nil { + m["status"] = aws.StringValue(v.DeleteMarkerReplication.Status) + } + t["delete_marker_replication"] = []interface{}{m} + } + rules = append(rules, t) } m["rules"] = schema.NewSet(rulesHash, rules) @@ -2574,6 +2602,9 @@ func rulesHash(v interface{}) int { if v, ok := m["priority"]; ok { buf.WriteString(fmt.Sprintf("%d-", v.(int))) } + if v, ok := m["delete_marker_replication"].([]interface{}); ok && len(v) > 0 && v[0] != nil { + buf.WriteString(fmt.Sprintf("%d-", deleteMarkerReplicationHash(v[0]))) + } if v, ok := m["filter"].([]interface{}); ok && len(v) > 0 && v[0] != nil { buf.WriteString(fmt.Sprintf("%d-", replicationRuleFilterHash(v[0]))) } @@ -2597,6 +2628,21 @@ func replicationRuleFilterHash(v interface{}) int { return hashcode.String(buf.String()) } +func deleteMarkerReplicationHash(v interface{}) int { + var buf bytes.Buffer + m, ok := v.(map[string]interface{}) + + if !ok { + return 0 + } + + if v, ok := m["status"]; ok { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + + return hashcode.String(buf.String()) +} + func destinationHash(v interface{}) int { var buf bytes.Buffer m, ok := v.(map[string]interface{}) diff --git a/aws/resource_aws_s3_bucket_test.go b/aws/resource_aws_s3_bucket_test.go index a7e1a196f38f..cf31272e75f6 100644 --- a/aws/resource_aws_s3_bucket_test.go +++ b/aws/resource_aws_s3_bucket_test.go @@ -2100,7 +2100,7 @@ func TestAccAWSS3Bucket_ReplicationSchemaV2(t *testing.T) { CheckDestroy: testAccCheckWithProviders(testAccCheckAWSS3BucketDestroyWithProvider, &providers), Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketConfigReplicationWithV2ConfigurationNoTags(rInt), + Config: testAccAWSS3BucketConfigReplicationWithV2ConfigurationDeleteMarkerReplicationDisabled(rInt), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketExistsWithProvider(resourceName, testAccAwsRegionProviderFunc(region, &providers)), resource.TestCheckResourceAttr(resourceName, "replication_configuration.#", "1"), @@ -2129,6 +2129,36 @@ func TestAccAWSS3Bucket_ReplicationSchemaV2(t *testing.T) { ), ), }, + { + Config: testAccAWSS3BucketConfigReplicationWithV2ConfigurationNoTags(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSS3BucketExistsWithProvider(resourceName, testAccAwsRegionProviderFunc(region, &providers)), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "replication_configuration.0.role", iamRoleResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "replication_configuration.0.rules.#", "1"), + testAccCheckAWSS3BucketExistsWithProvider("aws_s3_bucket.destination", testAccAwsRegionProviderFunc(alternateRegion, &providers)), + testAccCheckAWSS3BucketReplicationRules( + resourceName, + []*s3.ReplicationRule{ + { + ID: aws.String("foobar"), + Destination: &s3.Destination{ + Bucket: aws.String(fmt.Sprintf("arn:%s:s3:::tf-test-bucket-destination-%d", partition, rInt)), + StorageClass: aws.String(s3.ObjectStorageClassStandard), + }, + Status: aws.String(s3.ReplicationRuleStatusEnabled), + Filter: &s3.ReplicationRuleFilter{ + Prefix: aws.String("foo"), + }, + Priority: aws.Int64(0), + DeleteMarkerReplication: &s3.DeleteMarkerReplication{ + Status: aws.String(s3.DeleteMarkerReplicationStatusEnabled), + }, + }, + }, + ), + ), + }, { Config: testAccAWSS3BucketConfigReplicationWithV2ConfigurationNoTags(rInt), ResourceName: resourceName, @@ -4544,6 +4574,10 @@ resource "aws_s3_bucket" "bucket" { prefix = "testprefix" } + delete_marker_replication { + status = "Enabled" + } + destination { bucket = aws_s3_bucket.destination.arn storage_class = "STANDARD" @@ -4562,6 +4596,39 @@ resource "aws_s3_bucket" "destination" { `, rName, rNameDestination)) } +func testAccAWSS3BucketConfigReplicationWithV2ConfigurationDeleteMarkerReplicationDisabled(randInt int) string { + return testAccAWSS3BucketConfigReplicationBasic(randInt) + fmt.Sprintf(` +resource "aws_s3_bucket" "bucket" { + bucket = "tf-test-bucket-%[1]d" + acl = "private" + + versioning { + enabled = true + } + + replication_configuration { + role = aws_iam_role.role.arn + + rules { + id = "foobar" + status = "Enabled" + + filter { + prefix = "foo" + } + + delete_marker_replication {} + + destination { + bucket = aws_s3_bucket.destination.arn + storage_class = "STANDARD" + } + } + } +} +`, randInt) +} + func testAccAWSS3BucketConfigReplicationWithV2ConfigurationNoTags(randInt int) string { return testAccAWSS3BucketConfigReplicationBasic(randInt) + fmt.Sprintf(` resource "aws_s3_bucket" "bucket" { @@ -4583,6 +4650,10 @@ resource "aws_s3_bucket" "bucket" { prefix = "foo" } + delete_marker_replication { + status = "Enabled" + } + destination { bucket = aws_s3_bucket.destination.arn storage_class = "STANDARD" @@ -4618,6 +4689,10 @@ resource "aws_s3_bucket" "bucket" { } } + delete_marker_replication { + status = "Disabled" + } + destination { bucket = aws_s3_bucket.destination.arn storage_class = "STANDARD" @@ -4656,6 +4731,10 @@ resource "aws_s3_bucket" "bucket" { } } + delete_marker_replication { + status = "Disabled" + } + destination { bucket = aws_s3_bucket.destination.arn storage_class = "STANDARD" @@ -4691,6 +4770,10 @@ resource "aws_s3_bucket" "bucket" { } } + delete_marker_replication { + status = "Disabled" + } + destination { bucket = aws_s3_bucket.destination.arn storage_class = "STANDARD" diff --git a/website/docs/r/s3_bucket.html.markdown b/website/docs/r/s3_bucket.html.markdown index 3f15a9360857..cf54e1f364c5 100644 --- a/website/docs/r/s3_bucket.html.markdown +++ b/website/docs/r/s3_bucket.html.markdown @@ -436,6 +436,7 @@ The `rules` object supports the following: * `prefix` - (Optional) Object keyname prefix identifying one or more objects to which the rule applies. Must be less than or equal to 1024 characters in length. * `status` - (Required) The status of the rule. Either `Enabled` or `Disabled`. The rule is ignored if status is not Enabled. * `filter` - (Optional) Filter that identifies subset of objects to which the replication rule applies (documented below). +* `delete_marker_replication` - (Optional) Specifies whether delete markers are replicated (documented below). ~> **NOTE on `prefix` and `filter`:** Amazon S3's latest version of the replication configuration is V2, which includes the `filter` attribute for replication rules. With the `filter` attribute, you can specify object filters based on the object key prefix, tags, or both to scope the objects that the rule applies to. @@ -444,6 +445,10 @@ Replication configuration V1 supports filtering based on only the `prefix` attri * For a specific rule, `prefix` conflicts with `filter` * If any rule has `filter` specified then they all must * `priority` is optional (with a default value of `0`) but must be unique between multiple rules +* If a rule has `filter` then it **must** have a `delete_marker_replication` object +* If a rule has `prefix` then it **must not** have a `delete_marker_replication` object + +~> **NOTE:** Delete markers are always replicated when using `prefix` in a rule and is not configurable. The default behavior when using `filter` can be achieved by providing an empty configuration block `delete_marker_replication {}`. ~> **NOTE:** Replication to multiple destination buckets requires that `priority` is specified in the `rules` object. If the corresponding rule requires no filter, an empty configuration block `filter {}` must be specified. @@ -471,6 +476,10 @@ The `filter` object supports the following: * `tags` - (Optional) A map of tags that identifies subset of objects to which the rule applies. The rule applies only to objects having all the tags in its tagset. +The `delete_marker_replication` object supports the following: + +* `status` - (Optional) The delete marker replication status. Either `Enabled` or `Disabled`. Default `Disabled`. If `tags` is set in the `filter` object, then `status` must be set to `Disabled`. + The `server_side_encryption_configuration` object supports the following: * `rule` - (required) A single object for server-side encryption by default configuration. (documented below) From 40ed3a3322f5bfb1632d8e9cda2f0e82146d10a3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 9 Jul 2021 16:38:14 -0400 Subject: [PATCH 1075/1208] Fix awsproviderlint 'XAT001: missing ErrorCheck'. --- aws/resource_aws_guardduty_organization_configuration_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_guardduty_organization_configuration_test.go b/aws/resource_aws_guardduty_organization_configuration_test.go index 378a041336ea..8bd7ec2bd310 100644 --- a/aws/resource_aws_guardduty_organization_configuration_test.go +++ b/aws/resource_aws_guardduty_organization_configuration_test.go @@ -55,6 +55,7 @@ func testAccAwsGuardDutyOrganizationConfiguration_s3logs(t *testing.T) { testAccPreCheck(t) testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, guardduty.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAwsGuardDutyDetectorDestroy, Steps: []resource.TestStep{ From 1d2717fd1fe2855a4d790fb87bdca181efc6dfac Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 29 Jun 2021 16:58:48 -0700 Subject: [PATCH 1076/1208] Removes hardcoded "terraformtesting.com" domain name from acceptance tests --- ...e_aws_acmpca_certificate_authority_test.go | 29 +- aws/provider_test.go | 4 + aws/resource_aws_acm_certificate_test.go | 16 +- ...e_aws_acmpca_certificate_authority_test.go | 155 ++++--- aws/resource_aws_cognito_user_pool_test.go | 2 +- aws/resource_aws_db_instance_test.go | 436 +++++------------- aws/resource_aws_msk_cluster_test.go | 10 +- aws/resource_aws_ses_domain_dkim_test.go | 7 +- aws/resource_aws_ses_domain_identity_test.go | 13 +- ...s_ses_domain_identity_verification_test.go | 8 +- aws/resource_aws_ses_domain_mail_from_test.go | 28 +- aws/resource_aws_ses_email_identity_test.go | 13 +- ...ws_ses_identity_notification_topic_test.go | 6 +- aws/resource_aws_ses_identity_policy_test.go | 13 +- ...esource_aws_storagegateway_gateway_test.go | 52 ++- ..._aws_storagegateway_smb_file_share_test.go | 78 ++-- aws/test-fixtures/public-ssh-key.pub | 2 +- 17 files changed, 356 insertions(+), 516 deletions(-) diff --git a/aws/data_source_aws_acmpca_certificate_authority_test.go b/aws/data_source_aws_acmpca_certificate_authority_test.go index 8cf446889fc8..63fbba105583 100644 --- a/aws/data_source_aws_acmpca_certificate_authority_test.go +++ b/aws/data_source_aws_acmpca_certificate_authority_test.go @@ -1,6 +1,7 @@ package aws import ( + "fmt" "regexp" "testing" @@ -12,6 +13,8 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_basic(t *testing.T) { resourceName := "aws_acmpca_certificate_authority.test" datasourceName := "data.aws_acmpca_certificate_authority.test" + domainName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), @@ -22,7 +25,7 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_basic(t *testing.T) { ExpectError: regexp.MustCompile(`(AccessDeniedException|ResourceNotFoundException)`), }, { - Config: testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_ARN, + Config: testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_ARN(domainName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(datasourceName, "certificate", resourceName, "certificate"), @@ -47,6 +50,8 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_S3ObjectAcl(t *testing.T) { resourceName := "aws_acmpca_certificate_authority.test" datasourceName := "data.aws_acmpca_certificate_authority.test" + domainName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), @@ -57,7 +62,7 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_S3ObjectAcl(t *testing.T) { ExpectError: regexp.MustCompile(`(AccessDeniedException|ResourceNotFoundException)`), }, { - Config: testAccDataSourceAwsAcmpcaCertificateAuthorityConfigS3ObjectAcl_ARN, + Config: testAccDataSourceAwsAcmpcaCertificateAuthorityConfigS3ObjectAcl_ARN(domainName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(datasourceName, "certificate", resourceName, "certificate"), @@ -82,7 +87,8 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_S3ObjectAcl(t *testing.T) { }) } -const testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_ARN = ` +func testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_ARN(domainName string) string { + return fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "wrong" { permanent_deletion_time_in_days = 7 @@ -91,7 +97,7 @@ resource "aws_acmpca_certificate_authority" "wrong" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } } @@ -104,7 +110,7 @@ resource "aws_acmpca_certificate_authority" "test" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } } @@ -112,9 +118,11 @@ resource "aws_acmpca_certificate_authority" "test" { data "aws_acmpca_certificate_authority" "test" { arn = aws_acmpca_certificate_authority.test.arn } -` +`, domainName) +} -const testAccDataSourceAwsAcmpcaCertificateAuthorityConfigS3ObjectAcl_ARN = ` +func testAccDataSourceAwsAcmpcaCertificateAuthorityConfigS3ObjectAcl_ARN(domainName string) string { + return fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "wrong" { permanent_deletion_time_in_days = 7 @@ -123,7 +131,7 @@ resource "aws_acmpca_certificate_authority" "wrong" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } } @@ -136,7 +144,7 @@ resource "aws_acmpca_certificate_authority" "test" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } } @@ -144,7 +152,8 @@ resource "aws_acmpca_certificate_authority" "test" { data "aws_acmpca_certificate_authority" "test" { arn = aws_acmpca_certificate_authority.test.arn } -` +`, domainName) +} //lintignore:AWSAT003,AWSAT005 const testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_NonExistent = ` diff --git a/aws/provider_test.go b/aws/provider_test.go index c7ac625ea757..f96c68c60feb 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -2327,6 +2327,10 @@ func (d domainName) FQDN() domainName { return domainName(fmt.Sprintf("%s.", d)) } +func (d domainName) String() string { + return string(d) +} + func testAccRandomDomain() domainName { return domainNameTestTopLevelDomain.RandomSubdomain() } diff --git a/aws/resource_aws_acm_certificate_test.go b/aws/resource_aws_acm_certificate_test.go index bed7258619ad..d8858dfdc910 100644 --- a/aws/resource_aws_acm_certificate_test.go +++ b/aws/resource_aws_acm_certificate_test.go @@ -222,7 +222,9 @@ func TestAccAWSAcmCertificate_root(t *testing.T) { func TestAccAWSAcmCertificate_privateCert(t *testing.T) { certificateAuthorityResourceName := "aws_acmpca_certificate_authority.test" resourceName := "aws_acm_certificate.cert" - rName := acctest.RandomWithPrefix("tf-acc-test") + + commonName := testAccRandomDomain() + certificateDomainName := commonName.RandomSubdomain().String() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -231,10 +233,10 @@ func TestAccAWSAcmCertificate_privateCert(t *testing.T) { CheckDestroy: testAccCheckAcmCertificateDestroy, Steps: []resource.TestStep{ { - Config: testAccAcmCertificateConfig_privateCert(rName), + Config: testAccAcmCertificateConfig_privateCert(commonName.String(), certificateDomainName), Check: resource.ComposeTestCheckFunc( testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile("certificate/.+$")), - resource.TestCheckResourceAttr(resourceName, "domain_name", fmt.Sprintf("%s.terraformtesting.com", rName)), + resource.TestCheckResourceAttr(resourceName, "domain_name", certificateDomainName), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "0"), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusFailed), // FailureReason: PCA_INVALID_STATE (PCA State: PENDING_CERTIFICATE) resource.TestCheckResourceAttr(resourceName, "subject_alternative_names.#", "0"), @@ -751,7 +753,7 @@ resource "aws_acm_certificate" "cert" { } -func testAccAcmCertificateConfig_privateCert(rName string) string { +func testAccAcmCertificateConfig_privateCert(commonName, certificateDomainName string) string { return fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { permanent_deletion_time_in_days = 7 @@ -762,16 +764,16 @@ resource "aws_acmpca_certificate_authority" "test" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } } resource "aws_acm_certificate" "cert" { - domain_name = "%s.terraformtesting.com" + domain_name = %[2]q certificate_authority_arn = aws_acmpca_certificate_authority.test.arn } -`, rName) +`, commonName, certificateDomainName) } func testAccAcmCertificateConfig_subjectAlternativeNames(domainName, subjectAlternativeNames, validationMethod string) string { diff --git a/aws/resource_aws_acmpca_certificate_authority_test.go b/aws/resource_aws_acmpca_certificate_authority_test.go index 274be1562785..3b001fc17950 100644 --- a/aws/resource_aws_acmpca_certificate_authority_test.go +++ b/aws/resource_aws_acmpca_certificate_authority_test.go @@ -86,6 +86,8 @@ func TestAccAwsAcmpcaCertificateAuthority_basic(t *testing.T) { var certificateAuthority acmpca.CertificateAuthority resourceName := "aws_acmpca_certificate_authority.test" + commonName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), @@ -93,7 +95,7 @@ func TestAccAwsAcmpcaCertificateAuthority_basic(t *testing.T) { CheckDestroy: testAccCheckAwsAcmpcaCertificateAuthorityDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required, + Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required(commonName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm-pca", regexp.MustCompile(`certificate-authority/.+`)), @@ -101,7 +103,7 @@ func TestAccAwsAcmpcaCertificateAuthority_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "certificate_authority_configuration.0.key_algorithm", "RSA_4096"), resource.TestCheckResourceAttr(resourceName, "certificate_authority_configuration.0.signing_algorithm", "SHA512WITHRSA"), resource.TestCheckResourceAttr(resourceName, "certificate_authority_configuration.0.subject.#", "1"), - resource.TestCheckResourceAttr(resourceName, "certificate_authority_configuration.0.subject.0.common_name", "terraformtesting.com"), + resource.TestCheckResourceAttr(resourceName, "certificate_authority_configuration.0.subject.0.common_name", commonName), resource.TestCheckResourceAttr(resourceName, "certificate", ""), resource.TestCheckResourceAttr(resourceName, "certificate_chain", ""), resource.TestCheckResourceAttrSet(resourceName, "certificate_signing_request"), @@ -131,6 +133,8 @@ func TestAccAwsAcmpcaCertificateAuthority_disappears(t *testing.T) { var certificateAuthority acmpca.CertificateAuthority resourceName := "aws_acmpca_certificate_authority.test" + commonName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), @@ -138,7 +142,7 @@ func TestAccAwsAcmpcaCertificateAuthority_disappears(t *testing.T) { CheckDestroy: testAccCheckAwsAcmpcaCertificateAuthorityDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required, + Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required(commonName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), testAccCheckResourceDisappears(testAccProvider, resourceAwsAcmpcaCertificateAuthority(), resourceName), @@ -230,6 +234,11 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_acmpca_certificate_authority.test" + domain := testAccRandomDomain() + commonName := domain.String() + customCName := domain.Subdomain("crl").String() + customCName2 := domain.Subdomain("crl2").String() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), @@ -238,12 +247,12 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati Steps: []resource.TestStep{ // Test creating revocation configuration on resource creation { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_CustomCname(rName, "crl.terraformtesting.com"), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_CustomCname(rName, commonName, customCName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.custom_cname", "crl.terraformtesting.com"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.custom_cname", customCName), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.enabled", "true"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.expiration_in_days", "1"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.s3_bucket_name", rName), @@ -260,12 +269,12 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }, // Test updating revocation configuration { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_CustomCname(rName, "crl2.terraformtesting.com"), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_CustomCname(rName, commonName, customCName2), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.custom_cname", "crl2.terraformtesting.com"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.custom_cname", customCName2), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.enabled", "true"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.expiration_in_days", "1"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.s3_bucket_name", rName), @@ -273,7 +282,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }, // Test removing custom cname on resource update { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_Enabled(rName, true), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_Enabled(rName, commonName, true), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -286,12 +295,12 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }, // Test adding custom cname on resource update { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_CustomCname(rName, "crl.terraformtesting.com"), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_CustomCname(rName, commonName, customCName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.custom_cname", "crl.terraformtesting.com"), + resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.custom_cname", customCName), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.enabled", "true"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.expiration_in_days", "1"), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.0.crl_configuration.0.s3_bucket_name", rName), @@ -299,7 +308,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }, // Test removing revocation configuration on resource update { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required, + Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required(commonName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -316,6 +325,8 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_acmpca_certificate_authority.test" + commonName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), @@ -324,7 +335,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati Steps: []resource.TestStep{ // Test creating revocation configuration on resource creation { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_Enabled(rName, true), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_Enabled(rName, commonName, true), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -346,7 +357,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }, // Test disabling revocation configuration { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_Enabled(rName, false), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_Enabled(rName, commonName, false), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -356,7 +367,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }, // Test enabling revocation configuration { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_Enabled(rName, true), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_Enabled(rName, commonName, true), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -369,7 +380,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }, // Test removing revocation configuration on resource update { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required, + Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required(commonName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -386,6 +397,8 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_acmpca_certificate_authority.test" + commonName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), @@ -394,7 +407,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati Steps: []resource.TestStep{ // Test creating revocation configuration on resource creation { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_ExpirationInDays(rName, 1), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_ExpirationInDays(rName, commonName, 1), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -417,7 +430,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }, // Test updating revocation configuration { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_ExpirationInDays(rName, 2), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_ExpirationInDays(rName, commonName, 2), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -429,7 +442,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }, // Test removing revocation configuration on resource update { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required, + Config: testAccAwsAcmpcaCertificateAuthorityConfig_Required(commonName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -446,6 +459,8 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_acmpca_certificate_authority.test" + commonName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), @@ -454,7 +469,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati Steps: []resource.TestStep{ // Test creating revocation configuration on resource creation { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_s3ObjectAcl(rName, "BUCKET_OWNER_FULL_CONTROL"), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_s3ObjectAcl(rName, commonName, "BUCKET_OWNER_FULL_CONTROL"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -476,7 +491,7 @@ func TestAccAwsAcmpcaCertificateAuthority_RevocationConfiguration_CrlConfigurati }, // Test updating revocation configuration { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_s3ObjectAcl(rName, "PUBLIC_READ"), + Config: testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_s3ObjectAcl(rName, commonName, "PUBLIC_READ"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "revocation_configuration.#", "1"), @@ -495,6 +510,8 @@ func TestAccAwsAcmpcaCertificateAuthority_Tags(t *testing.T) { var certificateAuthority acmpca.CertificateAuthority resourceName := "aws_acmpca_certificate_authority.test" + commonName := testAccRandomDomainName() + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, acmpca.EndpointsID), @@ -502,7 +519,7 @@ func TestAccAwsAcmpcaCertificateAuthority_Tags(t *testing.T) { CheckDestroy: testAccCheckAwsAcmpcaCertificateAuthorityDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_Tags_Single, + Config: testAccAwsAcmpcaCertificateAuthorityConfig_Tags_Single(commonName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), @@ -510,7 +527,7 @@ func TestAccAwsAcmpcaCertificateAuthority_Tags(t *testing.T) { ), }, { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_Tags_SingleUpdated, + Config: testAccAwsAcmpcaCertificateAuthorityConfig_Tags_SingleUpdated(commonName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), @@ -518,7 +535,7 @@ func TestAccAwsAcmpcaCertificateAuthority_Tags(t *testing.T) { ), }, { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_Tags_Multiple, + Config: testAccAwsAcmpcaCertificateAuthorityConfig_Tags_Multiple(commonName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), @@ -527,7 +544,7 @@ func TestAccAwsAcmpcaCertificateAuthority_Tags(t *testing.T) { ), }, { - Config: testAccAwsAcmpcaCertificateAuthorityConfig_Tags_Single, + Config: testAccAwsAcmpcaCertificateAuthorityConfig_Tags_Single(commonName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAcmpcaCertificateAuthorityExists(resourceName, &certificateAuthority), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), @@ -751,23 +768,25 @@ data "aws_partition" "current" {} `, rName) } -const testAccAwsAcmpcaCertificateAuthorityConfig_Required = ` +func testAccAwsAcmpcaCertificateAuthorityConfig_Required(commonName string) string { + return fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { certificate_authority_configuration { key_algorithm = "RSA_4096" signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } } -` - -func testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_CustomCname(rName, customCname string) string { - return fmt.Sprintf(` -%s +`, commonName) +} +func testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_CustomCname(rName, commonName, customCname string) string { + return composeConfig( + testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName), + fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { permanent_deletion_time_in_days = 7 @@ -776,13 +795,13 @@ resource "aws_acmpca_certificate_authority" "test" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } revocation_configuration { crl_configuration { - custom_cname = "%s" + custom_cname = %[2]q enabled = true expiration_in_days = 1 s3_bucket_name = aws_s3_bucket.test.id @@ -791,13 +810,13 @@ resource "aws_acmpca_certificate_authority" "test" { depends_on = [aws_s3_bucket_policy.test] } -`, testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName), customCname) +`, commonName, customCname)) } -func testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_Enabled(rName string, enabled bool) string { - return fmt.Sprintf(` -%s - +func testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_Enabled(rName, commonName string, enabled bool) string { + return composeConfig( + testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName), + fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { permanent_deletion_time_in_days = 7 @@ -806,25 +825,25 @@ resource "aws_acmpca_certificate_authority" "test" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } revocation_configuration { crl_configuration { - enabled = %t + enabled = %[2]t expiration_in_days = 1 s3_bucket_name = aws_s3_bucket.test.id } } } -`, testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName), enabled) +`, commonName, enabled)) } -func testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_ExpirationInDays(rName string, expirationInDays int) string { - return fmt.Sprintf(` -%s - +func testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_ExpirationInDays(rName, commonName string, expirationInDays int) string { + return composeConfig( + testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName), + fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { permanent_deletion_time_in_days = 7 @@ -833,25 +852,25 @@ resource "aws_acmpca_certificate_authority" "test" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } revocation_configuration { crl_configuration { enabled = true - expiration_in_days = %d + expiration_in_days = %[2]d s3_bucket_name = aws_s3_bucket.test.id } } } -`, testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName), expirationInDays) +`, commonName, expirationInDays)) } -func testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_s3ObjectAcl(rName, s3ObjectAcl string) string { - return fmt.Sprintf(` -%s - +func testAccAwsAcmpcaCertificateAuthorityConfig_RevocationConfiguration_CrlConfiguration_s3ObjectAcl(rName, commonName, s3ObjectAcl string) string { + return composeConfig( + testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName), + fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { permanent_deletion_time_in_days = 7 @@ -860,7 +879,7 @@ resource "aws_acmpca_certificate_authority" "test" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } @@ -869,19 +888,19 @@ resource "aws_acmpca_certificate_authority" "test" { enabled = true expiration_in_days = 1 s3_bucket_name = aws_s3_bucket.test.id - s3_object_acl = "%s" + s3_object_acl = %[2]q } } depends_on = [aws_s3_bucket_policy.test] } -`, testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName), s3ObjectAcl) +`, commonName, s3ObjectAcl)) } func testAccAwsAcmpcaCertificateAuthorityConfig_S3Bucket(rName string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { - bucket = "%s" + bucket = %[1]q force_destroy = true } @@ -913,7 +932,8 @@ resource "aws_s3_bucket_policy" "test" { `, rName) } -const testAccAwsAcmpcaCertificateAuthorityConfig_Tags_Single = ` +func testAccAwsAcmpcaCertificateAuthorityConfig_Tags_Single(commonName string) string { + return fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { permanent_deletion_time_in_days = 7 @@ -922,7 +942,7 @@ resource "aws_acmpca_certificate_authority" "test" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } @@ -930,9 +950,11 @@ resource "aws_acmpca_certificate_authority" "test" { tag1 = "tag1value" } } -` +`, commonName) +} -const testAccAwsAcmpcaCertificateAuthorityConfig_Tags_SingleUpdated = ` +func testAccAwsAcmpcaCertificateAuthorityConfig_Tags_SingleUpdated(commonName string) string { + return fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { permanent_deletion_time_in_days = 7 @@ -941,7 +963,7 @@ resource "aws_acmpca_certificate_authority" "test" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } @@ -949,9 +971,11 @@ resource "aws_acmpca_certificate_authority" "test" { tag1 = "tag1value-updated" } } -` +`, commonName) +} -const testAccAwsAcmpcaCertificateAuthorityConfig_Tags_Multiple = ` +func testAccAwsAcmpcaCertificateAuthorityConfig_Tags_Multiple(commonName string) string { + return fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { permanent_deletion_time_in_days = 7 @@ -960,7 +984,7 @@ resource "aws_acmpca_certificate_authority" "test" { signing_algorithm = "SHA512WITHRSA" subject { - common_name = "terraformtesting.com" + common_name = %[1]q } } @@ -969,4 +993,5 @@ resource "aws_acmpca_certificate_authority" "test" { tag2 = "tag2value" } } -` +`, commonName) +} diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index 126e59e74795..c872796f5dbc 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -790,7 +790,7 @@ func TestAccAWSCognitoUserPool_withEmailConfiguration(t *testing.T) { func TestAccAWSCognitoUserPool_withEmailConfigurationSource(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") - replyTo := fmt.Sprintf("tf-acc-reply-%s@terraformtesting.com", rName) + replyTo := "no-reply@hashicorp.com" resourceName := "aws_cognito_user_pool.test" resourceName2 := "aws_ses_configuration_set.test" diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 22130346aeb7..b3dd3290ef26 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -2217,7 +2217,11 @@ func TestAccAWSDBInstance_MSSQL_TZ(t *testing.T) { func TestAccAWSDBInstance_MSSQL_Domain(t *testing.T) { var vBefore, vAfter rds.DBInstance - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") + + domain := testAccRandomDomain() + directory1 := domain.RandomSubdomain().String() + directory2 := domain.RandomSubdomain().String() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -2226,25 +2230,21 @@ func TestAccAWSDBInstance_MSSQL_Domain(t *testing.T) { CheckDestroy: testAccCheckAWSDBInstanceDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSDBInstanceConfig_MSSQLDomain(rInt), + Config: testAccAWSDBInstanceConfig_MSSQLDomain(rName, directory1, directory2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSDBInstanceExists("aws_db_instance.mssql", &vBefore), - testAccCheckAWSDBInstanceDomainAttributes("terraformtesting.com", &vBefore), - resource.TestCheckResourceAttrSet( - "aws_db_instance.mssql", "domain"), - resource.TestCheckResourceAttrSet( - "aws_db_instance.mssql", "domain_iam_role_name"), + testAccCheckAWSDBInstanceDomainAttributes(directory1, &vBefore), + resource.TestCheckResourceAttrSet("aws_db_instance.mssql", "domain"), + resource.TestCheckResourceAttrSet("aws_db_instance.mssql", "domain_iam_role_name"), ), }, { - Config: testAccAWSDBInstanceConfig_MSSQLUpdateDomain(rInt), + Config: testAccAWSDBInstanceConfig_MSSQLUpdateDomain(rName, directory1, directory2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSDBInstanceExists("aws_db_instance.mssql", &vAfter), - testAccCheckAWSDBInstanceDomainAttributes("corp.notexample.com", &vAfter), - resource.TestCheckResourceAttrSet( - "aws_db_instance.mssql", "domain"), - resource.TestCheckResourceAttrSet( - "aws_db_instance.mssql", "domain_iam_role_name"), + testAccCheckAWSDBInstanceDomainAttributes(directory2, &vAfter), + resource.TestCheckResourceAttrSet("aws_db_instance.mssql", "domain"), + resource.TestCheckResourceAttrSet("aws_db_instance.mssql", "domain_iam_role_name"), ), }, }, @@ -2253,7 +2253,9 @@ func TestAccAWSDBInstance_MSSQL_Domain(t *testing.T) { func TestAccAWSDBInstance_MSSQL_DomainSnapshotRestore(t *testing.T) { var v, vRestoredInstance rds.DBInstance - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") + + domain := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -2262,15 +2264,13 @@ func TestAccAWSDBInstance_MSSQL_DomainSnapshotRestore(t *testing.T) { CheckDestroy: testAccCheckAWSDBInstanceDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSDBInstanceConfig_MSSQLDomainSnapshotRestore(rInt), + Config: testAccAWSDBInstanceConfig_MSSQLDomainSnapshotRestore(rName, domain), Check: resource.ComposeTestCheckFunc( testAccCheckAWSDBInstanceExists("aws_db_instance.mssql_restore", &vRestoredInstance), testAccCheckAWSDBInstanceExists("aws_db_instance.mssql", &v), - testAccCheckAWSDBInstanceDomainAttributes("terraformtesting.com", &vRestoredInstance), - resource.TestCheckResourceAttrSet( - "aws_db_instance.mssql_restore", "domain"), - resource.TestCheckResourceAttrSet( - "aws_db_instance.mssql_restore", "domain_iam_role_name"), + testAccCheckAWSDBInstanceDomainAttributes(domain, &vRestoredInstance), + resource.TestCheckResourceAttrSet("aws_db_instance.mssql_restore", "domain"), + resource.TestCheckResourceAttrSet("aws_db_instance.mssql_restore", "domain_iam_role_name"), ), }, }, @@ -4240,307 +4240,175 @@ resource "aws_security_group_rule" "rds-mssql-1" { `, rInt)) } -func testAccAWSDBInstanceConfig_MSSQLDomain(rInt int) string { - return composeConfig( - testAccAWSDBInstanceConfig_orderableClassSQLServerEx(), - testAccAvailableAZsNoOptInConfig(), - fmt.Sprintf(` -resource "aws_vpc" "foo" { - cidr_block = "10.1.0.0/16" - enable_dns_hostnames = true +func testAccAWSDBInstanceConfig_RDSServiceRole(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "role" { + name = %[1]q - tags = { - Name = "terraform-testacc-db-instance-mssql-domain" - } + assume_role_policy = < Date: Tue, 29 Jun 2021 17:35:38 -0700 Subject: [PATCH 1077/1208] Adds constant for default email address --- aws/provider_test.go | 4 ++++ aws/resource_aws_cognito_user_pool_test.go | 2 +- aws/resource_aws_ses_email_identity_test.go | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/aws/provider_test.go b/aws/provider_test.go index f96c68c60feb..0a817b8dbcf1 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -2334,3 +2334,7 @@ func (d domainName) String() string { func testAccRandomDomain() domainName { return domainNameTestTopLevelDomain.RandomSubdomain() } + +// testAccDefaultEmailAddress is the default email address to set as a +// resource or data source parameter for acceptance tests. +const testAccDefaultEmailAddress = "no-reply@hashicorp.com" diff --git a/aws/resource_aws_cognito_user_pool_test.go b/aws/resource_aws_cognito_user_pool_test.go index c872796f5dbc..aa2b256187e7 100644 --- a/aws/resource_aws_cognito_user_pool_test.go +++ b/aws/resource_aws_cognito_user_pool_test.go @@ -790,7 +790,7 @@ func TestAccAWSCognitoUserPool_withEmailConfiguration(t *testing.T) { func TestAccAWSCognitoUserPool_withEmailConfigurationSource(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") - replyTo := "no-reply@hashicorp.com" + replyTo := testAccDefaultEmailAddress resourceName := "aws_cognito_user_pool.test" resourceName2 := "aws_ses_configuration_set.test" diff --git a/aws/resource_aws_ses_email_identity_test.go b/aws/resource_aws_ses_email_identity_test.go index 8e2ce53c759d..50af0d577720 100644 --- a/aws/resource_aws_ses_email_identity_test.go +++ b/aws/resource_aws_ses_email_identity_test.go @@ -20,7 +20,7 @@ func init() { } func TestAccAWSSESEmailIdentity_basic(t *testing.T) { - email := "no-reply@hashicorp.com" + email := testAccDefaultEmailAddress resourceName := "aws_ses_email_identity.test" resource.ParallelTest(t, resource.TestCase{ @@ -46,7 +46,7 @@ func TestAccAWSSESEmailIdentity_basic(t *testing.T) { } func TestAccAWSSESEmailIdentity_trailingPeriod(t *testing.T) { - email := "no-reply@hashicorp.com" + email := testAccDefaultEmailAddress resourceName := "aws_ses_email_identity.test" resource.ParallelTest(t, resource.TestCase{ From 39e916d147b9e4057169f9607079ef8706fcbbe5 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 29 Jun 2021 17:35:49 -0700 Subject: [PATCH 1078/1208] Naming clean up --- ...urce_aws_acmpca_certificate_authority_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aws/data_source_aws_acmpca_certificate_authority_test.go b/aws/data_source_aws_acmpca_certificate_authority_test.go index 63fbba105583..a74bff22ca66 100644 --- a/aws/data_source_aws_acmpca_certificate_authority_test.go +++ b/aws/data_source_aws_acmpca_certificate_authority_test.go @@ -13,7 +13,7 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_basic(t *testing.T) { resourceName := "aws_acmpca_certificate_authority.test" datasourceName := "data.aws_acmpca_certificate_authority.test" - domainName := testAccRandomDomainName() + commonName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -25,7 +25,7 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_basic(t *testing.T) { ExpectError: regexp.MustCompile(`(AccessDeniedException|ResourceNotFoundException)`), }, { - Config: testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_ARN(domainName), + Config: testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_ARN(commonName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(datasourceName, "certificate", resourceName, "certificate"), @@ -50,7 +50,7 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_S3ObjectAcl(t *testing.T) { resourceName := "aws_acmpca_certificate_authority.test" datasourceName := "data.aws_acmpca_certificate_authority.test" - domainName := testAccRandomDomainName() + commonName := testAccRandomDomainName() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -62,7 +62,7 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_S3ObjectAcl(t *testing.T) { ExpectError: regexp.MustCompile(`(AccessDeniedException|ResourceNotFoundException)`), }, { - Config: testAccDataSourceAwsAcmpcaCertificateAuthorityConfigS3ObjectAcl_ARN(domainName), + Config: testAccDataSourceAwsAcmpcaCertificateAuthorityConfigS3ObjectAcl_ARN(commonName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(datasourceName, "arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(datasourceName, "certificate", resourceName, "certificate"), @@ -87,7 +87,7 @@ func TestAccDataSourceAwsAcmpcaCertificateAuthority_S3ObjectAcl(t *testing.T) { }) } -func testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_ARN(domainName string) string { +func testAccDataSourceAwsAcmpcaCertificateAuthorityConfig_ARN(commonName string) string { return fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "wrong" { permanent_deletion_time_in_days = 7 @@ -118,10 +118,10 @@ resource "aws_acmpca_certificate_authority" "test" { data "aws_acmpca_certificate_authority" "test" { arn = aws_acmpca_certificate_authority.test.arn } -`, domainName) +`, commonName) } -func testAccDataSourceAwsAcmpcaCertificateAuthorityConfigS3ObjectAcl_ARN(domainName string) string { +func testAccDataSourceAwsAcmpcaCertificateAuthorityConfigS3ObjectAcl_ARN(commonName string) string { return fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "wrong" { permanent_deletion_time_in_days = 7 @@ -152,7 +152,7 @@ resource "aws_acmpca_certificate_authority" "test" { data "aws_acmpca_certificate_authority" "test" { arn = aws_acmpca_certificate_authority.test.arn } -`, domainName) +`, commonName) } //lintignore:AWSAT003,AWSAT005 From b321ae2e2add94fb8e81b9fb4cc741592ee40720 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 30 Jun 2021 11:05:29 -0700 Subject: [PATCH 1079/1208] Resource naming cleanup --- aws/resource_aws_db_instance_test.go | 43 +++++++++++++++------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index b3dd3290ef26..6760820584a3 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -2217,6 +2217,7 @@ func TestAccAWSDBInstance_MSSQL_TZ(t *testing.T) { func TestAccAWSDBInstance_MSSQL_Domain(t *testing.T) { var vBefore, vAfter rds.DBInstance + resourceName := "aws_db_instance.test" rName := acctest.RandomWithPrefix("tf-acc-test") domain := testAccRandomDomain() @@ -2232,19 +2233,19 @@ func TestAccAWSDBInstance_MSSQL_Domain(t *testing.T) { { Config: testAccAWSDBInstanceConfig_MSSQLDomain(rName, directory1, directory2), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSDBInstanceExists("aws_db_instance.mssql", &vBefore), + testAccCheckAWSDBInstanceExists(resourceName, &vBefore), testAccCheckAWSDBInstanceDomainAttributes(directory1, &vBefore), - resource.TestCheckResourceAttrSet("aws_db_instance.mssql", "domain"), - resource.TestCheckResourceAttrSet("aws_db_instance.mssql", "domain_iam_role_name"), + resource.TestCheckResourceAttrSet(resourceName, "domain"), + resource.TestCheckResourceAttrSet(resourceName, "domain_iam_role_name"), ), }, { Config: testAccAWSDBInstanceConfig_MSSQLUpdateDomain(rName, directory1, directory2), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSDBInstanceExists("aws_db_instance.mssql", &vAfter), + testAccCheckAWSDBInstanceExists(resourceName, &vAfter), testAccCheckAWSDBInstanceDomainAttributes(directory2, &vAfter), - resource.TestCheckResourceAttrSet("aws_db_instance.mssql", "domain"), - resource.TestCheckResourceAttrSet("aws_db_instance.mssql", "domain_iam_role_name"), + resource.TestCheckResourceAttrSet(resourceName, "domain"), + resource.TestCheckResourceAttrSet(resourceName, "domain_iam_role_name"), ), }, }, @@ -2253,6 +2254,8 @@ func TestAccAWSDBInstance_MSSQL_Domain(t *testing.T) { func TestAccAWSDBInstance_MSSQL_DomainSnapshotRestore(t *testing.T) { var v, vRestoredInstance rds.DBInstance + resourceName := "aws_db_instance.test" + originResourceName := "aws_db_instance.origin" rName := acctest.RandomWithPrefix("tf-acc-test") domain := testAccRandomDomainName() @@ -2266,11 +2269,11 @@ func TestAccAWSDBInstance_MSSQL_DomainSnapshotRestore(t *testing.T) { { Config: testAccAWSDBInstanceConfig_MSSQLDomainSnapshotRestore(rName, domain), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSDBInstanceExists("aws_db_instance.mssql_restore", &vRestoredInstance), - testAccCheckAWSDBInstanceExists("aws_db_instance.mssql", &v), + testAccCheckAWSDBInstanceExists(resourceName, &vRestoredInstance), + testAccCheckAWSDBInstanceExists(originResourceName, &v), testAccCheckAWSDBInstanceDomainAttributes(domain, &vRestoredInstance), - resource.TestCheckResourceAttrSet("aws_db_instance.mssql_restore", "domain"), - resource.TestCheckResourceAttrSet("aws_db_instance.mssql_restore", "domain_iam_role_name"), + resource.TestCheckResourceAttrSet(resourceName, "domain"), + resource.TestCheckResourceAttrSet(resourceName, "domain_iam_role_name"), ), }, }, @@ -4368,7 +4371,7 @@ func testAccAWSDBInstanceConfig_MSSQLUpdateDomain(rName, directory1, directory2 return composeConfig( testAccAWSDBInstanceConfig_MSSQLDomain_SharedConfig(rName, directory1), fmt.Sprintf(` -resource "aws_db_instance" "mssql" { +resource "aws_db_instance" "test" { allocated_storage = 20 apply_immediately = true backup_retention_period = 0 @@ -4404,7 +4407,7 @@ func testAccAWSDBInstanceConfig_MSSQLDomainSnapshotRestore(rName, directory stri return composeConfig( testAccAWSDBInstanceConfig_MSSQLDomain_SharedConfig(rName, directory), fmt.Sprintf(` -resource "aws_db_instance" "mssql" { +resource "aws_db_instance" "origin" { allocated_storage = 20 engine = data.aws_rds_orderable_db_instance.test.engine engine_version = data.aws_rds_orderable_db_instance.test.engine_version @@ -4415,29 +4418,29 @@ resource "aws_db_instance" "mssql" { username = "somecrazyusername" } -resource "aws_db_snapshot" "mssql-snap" { - db_instance_identifier = aws_db_instance.mssql.id +resource "aws_db_snapshot" "origin" { + db_instance_identifier = aws_db_instance.origin.id db_snapshot_identifier = %[1]q } -resource "aws_db_instance" "mssql_restore" { +resource "aws_db_instance" "test" { allocated_storage = 20 apply_immediately = true backup_retention_period = 0 db_subnet_group_name = aws_db_subnet_group.test.name - engine = aws_db_instance.mssql.engine - engine_version = aws_db_instance.mssql.engine_version + engine = aws_db_instance.origin.engine + engine_version = aws_db_instance.origin.engine_version identifier = "%[1]s-restore" - instance_class = aws_db_instance.mssql.instance_class + instance_class = aws_db_instance.origin.instance_class password = "somecrazypassword" skip_final_snapshot = true username = "somecrazyusername" vpc_security_group_ids = [aws_security_group.test.id] - domain = aws_directory_service_directory.foo.id + domain = aws_directory_service_directory.directory.id domain_iam_role_name = aws_iam_role.role.name - snapshot_identifier = aws_db_snapshot.mssql-snap.id + snapshot_identifier = aws_db_snapshot.origin.id } `, rName)) } From 2b2fdecacd6fc1e6076adb806950f5f3b7e7133c Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 2 Jul 2021 15:34:22 -0700 Subject: [PATCH 1080/1208] Removes hardcoded domain from Route 53 delegation set data source --- ..._source_aws_route53_delegation_set_test.go | 24 +++++++++---------- ...esource_aws_route53_delegation_set_test.go | 10 ++++---- aws/resource_aws_route53_zone_test.go | 1 + 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/aws/data_source_aws_route53_delegation_set_test.go b/aws/data_source_aws_route53_delegation_set_test.go index 0f69e70e3057..d3f217c8a576 100644 --- a/aws/data_source_aws_route53_delegation_set_test.go +++ b/aws/data_source_aws_route53_delegation_set_test.go @@ -1,6 +1,7 @@ package aws import ( + "fmt" "regexp" "testing" @@ -12,40 +13,37 @@ func TestAccAWSRoute53DelegationSetDataSource_basic(t *testing.T) { dataSourceName := "data.aws_route53_delegation_set.dset" resourceName := "aws_route53_delegation_set.dset" + zoneName := testAccRandomDomainName() + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, route53.EndpointsID), Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccAWSDataSourceAWSRoute53DelegationSetConfig_basic, + Config: testAccAWSDataSourceAWSRoute53DelegationSetConfig_basic(zoneName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrPair( - dataSourceName, "name_servers.#", - resourceName, "name_servers.#", - ), - resource.TestMatchResourceAttr( - "data.aws_route53_delegation_set.dset", - "caller_reference", - regexp.MustCompile("DynDNS(.*)"), - ), + resource.TestCheckResourceAttrPair(dataSourceName, "name_servers.#", resourceName, "name_servers.#"), + resource.TestMatchResourceAttr("data.aws_route53_delegation_set.dset", "caller_reference", regexp.MustCompile("DynDNS(.*)")), ), }, }, }) } -const testAccAWSDataSourceAWSRoute53DelegationSetConfig_basic = ` +func testAccAWSDataSourceAWSRoute53DelegationSetConfig_basic(zoneName string) string { + return fmt.Sprintf(` resource "aws_route53_delegation_set" "dset" { reference_name = "DynDNS" } resource "aws_route53_zone" "primary" { - name = "example.xyz" + name = %[1]q delegation_set_id = aws_route53_delegation_set.dset.id } data "aws_route53_delegation_set" "dset" { id = aws_route53_delegation_set.dset.id } -` +`, zoneName) +} diff --git a/aws/resource_aws_route53_delegation_set_test.go b/aws/resource_aws_route53_delegation_set_test.go index f29310b795c9..488ab57d5e2d 100644 --- a/aws/resource_aws_route53_delegation_set_test.go +++ b/aws/resource_aws_route53_delegation_set_test.go @@ -43,6 +43,8 @@ func TestAccAWSRoute53DelegationSet_withZones(t *testing.T) { refName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_route53_delegation_set.test" + primaryZoneResourceName := "aws_route53_zone.primary" + secondaryZoneResourceName := "aws_route53_zone.secondary" domain := testAccRandomDomainName() zoneName1 := fmt.Sprintf("primary.%s", domain) @@ -58,10 +60,10 @@ func TestAccAWSRoute53DelegationSet_withZones(t *testing.T) { Config: testAccRoute53DelegationSetWithZonesConfig(refName, zoneName1, zoneName2), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53DelegationSetExists(resourceName), - testAccCheckRoute53ZoneExists("aws_route53_zone.primary", &zone), - testAccCheckRoute53ZoneExists("aws_route53_zone.secondary", &zone), - testAccCheckRoute53NameServersMatch(resourceName, "aws_route53_zone.primary"), - testAccCheckRoute53NameServersMatch(resourceName, "aws_route53_zone.secondary"), + testAccCheckRoute53ZoneExists(primaryZoneResourceName, &zone), + testAccCheckRoute53ZoneExists(secondaryZoneResourceName, &zone), + testAccCheckRoute53NameServersMatch(resourceName, primaryZoneResourceName), + testAccCheckRoute53NameServersMatch(resourceName, secondaryZoneResourceName), ), }, { diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index f19b8275a85b..07460c33f9bd 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -682,6 +682,7 @@ func testAccCheckDomainName(zone *route53.GetHostedZoneOutput, domain string) re return fmt.Errorf("Invalid domain name. Expected %s is %s", domain, *zone.HostedZone.Name) } } + func testAccRoute53ZoneConfig(zoneName string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { From 51d6bfb5d044f75c7ca8f3922c35398665a48298 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 2 Jul 2021 17:11:56 -0700 Subject: [PATCH 1081/1208] Fixes trailing-period SES acceptance test --- aws/resource_aws_ses_email_identity_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_ses_email_identity_test.go b/aws/resource_aws_ses_email_identity_test.go index 50af0d577720..7d0c64d25f3d 100644 --- a/aws/resource_aws_ses_email_identity_test.go +++ b/aws/resource_aws_ses_email_identity_test.go @@ -46,7 +46,7 @@ func TestAccAWSSESEmailIdentity_basic(t *testing.T) { } func TestAccAWSSESEmailIdentity_trailingPeriod(t *testing.T) { - email := testAccDefaultEmailAddress + email := fmt.Sprintf("%s.", testAccDefaultEmailAddress) resourceName := "aws_ses_email_identity.test" resource.ParallelTest(t, resource.TestCase{ From 2812625f23616bf15dad2b4675016f784cb9d165 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 6 Jul 2021 10:49:26 -0700 Subject: [PATCH 1082/1208] Fixes resource name --- aws/resource_aws_db_instance_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 6760820584a3..d95d40176806 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -4336,7 +4336,7 @@ func testAccAWSDBInstanceConfig_MSSQLDomain(rName, directory1, directory2 string return composeConfig( testAccAWSDBInstanceConfig_MSSQLDomain_SharedConfig(rName, directory1), fmt.Sprintf(` -resource "aws_db_instance" "mssql" { +resource "aws_db_instance" "test" { allocated_storage = 20 backup_retention_period = 0 db_subnet_group_name = aws_db_subnet_group.test.name From 66433d3ccc8a2a28103ad29bcdae07955702746c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 9 Jul 2021 16:54:30 -0400 Subject: [PATCH 1083/1208] Add CHANGELOG entry. --- .changelog/19954.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19954.txt diff --git a/.changelog/19954.txt b/.changelog/19954.txt new file mode 100644 index 000000000000..1823e0216e5b --- /dev/null +++ b/.changelog/19954.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_guardduty_detector: Add `datasources` argument +``` \ No newline at end of file From 242f45c646cddd23bd6c8f78bc836bad29a4e035 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 9 Jul 2021 16:57:06 -0400 Subject: [PATCH 1084/1208] r/aws_guardduty_detector: More idiomatic expand/flatten functions. --- aws/resource_aws_guardduty_detector.go | 103 ++++++++++++++----------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/aws/resource_aws_guardduty_detector.go b/aws/resource_aws_guardduty_detector.go index cf9b6bd6da4c..23866b0eb343 100644 --- a/aws/resource_aws_guardduty_detector.go +++ b/aws/resource_aws_guardduty_detector.go @@ -25,26 +25,15 @@ func resourceAwsGuardDutyDetector() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "enable": { - Type: schema.TypeBool, - Optional: true, - Default: true, - }, "account_id": { Type: schema.TypeString, Computed: true, }, + "arn": { Type: schema.TypeString, Computed: true, }, - // finding_publishing_frequency is marked as Computed:true since - // GuardDuty member accounts inherit setting from master account - "finding_publishing_frequency": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, "datasources": { Type: schema.TypeList, @@ -71,8 +60,21 @@ func resourceAwsGuardDutyDetector() *schema.Resource { }, }, - "tags": tagsSchema(), + "enable": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + // finding_publishing_frequency is marked as Computed:true since + // GuardDuty member accounts inherit setting from master account + "finding_publishing_frequency": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "tags": tagsSchema(), "tags_all": tagsSchemaComputed(), }, @@ -93,8 +95,8 @@ func resourceAwsGuardDutyDetectorCreate(d *schema.ResourceData, meta interface{} input.FindingPublishingFrequency = aws.String(v.(string)) } - if v, ok := d.GetOk("datasources"); ok { - input.DataSources = expandDataSourceConfigurations(v.([]interface{})) + if v, ok := d.GetOk("datasources"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DataSources = expandGuardDutyDataSourceConfigurations(v.([]interface{})[0].(map[string]interface{})) } if len(tags) > 0 { @@ -141,13 +143,18 @@ func resourceAwsGuardDutyDetectorRead(d *schema.ResourceData, meta interface{}) d.Set("arn", arn) d.Set("account_id", meta.(*AWSClient).accountid) - d.Set("enable", *gdo.Status == guardduty.DetectorStatusEnabled) - d.Set("finding_publishing_frequency", gdo.FindingPublishingFrequency) - if err := d.Set("datasources", flattenDataSourceConfigurations(gdo.DataSources)); err != nil { - return fmt.Errorf("error setting datasources: %s", err) + if gdo.DataSources != nil { + if err := d.Set("datasources", []interface{}{flattenGuardDutyDataSourceConfigurationsResult(gdo.DataSources)}); err != nil { + return fmt.Errorf("error setting datasources: %w", err) + } + } else { + d.Set("datasources", nil) } + d.Set("enable", aws.StringValue(gdo.Status) == guardduty.DetectorStatusEnabled) + d.Set("finding_publishing_frequency", gdo.FindingPublishingFrequency) + tags := keyvaluetags.GuarddutyKeyValueTags(gdo.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 @@ -165,7 +172,7 @@ func resourceAwsGuardDutyDetectorRead(d *schema.ResourceData, meta interface{}) func resourceAwsGuardDutyDetectorUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).guarddutyconn - if d.HasChanges("enable", "finding_publishing_frequency", "datasources") { + if d.HasChangesExcept("tags", "tags_all") { input := guardduty.UpdateDetectorInput{ DetectorId: aws.String(d.Id()), Enable: aws.Bool(d.Get("enable").(bool)), @@ -173,7 +180,7 @@ func resourceAwsGuardDutyDetectorUpdate(d *schema.ResourceData, meta interface{} } if d.HasChange("datasources") { - input.DataSources = expandDataSourceConfigurations(d.Get("datasources").([]interface{})) + input.DataSources = expandGuardDutyDataSourceConfigurations(d.Get("datasources").([]interface{})[0].(map[string]interface{})) } log.Printf("[DEBUG] Update GuardDuty Detector: %s", input) @@ -226,56 +233,58 @@ func resourceAwsGuardDutyDetectorDelete(d *schema.ResourceData, meta interface{} return nil } -func expandDataSourceConfigurations(dsc []interface{}) *guardduty.DataSourceConfigurations { - if len(dsc) < 1 || dsc[0] == nil { +func expandGuardDutyDataSourceConfigurations(tfMap map[string]interface{}) *guardduty.DataSourceConfigurations { + if tfMap == nil { return nil } - m := dsc[0].(map[string]interface{}) - - dataSourceConfigurations := &guardduty.DataSourceConfigurations{} + apiObject := &guardduty.DataSourceConfigurations{} - if v, ok := m["s3_logs"]; ok && v != "" && (len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil) { - dataSourceConfigurations.S3Logs = expandS3LogsConfiguration(v.([]interface{})) + if v, ok := tfMap["s3_logs"].([]interface{}); ok && len(v) > 0 { + apiObject.S3Logs = expandGuardDutyS3LogsConfiguration(v[0].(map[string]interface{})) } - return dataSourceConfigurations + return apiObject } -func expandS3LogsConfiguration(slc []interface{}) *guardduty.S3LogsConfiguration { - if len(slc) < 1 || slc[0] == nil { +func expandGuardDutyS3LogsConfiguration(tfMap map[string]interface{}) *guardduty.S3LogsConfiguration { + if tfMap == nil { return nil } - m := slc[0].(map[string]interface{}) + apiObject := &guardduty.S3LogsConfiguration{} - s3LogsConfiguration := &guardduty.S3LogsConfiguration{ - Enable: aws.Bool(m["enable"].(bool)), + if v, ok := tfMap["enable"].(bool); ok { + apiObject.Enable = aws.Bool(v) } - return s3LogsConfiguration + return apiObject } -func flattenDataSourceConfigurations(dsc *guardduty.DataSourceConfigurationsResult) []interface{} { - if dsc == nil { - return []interface{}{} +func flattenGuardDutyDataSourceConfigurationsResult(apiObject *guardduty.DataSourceConfigurationsResult) map[string]interface{} { + if apiObject == nil { + return nil } - m := map[string]interface{}{ - "s3_logs": flattenS3LogsConfiguration(dsc.S3Logs), + tfMap := map[string]interface{}{} + + if v := apiObject.S3Logs; v != nil { + tfMap["s3_logs"] = []interface{}{flattenGuardDutyS3LogsConfigurationResult(v)} } - return []interface{}{m} + return tfMap } -func flattenS3LogsConfiguration(slc *guardduty.S3LogsConfigurationResult) []interface{} { - if slc == nil { - return []interface{}{} +func flattenGuardDutyS3LogsConfigurationResult(apiObject *guardduty.S3LogsConfigurationResult) map[string]interface{} { + if apiObject == nil { + return nil } - m := map[string]interface{}{ - "enable": aws.StringValue(slc.Status) == guardduty.DataSourceStatusEnabled, + tfMap := map[string]interface{}{} + + if v := apiObject.Status; v != nil { + tfMap["enable"] = aws.StringValue(v) == guardduty.DataSourceStatusEnabled } - return []interface{}{m} + return tfMap } From 39f0e5aca7485e6abc21d0f918b706c4c2e73754 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Fri, 9 Jul 2021 21:31:22 +0000 Subject: [PATCH 1085/1208] Update CHANGELOG.md for #19859 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1588887e9750..2002c23ec123 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,15 @@ FEATURES: ENHANCEMENTS: * resource/aws_cognito_user_pool_client: Add the `enable_token_revocation` argument to support targeted sign out ([#20031](https://github.com/hashicorp/terraform-provider-aws/issues/20031)) +* resource/aws_guardduty_detector: Add `datasources` argument ([#19954](https://github.com/hashicorp/terraform-provider-aws/issues/19954)) * resource/fsx_windows_file_system: Add `aliases` argument. ([#20054](https://github.com/hashicorp/terraform-provider-aws/issues/20054)) BUG FIXES: * resource/aws_cognito_user_pool_client: Allow the `default_redirect_uri` argument value to be an empty string ([#20031](https://github.com/hashicorp/terraform-provider-aws/issues/20031)) * resource/aws_cognito_user_pool_client: Retry on `ConcurrentModificationException` ([#20031](https://github.com/hashicorp/terraform-provider-aws/issues/20031)) +* resource/aws_datasync_location_s3: Correctly parse S3 on Outposts location URI ([#19859](https://github.com/hashicorp/terraform-provider-aws/issues/19859)) +* resource/aws_db_instance: Ignore allocated_storage for replica at creation time ([#12548](https://github.com/hashicorp/terraform-provider-aws/issues/12548)) ## 3.49.0 (July 08, 2021) From 7d02775b17d868b039f5a0ddba3beb91cb163471 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 9 Jul 2021 17:34:17 -0400 Subject: [PATCH 1086/1208] Correct resource name in CHANGELOG entry --- .changelog/20054.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/20054.txt b/.changelog/20054.txt index 17613fbece00..158d54ba1be1 100644 --- a/.changelog/20054.txt +++ b/.changelog/20054.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/fsx_windows_file_system: Add `aliases` argument. +resource/aws_fsx_windows_file_system: Add `aliases` argument ``` From e7ded777058dbb3048ab222f85f941fd5fa53796 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Fri, 9 Jul 2021 21:36:46 +0000 Subject: [PATCH 1087/1208] Update CHANGELOG.md for #20124 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2002c23ec123..7c4e572644d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,8 @@ FEATURES: ENHANCEMENTS: * resource/aws_cognito_user_pool_client: Add the `enable_token_revocation` argument to support targeted sign out ([#20031](https://github.com/hashicorp/terraform-provider-aws/issues/20031)) +* resource/aws_fsx_windows_file_system: Add `aliases` argument ([#20054](https://github.com/hashicorp/terraform-provider-aws/issues/20054)) * resource/aws_guardduty_detector: Add `datasources` argument ([#19954](https://github.com/hashicorp/terraform-provider-aws/issues/19954)) -* resource/fsx_windows_file_system: Add `aliases` argument. ([#20054](https://github.com/hashicorp/terraform-provider-aws/issues/20054)) BUG FIXES: From 8a5033ef9d9637afdaf767d30da28ae6ba6ec2e5 Mon Sep 17 00:00:00 2001 From: Muhammad Panji Date: Sun, 11 Jul 2021 05:40:54 +0700 Subject: [PATCH 1088/1208] Fix typo in glue_catalog_table (#19921) --- website/docs/r/glue_catalog_table.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/glue_catalog_table.html.markdown b/website/docs/r/glue_catalog_table.html.markdown index 48dcd2d2c37c..415d0ea9a7cf 100644 --- a/website/docs/r/glue_catalog_table.html.markdown +++ b/website/docs/r/glue_catalog_table.html.markdown @@ -96,7 +96,7 @@ The follow arguments are optional: * `partition_index` - (Optional) Configuration block for a maximum of 3 partition indexes. See [`partition_index`](#partition_index) below. * `partition_keys` - (Optional) Configuration block of columns by which the table is partitioned. Only primitive types are supported as partition keys. See [`partition_keys`](#partition_keys) below. * `retention` - (Optional) Retention time for this table. -* `storage_descriptor` - (Optional) Configuration block for information about the physical storage of this table. For more information, refer to the [Glue Developer Guide](https://docs.aws.amazon.com/glue/latest/dg/aws-glue-api-catalog-tables. html#aws-glue-api-catalog-tables-StorageDescriptor). See [`storage_descriptor`](#storage_descriptor) below. +* `storage_descriptor` - (Optional) Configuration block for information about the physical storage of this table. For more information, refer to the [Glue Developer Guide](https://docs.aws.amazon.com/glue/latest/dg/aws-glue-api-catalog-tables.html#aws-glue-api-catalog-tables-StorageDescriptor). See [`storage_descriptor`](#storage_descriptor) below. * `table_type` - (Optional) Type of this table (EXTERNAL_TABLE, VIRTUAL_VIEW, etc.). While optional, some Athena DDL queries such as `ALTER TABLE` and `SHOW CREATE TABLE` will fail if this argument is empty. * `target_table` - (Optional) Configuration block of a target table for resource linking. See [`target_table`](#target_table) below. * `view_expanded_text` - (Optional) If the table is a view, the expanded text of the view; otherwise null. From fec543cf1de0b2299f2b868c441b1ff6d20cf18a Mon Sep 17 00:00:00 2001 From: Muhammad Panji Date: Sun, 11 Jul 2021 05:49:10 +0700 Subject: [PATCH 1089/1208] Add reference to AWS documentation for schedule_expression (#20060) --- website/docs/r/cloudwatch_event_rule.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/cloudwatch_event_rule.html.markdown b/website/docs/r/cloudwatch_event_rule.html.markdown index 31a578ca538b..000e8e24b368 100644 --- a/website/docs/r/cloudwatch_event_rule.html.markdown +++ b/website/docs/r/cloudwatch_event_rule.html.markdown @@ -64,7 +64,7 @@ The following arguments are supported: * `name` - (Optional) The name of the rule. If omitted, Terraform will assign a random, unique name. Conflicts with `name_prefix`. * `name_prefix` - (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `name`. -* `schedule_expression` - (Optional) The scheduling expression. For example, `cron(0 20 * * ? *)` or `rate(5 minutes)`. At least one of `schedule_expression` or `event_pattern` is required. Can only be used on the default event bus. +* `schedule_expression` - (Optional) The scheduling expression. For example, `cron(0 20 * * ? *)` or `rate(5 minutes)`. At least one of `schedule_expression` or `event_pattern` is required. Can only be used on the default event bus. For more information, refer to the AWS documentation [Schedule Expressions for Rules](https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html). * `event_bus_name` - (Optional) The event bus to associate with this rule. If you omit this, the `default` event bus is used. * `event_pattern` - (Optional) The event pattern described a JSON object. At least one of `schedule_expression` or `event_pattern` is required. See full documentation of [Events and Event Patterns in EventBridge](https://docs.aws.amazon.com/eventbridge/latest/userguide/eventbridge-and-event-patterns.html) for details. * `description` - (Optional) The description of the rule. From 4dd0e53392111e3f435a24b97d3d2409d3e22838 Mon Sep 17 00:00:00 2001 From: Muhammad Panji Date: Sun, 11 Jul 2021 06:23:41 +0700 Subject: [PATCH 1090/1208] Add more info for from_address in aws_pinpoint_email_channel (#18050) --- website/docs/r/pinpoint_email_channel.markdown | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/r/pinpoint_email_channel.markdown b/website/docs/r/pinpoint_email_channel.markdown index 95a43627952e..4a1bbd2c6857 100644 --- a/website/docs/r/pinpoint_email_channel.markdown +++ b/website/docs/r/pinpoint_email_channel.markdown @@ -16,7 +16,6 @@ Provides a Pinpoint Email Channel resource. resource "aws_pinpoint_email_channel" "email" { application_id = aws_pinpoint_app.app.application_id from_address = "user@example.com" - identity = aws_ses_domain_identity.identity.arn role_arn = aws_iam_role.role.arn } @@ -74,7 +73,7 @@ The following arguments are supported: * `application_id` - (Required) The application ID. * `enabled` - (Optional) Whether the channel is enabled or disabled. Defaults to `true`. * `configuration_set` - (Optional) The ARN of the Amazon SES configuration set that you want to apply to messages that you send through the channel. -* `from_address` - (Required) The email address used to send emails from. +* `from_address` - (Required) The email address used to send emails from. You can use email only (`user@example.com`) or friendly address (`User `). This field comply with [RFC 5322](https://www.ietf.org/rfc/rfc5322.txt). * `identity` - (Required) The ARN of an identity verified with SES. * `role_arn` - (Optional) The ARN of an IAM Role used to submit events to Mobile Analytics' event ingestion service. From f8914c38ade79ed049b4ec103161c3225ec5d49c Mon Sep 17 00:00:00 2001 From: LCStephens Date: Sun, 11 Jul 2021 10:31:09 -0500 Subject: [PATCH 1091/1208] add import documentation for aws_cloudfront_cache_policy --- website/docs/r/cloudfront_cache_policy.html.markdown | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/website/docs/r/cloudfront_cache_policy.html.markdown b/website/docs/r/cloudfront_cache_policy.html.markdown index 5f8de3c97449..f1e913a86b5a 100644 --- a/website/docs/r/cloudfront_cache_policy.html.markdown +++ b/website/docs/r/cloudfront_cache_policy.html.markdown @@ -91,3 +91,11 @@ In addition to all arguments above, the following attributes are exported: * `etag` - The current version of the cache policy. * `id` - The identifier for the cache policy. + +## Import + +Cloudfront Cache Policies can be imported using the `id`, e.g. + +``` +$ terraform import aws_cloudfront_cache_policy.policy 658327ea-f89d-4fab-a63d-7e88639e58f6 +``` \ No newline at end of file From ccff872e7e1df8cb01119542c44ac80c303f040c Mon Sep 17 00:00:00 2001 From: Raksit Mantanacharu Date: Mon, 12 Jul 2021 00:14:33 +0700 Subject: [PATCH 1092/1208] docs/r/lex_intent: add name in example usage --- website/docs/r/lex_intent.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/lex_intent.html.markdown b/website/docs/r/lex_intent.html.markdown index 07732ca168cf..bf02585efcb6 100644 --- a/website/docs/r/lex_intent.html.markdown +++ b/website/docs/r/lex_intent.html.markdown @@ -25,6 +25,7 @@ resource "aws_lex_intent" "order_flowers_intent" { } create_version = false + name = "OrderFlowers" description = "Intent to order a bouquet of flowers for pick up" fulfillment_activity { From 78067375b695ac0d20603090ec67afcb7f0cec87 Mon Sep 17 00:00:00 2001 From: Phil Nichol <35630607+philnichol@users.noreply.github.com> Date: Mon, 12 Jul 2021 00:05:18 +0100 Subject: [PATCH 1093/1208] updated aws_vpc_endpoint policy documentation to mention that a JSON-formatted string is required --- website/docs/r/vpc_endpoint.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/vpc_endpoint.html.markdown b/website/docs/r/vpc_endpoint.html.markdown index 368dd73fa2d1..32553ed50da3 100644 --- a/website/docs/r/vpc_endpoint.html.markdown +++ b/website/docs/r/vpc_endpoint.html.markdown @@ -116,7 +116,7 @@ The following arguments are supported: * `service_name` - (Required) The service name. For AWS services the service name is usually in the form `com.amazonaws..` (the SageMaker Notebook service is an exception to this rule, the service name is in the form `aws.sagemaker..notebook`). * `vpc_id` - (Required) The ID of the VPC in which the endpoint will be used. * `auto_accept` - (Optional) Accept the VPC endpoint (the VPC endpoint and service need to be in the same AWS account). -* `policy` - (Optional) A policy to attach to the endpoint that controls access to the service. Defaults to full access. All `Gateway` and some `Interface` endpoints support policies - see the [relevant AWS documentation](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints-access.html) for more details. For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). +* `policy` - (Optional) A policy to attach to the endpoint that controls access to the service. This is a JSON formatted string. Defaults to full access. All `Gateway` and some `Interface` endpoints support policies - see the [relevant AWS documentation](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints-access.html) for more details. For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). * `private_dns_enabled` - (Optional; AWS services and AWS Marketplace partner services only) Whether or not to associate a private hosted zone with the specified VPC. Applicable for endpoints of type `Interface`. Defaults to `false`. * `route_table_ids` - (Optional) One or more route table IDs. Applicable for endpoints of type `Gateway`. From 876c4be9519463df40dbfcc3c07680bc2a87adf2 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Sun, 11 Jul 2021 21:22:56 -0400 Subject: [PATCH 1094/1208] * Add Default Tags Support * Update documentation * Add test coverage for resource updates * refactor expand/flatten methods --- .changelog/18032.txt | 3 - .changelog/19307.txt | 4 + aws/resource_aws_appconfig_application.go | 121 ++--- ...resource_aws_appconfig_application_test.go | 154 +++++-- aws/resource_aws_appconfig_environment.go | 308 +++++++++---- ...resource_aws_appconfig_environment_test.go | 434 +++++++++++++----- website/docs/index.html.markdown | 2 + .../r/appconfig_application.html.markdown | 24 +- .../r/appconfig_environment.html.markdown | 60 +-- 9 files changed, 753 insertions(+), 357 deletions(-) delete mode 100644 .changelog/18032.txt diff --git a/.changelog/18032.txt b/.changelog/18032.txt deleted file mode 100644 index bfbca0898be6..000000000000 --- a/.changelog/18032.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:new-resource -aws_appconfig_application -``` \ No newline at end of file diff --git a/.changelog/19307.txt b/.changelog/19307.txt index 446c1c8af699..2c375c1a0d90 100644 --- a/.changelog/19307.txt +++ b/.changelog/19307.txt @@ -1,3 +1,7 @@ +```release-note:new-resource +aws_appconfig_application +``` + ```release-note:new-resource aws_appconfig_environment ``` diff --git a/aws/resource_aws_appconfig_application.go b/aws/resource_aws_appconfig_application.go index adcd5c9a8de5..34a26b850d14 100644 --- a/aws/resource_aws_appconfig_application.go +++ b/aws/resource_aws_appconfig_application.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,47 +24,51 @@ func resourceAwsAppconfigApplication() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { + "arn": { Type: schema.TypeString, - Required: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 64), - ), + Computed: true, }, "description": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.All( - validation.StringLenBetween(0, 1024), - ), + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 1024), }, - "tags": tagsSchema(), - "id": { - Type: schema.TypeString, - Computed: true, - }, - "arn": { - Type: schema.TypeString, - Computed: true, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 64), }, + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, + CustomizeDiff: SetTagsDiff, } } func resourceAwsAppconfigApplicationCreate(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{}))) + applicationName := d.Get("name").(string) - applicationDescription := d.Get("description").(string) input := &appconfig.CreateApplicationInput{ - Name: aws.String(applicationName), - Description: aws.String(applicationDescription), - Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), + Name: aws.String(applicationName), + Tags: tags.IgnoreAws().AppconfigTags(), + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) } app, err := conn.CreateApplication(input) + if err != nil { - return fmt.Errorf("Error creating AppConfig application: %s", err) + return fmt.Errorf("error creating AppConfig Application (%s): %w", applicationName, err) + } + + if app == nil { + return fmt.Errorf("error creating AppConfig Application (%s): empty response", applicationName) } d.SetId(aws.StringValue(app.Id)) @@ -73,6 +78,7 @@ func resourceAwsAppconfigApplicationCreate(d *schema.ResourceData, meta interfac func resourceAwsAppconfigApplicationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig input := &appconfig.GetApplicationInput{ @@ -81,21 +87,21 @@ func resourceAwsAppconfigApplicationRead(d *schema.ResourceData, meta interface{ output, err := conn.GetApplication(input) - if !d.IsNewResource() && isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { log.Printf("[WARN] Appconfig Application (%s) not found, removing from state", d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error getting AppConfig Application (%s): %s", d.Id(), err) + return fmt.Errorf("error getting AppConfig Application (%s): %w", d.Id(), err) } if output == nil { return fmt.Errorf("error getting AppConfig Application (%s): empty response", d.Id()) } - appARN := arn.ARN{ + arn := arn.ARN{ AccountID: meta.(*AWSClient).accountid, Partition: meta.(*AWSClient).partition, Region: meta.(*AWSClient).region, @@ -103,17 +109,25 @@ func resourceAwsAppconfigApplicationRead(d *schema.ResourceData, meta interface{ Service: "appconfig", }.String() - d.Set("arn", appARN) + d.Set("arn", arn) d.Set("name", output.Name) d.Set("description", output.Description) - tags, err := keyvaluetags.AppconfigListTags(conn, appARN) + tags, err := keyvaluetags.AppconfigListTags(conn, arn) + if err != nil { - return fmt.Errorf("error getting tags for AppConfig Application (%s): %s", d.Id(), err) + return fmt.Errorf("error listing tags for AppConfig Application (%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 @@ -122,35 +136,32 @@ func resourceAwsAppconfigApplicationRead(d *schema.ResourceData, meta interface{ func resourceAwsAppconfigApplicationUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn - 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) + if d.HasChangesExcept("tags", "tags_all") { + + updateInput := &appconfig.UpdateApplicationInput{ + ApplicationId: aws.String(d.Id()), } - } - appDesc := d.Get("description").(string) - appName := d.Get("name").(string) + if d.HasChange("description") { + updateInput.Description = aws.String(d.Get("description").(string)) + } - updateInput := &appconfig.UpdateApplicationInput{ - ApplicationId: aws.String(d.Id()), - Description: aws.String(appDesc), - Name: aws.String(appName), - } + if d.HasChange("name") { + updateInput.Name = aws.String(d.Get("name").(string)) + } - if d.HasChange("description") { - _, n := d.GetChange("description") - updateInput.Description = aws.String(n.(string)) - } + _, err := conn.UpdateApplication(updateInput) - if d.HasChange("name") { - _, n := d.GetChange("name") - updateInput.Name = aws.String(n.(string)) + if err != nil { + return fmt.Errorf("error updating AppConfig Application(%s): %w", d.Id(), err) + } } - _, err := conn.UpdateApplication(updateInput) - if err != nil { - return fmt.Errorf("error updating AppConfig Application(%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 Application (%s) tags: %w", d.Get("arn").(string), err) + } } return resourceAwsAppconfigApplicationRead(d, meta) @@ -165,12 +176,12 @@ func resourceAwsAppconfigApplicationDelete(d *schema.ResourceData, meta interfac _, err := conn.DeleteApplication(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { return nil } if err != nil { - return fmt.Errorf("error deleting Appconfig Application (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting Appconfig Application (%s): %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_appconfig_application_test.go b/aws/resource_aws_appconfig_application_test.go index 41ff1c820310..e00910360011 100644 --- a/aws/resource_aws_appconfig_application_test.go +++ b/aws/resource_aws_appconfig_application_test.go @@ -2,20 +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 TestAccAWSAppConfigApplication_basic(t *testing.T) { - var application appconfig.GetApplicationOutput rName := acctest.RandomWithPrefix("tf-acc-test") - rDesc := acctest.RandomWithPrefix("desc") resourceName := "aws_appconfig_application.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), @@ -23,13 +24,12 @@ func TestAccAWSAppConfigApplication_basic(t *testing.T) { CheckDestroy: testAccCheckAppConfigApplicationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAppConfigApplicationName(rName, rDesc), + Config: testAccAWSAppConfigApplicationConfigName(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigApplicationExists(resourceName, &application), + testAccCheckAWSAppConfigApplicationExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "appconfig", regexp.MustCompile(`application/[a-z0-9]{4,7}`)), resource.TestCheckResourceAttr(resourceName, "name", rName), - testAccCheckAWSAppConfigApplicationARN(resourceName, &application), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - resource.TestCheckResourceAttr(resourceName, "description", rDesc), ), }, { @@ -42,10 +42,7 @@ func TestAccAWSAppConfigApplication_basic(t *testing.T) { } func TestAccAWSAppConfigApplication_disappears(t *testing.T) { - var application appconfig.GetApplicationOutput - rName := acctest.RandomWithPrefix("tf-acc-test") - rDesc := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_application.test" resource.ParallelTest(t, resource.TestCase{ @@ -55,10 +52,10 @@ func TestAccAWSAppConfigApplication_disappears(t *testing.T) { CheckDestroy: testAccCheckAppConfigApplicationDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAppConfigApplicationName(rName, rDesc), + Config: testAccAWSAppConfigApplicationConfigName(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigApplicationExists(resourceName, &application), - testAccCheckAWSAppConfigApplicationDisappears(&application), + testAccCheckAWSAppConfigApplicationExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAppconfigApplication(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -66,9 +63,86 @@ func TestAccAWSAppConfigApplication_disappears(t *testing.T) { }) } -func TestAccAWSAppConfigApplication_Tags(t *testing.T) { - var application appconfig.GetApplicationOutput +func TestAccAWSAppConfigApplication_updateName(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + rNameUpdated := acctest.RandomWithPrefix("tf-acc-test-update") + resourceName := "aws_appconfig_application.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigApplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigApplicationConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigApplicationExists(resourceName), + ), + }, + { + Config: testAccAWSAppConfigApplicationConfigName(rNameUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigApplicationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", rNameUpdated), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigApplication_updateDescription(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + description := acctest.RandomWithPrefix("tf-acc-test-update") + resourceName := "aws_appconfig_application.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigApplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigApplicationConfigDescription(rName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigApplicationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", rName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigApplicationConfigDescription(rName, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigApplicationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", description), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Description Removal + Config: testAccAWSAppConfigApplicationConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigApplicationExists(resourceName), + ), + }, + }, + }) +} +func TestAccAWSAppConfigApplication_Tags(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_application.test" @@ -81,7 +155,7 @@ func TestAccAWSAppConfigApplication_Tags(t *testing.T) { { Config: testAccAWSAppConfigApplicationTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigApplicationExists(resourceName, &application), + testAccCheckAWSAppConfigApplicationExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), @@ -94,7 +168,7 @@ func TestAccAWSAppConfigApplication_Tags(t *testing.T) { { Config: testAccAWSAppConfigApplicationTags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigApplicationExists(resourceName, &application), + testAccCheckAWSAppConfigApplicationExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), @@ -103,7 +177,7 @@ func TestAccAWSAppConfigApplication_Tags(t *testing.T) { { Config: testAccAWSAppConfigApplicationTags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigApplicationExists(resourceName, &application), + testAccCheckAWSAppConfigApplicationExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), @@ -126,12 +200,12 @@ func testAccCheckAppConfigApplicationDestroy(s *terraform.State) error { output, err := conn.GetApplication(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { continue } if err != nil { - return err + return fmt.Errorf("error reading AppConfig Application (%s): %w", rs.Primary.ID, err) } if output != nil { @@ -140,24 +214,9 @@ func testAccCheckAppConfigApplicationDestroy(s *terraform.State) error { } return nil - -} - -func testAccCheckAWSAppConfigApplicationDisappears(application *appconfig.GetApplicationOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).appconfigconn - - input := &appconfig.DeleteApplicationInput{ - ApplicationId: aws.String(*application.Id), - } - - _, err := conn.DeleteApplication(input) - - return err - } } -func testAccCheckAWSAppConfigApplicationExists(resourceName string, application *appconfig.GetApplicationOutput) resource.TestCheckFunc { +func testAccCheckAWSAppConfigApplicationExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -175,29 +234,34 @@ func testAccCheckAWSAppConfigApplicationExists(resourceName string, application } output, err := conn.GetApplication(input) + if err != nil { - return err + return fmt.Errorf("error reading AppConfig Application (%s): %w", rs.Primary.ID, err) } - *application = *output + if output == nil { + return fmt.Errorf("AppConfig Application (%s) not found", rs.Primary.ID) + } return nil } } -func testAccCheckAWSAppConfigApplicationARN(resourceName string, application *appconfig.GetApplicationOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - return testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appconfig", fmt.Sprintf("application/%s", aws.StringValue(application.Id)))(s) - } +func testAccAWSAppConfigApplicationConfigName(rName string) string { + return fmt.Sprintf(` +resource "aws_appconfig_application" "test" { + name = %[1]q +} +`, rName) } -func testAccAWSAppConfigApplicationName(rName, rDesc string) string { +func testAccAWSAppConfigApplicationConfigDescription(rName, description string) string { return fmt.Sprintf(` resource "aws_appconfig_application" "test" { - name = %[1]q - description = %[2]q + name = %q + description = %q } -`, rName, rDesc) +`, rName, description) } func testAccAWSAppConfigApplicationTags1(rName, tagKey1, tagValue1 string) string { diff --git a/aws/resource_aws_appconfig_environment.go b/aws/resource_aws_appconfig_environment.go index 3a66831f2698..415bfce0c2f9 100644 --- a/aws/resource_aws_appconfig_environment.go +++ b/aws/resource_aws_appconfig_environment.go @@ -8,6 +8,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" @@ -20,48 +21,42 @@ func resourceAwsAppconfigEnvironment() *schema.Resource { Update: resourceAwsAppconfigEnvironmentUpdate, Delete: resourceAwsAppconfigEnvironmentDelete, Importer: &schema.ResourceImporter{ - State: resourceAwsAppconfigEnvironmentImport, + State: schema.ImportStatePassthrough, }, 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), - ), - }, - "description": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.All( - validation.StringLenBetween(0, 1024), - ), + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(4, 7), }, - "tags": tagsSchema(), "arn": { Type: schema.TypeString, Computed: true, }, - "monitors": { - Type: schema.TypeList, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 64), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 1024), + }, + "monitor": { + Type: schema.TypeSet, Optional: true, MaxItems: 5, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "alarm_arn": { Type: schema.TypeString, - Optional: true, + Required: true, ValidateFunc: validation.All( - validation.StringLenBetween(20, 2048), + validation.StringLenBetween(1, 2048), + validateArn, ), }, "alarm_role_arn": { @@ -69,107 +64,125 @@ func resourceAwsAppconfigEnvironment() *schema.Resource { Optional: true, ValidateFunc: validation.All( validation.StringLenBetween(20, 2048), + validateArn, ), }, }, }, }, + "state": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), }, + CustomizeDiff: SetTagsDiff, } } func resourceAwsAppconfigEnvironmentCreate(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{}))) + + appId := d.Get("application_id").(string) input := &appconfig.CreateEnvironmentInput{ Name: aws.String(d.Get("name").(string)), - Description: aws.String(d.Get("description").(string)), - ApplicationId: aws.String(d.Get("application_id").(string)), - Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().AppconfigTags(), - Monitors: expandAppconfigEnvironmentMonitors(d.Get("monitors").([]interface{})), + ApplicationId: aws.String(appId), + Tags: tags.IgnoreAws().AppconfigTags(), } - environment, err := conn.CreateEnvironment(input) - if err != nil { - return fmt.Errorf("Error creating AppConfig Environment: %s", err) + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) } - d.SetId(aws.StringValue(environment.Id)) + if v, ok := d.GetOk("monitor"); ok && v.(*schema.Set).Len() > 0 { + input.Monitors = expandAppconfigEnvironmentMonitors(v.(*schema.Set).List()) + } - return resourceAwsAppconfigEnvironmentRead(d, meta) -} + environment, err := conn.CreateEnvironment(input) -func expandAppconfigEnvironmentMonitors(list []interface{}) []*appconfig.Monitor { - monitors := make([]*appconfig.Monitor, len(list)) - for i, monitorInterface := range list { - m := monitorInterface.(map[string]interface{}) - monitors[i] = &appconfig.Monitor{ - AlarmArn: aws.String(m["alarm_arn"].(string)), - AlarmRoleArn: aws.String(m["alarm_role_arn"].(string)), - } + if err != nil { + return fmt.Errorf("error creating AppConfig Environment for Application (%s): %w", appId, err) } - return monitors -} -func flattenAwsAppconfigEnvironmentMonitors(monitors []*appconfig.Monitor) []interface{} { - list := make([]interface{}, len(monitors)) - for i, monitor := range monitors { - list[i] = map[string]interface{}{ - "alarm_arn": aws.StringValue(monitor.AlarmArn), - "alarm_role_arn": aws.StringValue(monitor.AlarmRoleArn), - } + if environment == nil { + return fmt.Errorf("error creating AppConfig Environment for Application (%s): empty response", appId) } - return list + + d.SetId(fmt.Sprintf("%s:%s", aws.StringValue(environment.Id), aws.StringValue(environment.ApplicationId))) + + return resourceAwsAppconfigEnvironmentRead(d, meta) } func resourceAwsAppconfigEnvironmentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - appID := d.Get("application_id").(string) + envID, appID, err := resourceAwsAppconfigEnvironmentParseID(d.Id()) + + if err != nil { + return err + } input := &appconfig.GetEnvironmentInput{ ApplicationId: aws.String(appID), - EnvironmentId: aws.String(d.Id()), + EnvironmentId: aws.String(envID), } output, err := conn.GetEnvironment(input) - if !d.IsNewResource() && isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] Appconfig Environment (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { + log.Printf("[WARN] Appconfig Environment (%s) for Application (%s) not found, removing from state", envID, appID) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error getting AppConfig Environment (%s): %s", d.Id(), err) + return fmt.Errorf("error getting AppConfig Environment (%s) for Application (%s): %w", envID, appID, err) } if output == nil { - return fmt.Errorf("error getting AppConfig Environment (%s): empty response", d.Id()) + return fmt.Errorf("error getting AppConfig Environment (%s) for Application (%s): empty response", envID, appID) } - d.Set("name", output.Name) - d.Set("description", output.Description) d.Set("application_id", output.ApplicationId) - d.Set("monitors", flattenAwsAppconfigEnvironmentMonitors(output.Monitors)) + d.Set("description", output.Description) + d.Set("name", output.Name) + d.Set("state", output.State) + + if err := d.Set("monitor", flattenAwsAppconfigEnvironmentMonitors(output.Monitors)); err != nil { + return fmt.Errorf("error setting monitor: %w", err) + } - environmentARN := arn.ARN{ + arn := arn.ARN{ AccountID: meta.(*AWSClient).accountid, Partition: meta.(*AWSClient).partition, Region: meta.(*AWSClient).region, - Resource: fmt.Sprintf("application/%s/environment/%s", appID, d.Id()), + Resource: fmt.Sprintf("application/%s/environment/%s", appID, envID), Service: "appconfig", }.String() - d.Set("arn", environmentARN) - tags, err := keyvaluetags.AppconfigListTags(conn, environmentARN) + d.Set("arn", arn) + + tags, err := keyvaluetags.AppconfigListTags(conn, arn) + if err != nil { - return fmt.Errorf("error getting tags for AppConfig Environment (%s): %s", d.Id(), err) + return fmt.Errorf("error listing tags for AppConfig Environment (%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) + 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_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) } return nil @@ -178,33 +191,42 @@ func resourceAwsAppconfigEnvironmentRead(d *schema.ResourceData, meta interface{ func resourceAwsAppconfigEnvironmentUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn - updateInput := &appconfig.UpdateEnvironmentInput{ - EnvironmentId: aws.String(d.Id()), - ApplicationId: aws.String(d.Get("application_id").(string)), - } + if d.HasChangesExcept("tags", "tags_all") { + envID, appID, err := resourceAwsAppconfigEnvironmentParseID(d.Id()) - if d.HasChange("description") { - updateInput.Description = aws.String(d.Get("description").(string)) - } + if err != nil { + return err + } - if d.HasChange("name") { - updateInput.Name = aws.String(d.Get("name").(string)) - } + updateInput := &appconfig.UpdateEnvironmentInput{ + EnvironmentId: aws.String(envID), + ApplicationId: aws.String(appID), + } - 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) + 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("monitors") { - updateInput.Monitors = expandAppconfigEnvironmentMonitors(d.Get("monitors").([]interface{})) + if d.HasChange("monitor") { + updateInput.Monitors = expandAppconfigEnvironmentMonitors(d.Get("monitor").(*schema.Set).List()) + } + + _, err = conn.UpdateEnvironment(updateInput) + + if err != nil { + return fmt.Errorf("error updating AppConfig Environment (%s) for Application (%s): %w", envID, appID, err) + } } - _, err := conn.UpdateEnvironment(updateInput) - if err != nil { - return fmt.Errorf("error updating AppConfig Environment(%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 Environment (%s) tags: %w", d.Get("arn").(string), err) + } } return resourceAwsAppconfigEnvironmentRead(d, meta) @@ -213,32 +235,114 @@ func resourceAwsAppconfigEnvironmentUpdate(d *schema.ResourceData, meta interfac func resourceAwsAppconfigEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn + envID, appID, err := resourceAwsAppconfigEnvironmentParseID(d.Id()) + + if err != nil { + return err + } + input := &appconfig.DeleteEnvironmentInput{ - EnvironmentId: aws.String(d.Id()), - ApplicationId: aws.String(d.Get("application_id").(string)), + EnvironmentId: aws.String(envID), + ApplicationId: aws.String(appID), } - _, err := conn.DeleteEnvironment(input) + _, err = conn.DeleteEnvironment(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { return nil } if err != nil { - return fmt.Errorf("error deleting Appconfig Environment (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting Appconfig Environment (%s) for Application (%s): %w", envID, appID, err) } return nil } -func resourceAwsAppconfigEnvironmentImport(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/environment-id'", d.Id()) +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 parts[0], parts[1], nil +} + +func expandAppconfigEnvironmentMonitor(tfMap map[string]interface{}) *appconfig.Monitor { + if tfMap == nil { + return nil + } + + monitor := &appconfig.Monitor{} + + if v, ok := tfMap["alarm_arn"].(string); ok && v != "" { + monitor.AlarmArn = aws.String(v) } - d.SetId(parts[1]) - d.Set("application_id", parts[0]) + if v, ok := tfMap["alarm_role_arn"].(string); ok && v != "" { + monitor.AlarmRoleArn = aws.String(v) + } + + return monitor +} + +func expandAppconfigEnvironmentMonitors(tfList []interface{}) []*appconfig.Monitor { + // AppConfig API requires a 0 length slice instead of a nil value + // when updating from N monitors to 0/nil monitors + monitors := make([]*appconfig.Monitor, 0) + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + + if !ok { + continue + } + + monitor := expandAppconfigEnvironmentMonitor(tfMap) + + if monitor == nil { + continue + } + + monitors = append(monitors, monitor) + } + + return monitors +} + +func flattenAwsAppconfigEnvironmentMonitor(monitor *appconfig.Monitor) map[string]interface{} { + if monitor == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := monitor.AlarmArn; v != nil { + tfMap["alarm_arn"] = aws.StringValue(v) + } + + if v := monitor.AlarmRoleArn; v != nil { + tfMap["alarm_role_arn"] = aws.StringValue(v) + } + + return tfMap +} + +func flattenAwsAppconfigEnvironmentMonitors(monitors []*appconfig.Monitor) []interface{} { + if len(monitors) == 0 { + return nil + } + + var tfList []interface{} + + for _, monitor := range monitors { + if monitor == nil { + continue + } + + tfList = append(tfList, flattenAwsAppconfigEnvironmentMonitor(monitor)) + } - return []*schema.ResourceData{d}, nil + return tfList } diff --git a/aws/resource_aws_appconfig_environment_test.go b/aws/resource_aws_appconfig_environment_test.go index fff5d3affa1f..3845bc9e41c3 100644 --- a/aws/resource_aws_appconfig_environment_test.go +++ b/aws/resource_aws_appconfig_environment_test.go @@ -2,24 +2,22 @@ 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 TestAccAWSAppConfigEnvironment_basic(t *testing.T) { - var environment appconfig.GetEnvironmentOutput - roleName := acctest.RandomWithPrefix("tf-acc-test") - alarmName := acctest.RandomWithPrefix("tf-acc-test") - appName := acctest.RandomWithPrefix("tf-acc-test") - appDesc := acctest.RandomWithPrefix("desc") - envName := acctest.RandomWithPrefix("tf-acc-test") - envDesc := acctest.RandomWithPrefix("desc") + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_environment.test" + appResourceName := "aws_appconfig_application.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), @@ -27,18 +25,19 @@ func TestAccAWSAppConfigEnvironment_basic(t *testing.T) { CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAppConfigEnvironmentWithMonitors(roleName, alarmName, appName, appDesc, envName, envDesc), + Config: testAccAWSAppConfigEnvironmentConfigBasic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigEnvironmentExists(resourceName, &environment), - resource.TestCheckResourceAttr(resourceName, "name", envName), - testAccCheckAWSAppConfigEnvironmentARN(resourceName, &environment), + testAccCheckAWSAppConfigEnvironmentExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "appconfig", regexp.MustCompile(`application/[a-z0-9]{4,7}/environment/[a-z0-9]{4,7}`)), + resource.TestCheckResourceAttrPair(resourceName, "application_id", appResourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "monitor.#", "0"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrSet(resourceName, "state"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - resource.TestCheckResourceAttr(resourceName, "description", envDesc), ), }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAppConfigEnvironmentImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -47,12 +46,7 @@ func TestAccAWSAppConfigEnvironment_basic(t *testing.T) { } func TestAccAWSAppConfigEnvironment_disappears(t *testing.T) { - var environment appconfig.GetEnvironmentOutput - - appName := acctest.RandomWithPrefix("tf-acc-test") - appDesc := acctest.RandomWithPrefix("desc") - envName := acctest.RandomWithPrefix("tf-acc-test") - envDesc := acctest.RandomWithPrefix("desc") + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_environment.test" resource.ParallelTest(t, resource.TestCase{ @@ -62,10 +56,10 @@ func TestAccAWSAppConfigEnvironment_disappears(t *testing.T) { CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAppConfigEnvironment(appName, appDesc, envName, envDesc), + Config: testAccAWSAppConfigEnvironmentConfigBasic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigEnvironmentExists(resourceName, &environment), - testAccCheckAWSAppConfigEnvironmentDisappears(&environment), + testAccCheckAWSAppConfigEnvironmentExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAppconfigEnvironment(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -73,9 +67,185 @@ func TestAccAWSAppConfigEnvironment_disappears(t *testing.T) { }) } -func TestAccAWSAppConfigEnvironment_Tags(t *testing.T) { - var environment appconfig.GetEnvironmentOutput +func TestAccAWSAppConfigEnvironment_updateName(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + rNameUpdated := acctest.RandomWithPrefix("tf-acc-test-update") + resourceName := "aws_appconfig_environment.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigEnvironmentConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName), + ), + }, + { + Config: testAccAWSAppConfigEnvironmentConfigBasic(rNameUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", rNameUpdated), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} +func TestAccAWSAppConfigEnvironment_updateDescription(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + description := acctest.RandomWithPrefix("tf-acc-test-update") + resourceName := "aws_appconfig_environment.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigEnvironmentConfigDescription(rName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", rName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigEnvironmentConfigDescription(rName, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", description), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Description Removal + Config: testAccAWSAppConfigEnvironmentConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName), + ), + }, + }, + }) +} + +func TestAccAWSAppConfigEnvironment_Monitors(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appconfig_environment.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigEnvironmentWithMonitors(rName, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "monitor.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "monitor.*.alarm_arn", "aws_cloudwatch_metric_alarm.test.0", "arn"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "monitor.*.alarm_role_arn", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigEnvironmentWithMonitors(rName, 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "monitor.#", "2"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "monitor.*.alarm_arn", "aws_cloudwatch_metric_alarm.test.0", "arn"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "monitor.*.alarm_role_arn", "aws_iam_role.test", "arn"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "monitor.*.alarm_arn", "aws_cloudwatch_metric_alarm.test.1", "arn"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "monitor.*.alarm_role_arn", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Monitor Removal + Config: testAccAWSAppConfigEnvironmentConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "monitor.#", "0"), + ), + }, + }, + }) +} + +func TestAccAWSAppConfigEnvironment_MultipleEnvironments(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName1 := "aws_appconfig_environment.test" + resourceName2 := "aws_appconfig_environment.test2" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppConfigEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAppConfigEnvironmentConfigMultiple(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName1), + testAccCheckAWSAppConfigEnvironmentExists(resourceName2), + ), + }, + { + ResourceName: resourceName1, + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: resourceName2, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigEnvironmentConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigEnvironmentExists(resourceName1), + ), + }, + { + ResourceName: resourceName1, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigEnvironment_Tags(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_environment.test" @@ -88,21 +258,20 @@ func TestAccAWSAppConfigEnvironment_Tags(t *testing.T) { { Config: testAccAWSAppConfigEnvironmentTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigEnvironmentExists(resourceName, &environment), + testAccCheckAWSAppConfigEnvironmentExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAppConfigEnvironmentImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, { Config: testAccAWSAppConfigEnvironmentTags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigEnvironmentExists(resourceName, &environment), + testAccCheckAWSAppConfigEnvironmentExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), @@ -111,7 +280,7 @@ func TestAccAWSAppConfigEnvironment_Tags(t *testing.T) { { Config: testAccAWSAppConfigEnvironmentTags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigEnvironmentExists(resourceName, &environment), + testAccCheckAWSAppConfigEnvironmentExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), @@ -128,43 +297,36 @@ func testAccCheckAppConfigEnvironmentDestroy(s *terraform.State) error { continue } + envID, appID, err := resourceAwsAppconfigEnvironmentParseID(rs.Primary.ID) + + if err != nil { + return err + } + input := &appconfig.GetEnvironmentInput{ - ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), - EnvironmentId: aws.String(rs.Primary.ID), + ApplicationId: aws.String(appID), + EnvironmentId: aws.String(envID), } output, err := conn.GetEnvironment(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { continue } if err != nil { - return err + return fmt.Errorf("error reading AppConfig Environment (%s) for Application (%s): %w", envID, appID, err) } if output != nil { - return fmt.Errorf("AppConfig Environment (%s) still exists", rs.Primary.ID) + return fmt.Errorf("AppConfig Environment (%s) for Application (%s) still exists", envID, appID) } } return nil } -func testAccCheckAWSAppConfigEnvironmentDisappears(environment *appconfig.GetEnvironmentOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).appconfigconn - - _, err := conn.DeleteEnvironment(&appconfig.DeleteEnvironmentInput{ - ApplicationId: environment.ApplicationId, - EnvironmentId: environment.Id, - }) - - return err - } -} - -func testAccCheckAWSAppConfigEnvironmentExists(resourceName string, environment *appconfig.GetEnvironmentOutput) resource.TestCheckFunc { +func testAccCheckAWSAppConfigEnvironmentExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -175,84 +337,64 @@ func testAccCheckAWSAppConfigEnvironmentExists(resourceName string, environment return fmt.Errorf("Resource (%s) ID not set", resourceName) } - conn := testAccProvider.Meta().(*AWSClient).appconfigconn + envID, appID, err := resourceAwsAppconfigEnvironmentParseID(rs.Primary.ID) - output, err := conn.GetEnvironment(&appconfig.GetEnvironmentInput{ - ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), - EnvironmentId: aws.String(rs.Primary.ID), - }) if err != nil { return err } - *environment = *output + conn := testAccProvider.Meta().(*AWSClient).appconfigconn - return nil - } -} + input := &appconfig.GetEnvironmentInput{ + ApplicationId: aws.String(appID), + EnvironmentId: aws.String(envID), + } -func testAccCheckAWSAppConfigEnvironmentARN(resourceName string, environment *appconfig.GetEnvironmentOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - return testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appconfig", fmt.Sprintf("application/%s/environment/%s", aws.StringValue(environment.ApplicationId), aws.StringValue(environment.Id)))(s) - } -} + output, err := conn.GetEnvironment(input) -func testAccAWSAppConfigEnvironmentWithMonitors(roleName, alarmName, appName, appDesc, envName, envDesc string) string { - return testAccAWSAppConfigMonitor_ServiceRole(roleName) + testAccAWSCloudWatchMetricAlarmConfig(alarmName) + testAccAWSAppConfigApplicationName(appName, appDesc) + fmt.Sprintf(` -resource "aws_appconfig_environment" "test" { - name = %[1]q - description = %[2]q - application_id = aws_appconfig_application.test.id + if err != nil { + return err + } - monitors { - alarm_arn = aws_cloudwatch_metric_alarm.test.arn - alarm_role_arn = aws_iam_role.test.arn - } -} -`, envName, envDesc) -} + if output == nil { + return fmt.Errorf("AppConfig Environment (%s) for Application (%s) not found", envID, appID) + } -func testAccAWSAppConfigEnvironment(appName, appDesc, envName, envDesc string) string { - return testAccAWSAppConfigApplicationName(appName, appDesc) + fmt.Sprintf(` -resource "aws_appconfig_environment" "test" { - name = %[1]q - description = %[2]q - application_id = aws_appconfig_application.test.id -} -`, envName, envDesc) + return nil + } } -func testAccAWSAppConfigEnvironmentTags1(rName, tagKey1, tagValue1 string) string { - return testAccAWSAppConfigApplicationTags1(rName, tagKey1, tagValue1) + fmt.Sprintf(` +func testAccAWSAppConfigEnvironmentConfigBasic(rName string) string { + return composeConfig( + testAccAWSAppConfigApplicationConfigName(rName), + fmt.Sprintf(` resource "aws_appconfig_environment" "test" { - name = %[1]q + name = %q application_id = aws_appconfig_application.test.id - - tags = { - %[2]q = %[3]q - } } -`, rName, tagKey1, tagValue1) +`, rName)) } -func testAccAWSAppConfigEnvironmentTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return testAccAWSAppConfigApplicationTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2) + fmt.Sprintf(` +func testAccAWSAppConfigEnvironmentConfigDescription(rName, description string) string { + return composeConfig( + testAccAWSAppConfigApplicationConfigName(rName), + fmt.Sprintf(` resource "aws_appconfig_environment" "test" { - name = %[1]q + name = %q + description = %q application_id = aws_appconfig_application.test.id - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } } -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +`, rName, description)) } -func testAccAWSAppConfigMonitor_ServiceRole(rName string) string { - return fmt.Sprintf(` +func testAccAWSAppConfigEnvironmentWithMonitors(rName string, count int) string { + return composeConfig( + testAccAWSAppConfigApplicationConfigName(rName), + fmt.Sprintf(` +data "aws_partition" "current" {} + resource "aws_iam_role" "test" { - name = "%s" + name = %[1]q assume_role_policy = < Date: Sun, 11 Jul 2021 21:41:05 -0400 Subject: [PATCH 1095/1208] update attributes reference in env resource --- website/docs/r/appconfig_environment.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/appconfig_environment.html.markdown b/website/docs/r/appconfig_environment.html.markdown index a743773d67cb..506e3b1266b8 100644 --- a/website/docs/r/appconfig_environment.html.markdown +++ b/website/docs/r/appconfig_environment.html.markdown @@ -42,10 +42,10 @@ resource "aws_appconfig_application" "example" { The following arguments are supported: +* `application_id` - (Required, Forces new resource) The AppConfig application ID. Must be between 4 and 7 characters in length. * `name` - (Required) The name for the environment. Must be between 1 and 64 characters in length. -* `application_id` - (Required) The AppConfig application ID. Must be between 4 and 7 characters in length. * `description` - (Optional) The description of the environment. Can be at most 1024 characters. -* `monitor` - (Optional) Set of Amazon CloudWatch alarms to monitor during the deployment process. Maximum of 5. Detailed below. +* `monitor` - (Optional) Set of Amazon CloudWatch alarms to monitor during the deployment process. Maximum of 5. See [Monitor](#monitor) below for more details. * `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. ### Monitor @@ -68,5 +68,5 @@ In addition to all arguments above, the following attributes are exported: AppConfig Environments can be imported by using the environment ID and application ID separated by a colon (`:`), e.g. ``` -$ terraform import aws_appconfig_environment.example 71abcde/11xxxxx +$ terraform import aws_appconfig_environment.example 71abcde:11xxxxx ``` From 4e0217c2e20c876d296fd4a56d1c4104873efccf Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 22:07:31 +0900 Subject: [PATCH 1096/1208] 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 90236fbf4ec4..48e60dbd52cc 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 000000000000..700fe6f0f610 --- /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 4fde4995f204465b51e2e7173f2e78b7afa38294 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 22:44:58 +0900 Subject: [PATCH 1097/1208] 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 700fe6f0f610..c0fce7410080 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 94edc9e54bf9069ce11df63a08a5c307c886cd47 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 22:53:50 +0900 Subject: [PATCH 1098/1208] 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 000000000000..862e1648474b --- /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 a2d6abe3bad4c99e69360d3879c7d44a62d48ed1 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 07:20:57 +0900 Subject: [PATCH 1099/1208] 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 000000000000..a25999e52ffd --- /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 16e0a34871217880c8abd1f306483212f6a2f09b Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 09:39:35 +0900 Subject: [PATCH 1100/1208] 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 862e1648474b..01da1fef385d 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 5e42c00bc2cc40074bd9e6ed24cf1f1b4ccce5ab Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 09:41:16 +0900 Subject: [PATCH 1101/1208] 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 a25999e52ffd..8b08b7130e71 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 d5338d41244480fb3b9346fa065d78ba7ab124dd Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 09:42:45 +0900 Subject: [PATCH 1102/1208] 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 01da1fef385d..c3974e546ee2 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 82aff38a9d140f5c72d8ae8e350b1c4320706a39 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 09:45:38 +0900 Subject: [PATCH 1103/1208] 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 8b08b7130e71..4b873474fde0 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 2f911b800a68ad481266593f95905d863273947d Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Wed, 12 May 2021 22:31:15 +0900 Subject: [PATCH 1104/1208] 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 c0fce7410080..331c1fc63723 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 eae43b84de10f91104bddc6ab64dfc00402ca4c4 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Fri, 14 May 2021 20:36:12 +0900 Subject: [PATCH 1105/1208] 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 331c1fc63723..321aba0c7935 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 9b6b71a320b34214bdde8ad2cb45216cd812a906 Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Mon, 12 Jul 2021 12:05:24 +0900 Subject: [PATCH 1106/1208] 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 4b873474fde0..f594dad9bf63 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 df7dcdabe328dda424215919fe1e78c7e68ef336 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Tue, 11 May 2021 22:07:31 +0900 Subject: [PATCH 1107/1208] 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 90236fbf4ec4..48e60dbd52cc 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 000000000000..700fe6f0f610 --- /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 1108/1208] 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 700fe6f0f610..c0fce7410080 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 1109/1208] 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 000000000000..862e1648474b --- /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 1110/1208] 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 000000000000..a25999e52ffd --- /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 1111/1208] 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 862e1648474b..01da1fef385d 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 1112/1208] 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 a25999e52ffd..8b08b7130e71 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 1113/1208] 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 01da1fef385d..c3974e546ee2 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 1114/1208] 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 8b08b7130e71..4b873474fde0 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 1115/1208] 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 c0fce7410080..331c1fc63723 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 1116/1208] 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 331c1fc63723..321aba0c7935 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 1117/1208] 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 48e60dbd52cc..6555293a3106 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 000000000000..f7471fe0331d --- /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 1118/1208] 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 000000000000..1482f5ecb801 --- /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 1119/1208] 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 000000000000..949711880370 --- /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 1120/1208] 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 4b873474fde0..f594dad9bf63 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 1121/1208] 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 949711880370..8215e67cf9ac 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 b43c26ad1a9e67be834dd4cfd6b4770e6c7bd5ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jul 2021 06:10:59 +0000 Subject: [PATCH 1122/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.39.3 to 1.39.4. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.39.3...v1.39.4) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 +-- .../aws/aws-sdk-go/aws/endpoints/defaults.go | 25 +++++++++++++++++++ .../github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index c457e5dd1a16..1a77c9b93d8e 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.39.3 + github.com/aws/aws-sdk-go v1.39.4 github.com/bflad/tfproviderlint v0.27.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index 4816e45d0e37..b9de0de284d7 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -70,8 +70,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.39.3 h1:JMDk7p+AV89MdVy/ZcFWAGivWIE3vXOsRriFjFWVcIY= -github.com/aws/aws-sdk-go v1.39.3/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go v1.39.4 h1:nXBChUaG5cinrl3yg4/rUyssOOLH/ohk4S9K03kJirE= +github.com/aws/aws-sdk-go v1.39.4/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.27.0 h1:KXF+dYaWJ/OSVyWIrk2NIYgQBMDDSOC4VQB/P+P5nhI= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index cebbe397201a..60ff236dfd52 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -3843,6 +3843,18 @@ var awsPartition = partition{ "iotwireless": service{ Endpoints: endpoints{ + "ap-northeast-1": endpoint{ + Hostname: "api.iotwireless.ap-northeast-1.amazonaws.com", + CredentialScope: credentialScope{ + Region: "ap-northeast-1", + }, + }, + "ap-southeast-2": endpoint{ + Hostname: "api.iotwireless.ap-southeast-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "ap-southeast-2", + }, + }, "eu-west-1": endpoint{ Hostname: "api.iotwireless.eu-west-1.amazonaws.com", CredentialScope: credentialScope{ @@ -3855,6 +3867,12 @@ var awsPartition = partition{ Region: "us-east-1", }, }, + "us-west-2": endpoint{ + Hostname: "api.iotwireless.us-west-2.amazonaws.com", + CredentialScope: credentialScope{ + Region: "us-west-2", + }, + }, }, }, "kafka": service{ @@ -8442,6 +8460,13 @@ var awscnPartition = partition{ }, }, }, + "transcribestreaming": service{ + + Endpoints: endpoints{ + "cn-north-1": endpoint{}, + "cn-northwest-1": endpoint{}, + }, + }, "transfer": service{ Endpoints: endpoints{ diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index 19a602480f06..8b253ba02b18 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.39.3" +const SDKVersion = "1.39.4" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index 6f58fbb8f972..a9d77a9d5ef9 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.39.3 +# github.com/aws/aws-sdk-go v1.39.4 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From eb885d126da4e273c9abd688a3bfeb9dd128f797 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jul 2021 06:15:03 +0000 Subject: [PATCH 1123/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.39.3 to 1.39.4 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.39.3 to 1.39.4. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.39.3...v1.39.4) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4e23c51ff636..13234f81e5e3 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect - github.com/aws/aws-sdk-go v1.39.3 + github.com/aws/aws-sdk-go v1.39.4 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index c0acb2cd1b68..fc92a009e9de 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.39.3 h1:JMDk7p+AV89MdVy/ZcFWAGivWIE3vXOsRriFjFWVcIY= -github.com/aws/aws-sdk-go v1.39.3/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go v1.39.4 h1:nXBChUaG5cinrl3yg4/rUyssOOLH/ohk4S9K03kJirE= +github.com/aws/aws-sdk-go v1.39.4/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From a0d51c5230321458e9d90e3d50dfd049313008a6 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Mon, 12 Jul 2021 02:42:29 -0400 Subject: [PATCH 1124/1208] CR updates; add CHANGELOG entry --- .changelog/19320.txt | 3 + aws/provider.go | 2 +- ...rce_aws_appconfig_configuration_profile.go | 357 +++++++++----- ...ws_appconfig_configuration_profile_test.go | 453 +++++++++++++++--- aws/resource_aws_appconfig_environment.go | 12 +- ...resource_aws_appconfig_environment_test.go | 2 +- website/docs/index.html.markdown | 1 + ...config_configuration_profile.html.markdown | 55 ++- 8 files changed, 648 insertions(+), 237 deletions(-) create mode 100644 .changelog/19320.txt diff --git a/.changelog/19320.txt b/.changelog/19320.txt new file mode 100644 index 000000000000..c4cdbdca9d43 --- /dev/null +++ b/.changelog/19320.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_appconfig_configuration_profile +``` diff --git a/aws/provider.go b/aws/provider.go index 48e60dbd52cc..29aa1e41d054 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -507,8 +507,8 @@ func Provider() *schema.Provider { "aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(), "aws_appautoscaling_scheduled_action": resourceAwsAppautoscalingScheduledAction(), "aws_appconfig_application": resourceAwsAppconfigApplication(), - "aws_appconfig_environment": resourceAwsAppconfigEnvironment(), "aws_appconfig_configuration_profile": resourceAwsAppconfigConfigurationProfile(), + "aws_appconfig_environment": resourceAwsAppconfigEnvironment(), "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 index 321aba0c7935..6a17f2120125 100644 --- a/aws/resource_aws_appconfig_configuration_profile.go +++ b/aws/resource_aws_appconfig_configuration_profile.go @@ -3,11 +3,13 @@ package aws import ( "fmt" "log" + "regexp" "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" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" @@ -20,178 +22,187 @@ func resourceAwsAppconfigConfigurationProfile() *schema.Resource { Update: resourceAwsAppconfigConfigurationProfileUpdate, Delete: resourceAwsAppconfigConfigurationProfileDelete, Importer: &schema.ResourceImporter{ - State: resourceAwsAppconfigConfigurationProfileImport, + State: schema.ImportStatePassthrough, }, 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.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, }, - "location_uri": { + "configuration_profile_id": { Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(0, 2048), - ), + Computed: true, }, "description": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.All( - validation.StringLenBetween(0, 1024), - ), + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 1024), + }, + "location_uri": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 2048), + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 64), }, "retrieval_role_arn": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.All( - validation.StringLenBetween(20, 2048), - ), + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, }, - "validators": { - Type: schema.TypeList, + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), + "validator": { + Type: schema.TypeSet, 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: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.Any( + validation.StringIsJSON, + validateArn, ), + DiffSuppressFunc: suppressEquivalentJsonDiffs, }, "type": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "JSON_SCHEMA", "LAMBDA", - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appconfig.ValidatorType_Values(), false), }, }, }, }, - "tags": tagsSchema(), - "arn": { - Type: schema.TypeString, - Computed: true, - }, }, + CustomizeDiff: SetTagsDiff, } } func resourceAwsAppconfigConfigurationProfileCreate(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{}))) + + appId := d.Get("application_id").(string) + name := d.Get("name").(string) input := &appconfig.CreateConfigurationProfileInput{ - Name: aws.String(d.Get("name").(string)), - Description: aws.String(d.Get("description").(string)), + ApplicationId: aws.String(appId), 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(), + Name: aws.String(name), + Tags: tags.IgnoreAws().AppconfigTags(), } - if retrievalRoleARN := d.Get("retrieval_role_arn").(string); retrievalRoleARN != "" { - input.RetrievalRoleArn = aws.String(retrievalRoleARN) + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) } - profile, err := conn.CreateConfigurationProfile(input) - if err != nil { - return fmt.Errorf("Error creating AppConfig ConfigurationProfile: %s", err) + if v, ok := d.GetOk("retrieval_role_arn"); ok { + input.RetrievalRoleArn = aws.String(v.(string)) } - d.SetId(aws.StringValue(profile.Id)) + if v, ok := d.GetOk("validator"); ok && v.(*schema.Set).Len() > 0 { + input.Validators = expandAppconfigValidators(v.(*schema.Set).List()) + } - return resourceAwsAppconfigConfigurationProfileRead(d, meta) -} + profile, err := conn.CreateConfigurationProfile(input) -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)), - } + if err != nil { + return fmt.Errorf("error creating AppConfig Configuration Profile (%s) for Application (%s): %w", name, appId, err) } - 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), - } + if profile == nil { + return fmt.Errorf("error creating AppConfig Configuration Profile (%s) for Application (%s): empty response", name, appId) } - return list + + d.SetId(fmt.Sprintf("%s:%s", aws.StringValue(profile.Id), aws.StringValue(profile.ApplicationId))) + + return resourceAwsAppconfigConfigurationProfileRead(d, meta) } func resourceAwsAppconfigConfigurationProfileRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - appID := d.Get("application_id").(string) + confProfID, appID, err := resourceAwsAppconfigConfigurationProfileParseID(d.Id()) + + if err != nil { + return err + } input := &appconfig.GetConfigurationProfileInput{ ApplicationId: aws.String(appID), - ConfigurationProfileId: aws.String(d.Id()), + ConfigurationProfileId: aws.String(confProfID), } 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()) + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { + log.Printf("[WARN] AppConfig Configuration Profile (%s) for Application (%s) not found, removing from state", confProfID, appID) d.SetId("") return nil } if err != nil { - return fmt.Errorf("error getting AppConfig ConfigurationProfile (%s): %s", d.Id(), err) + return fmt.Errorf("error getting AppConfig Configuration Profile (%s) for Application (%s): %w", confProfID, appID, err) } if output == nil { - return fmt.Errorf("error getting AppConfig ConfigurationProfile (%s): empty response", d.Id()) + return fmt.Errorf("error getting AppConfig Configuration Profile (%s) for Application (%s): empty response", confProfID, appID) } - d.Set("name", output.Name) - d.Set("description", output.Description) d.Set("application_id", output.ApplicationId) + d.Set("configuration_profile_id", output.Id) + d.Set("description", output.Description) d.Set("location_uri", output.LocationUri) + d.Set("name", output.Name) + d.Set("retrieval_role_arn", output.RetrievalRoleArn) - d.Set("validators", flattenAwsAppconfigValidators(output.Validators)) - profileARN := arn.ARN{ + if err := d.Set("validator", flattenAwsAppconfigValidators(output.Validators)); err != nil { + return fmt.Errorf("error setting validator: %w", err) + } + + arn := arn.ARN{ AccountID: meta.(*AWSClient).accountid, Partition: meta.(*AWSClient).partition, Region: meta.(*AWSClient).region, - Resource: fmt.Sprintf("application/%s/configurationprofile/%s", appID, d.Id()), + Resource: fmt.Sprintf("application/%s/configurationprofile/%s", appID, confProfID), Service: "appconfig", }.String() - d.Set("arn", profileARN) - tags, err := keyvaluetags.AppconfigListTags(conn, profileARN) + d.Set("arn", arn) + + tags, err := keyvaluetags.AppconfigListTags(conn, arn) + if err != nil { - return fmt.Errorf("error getting tags for AppConfig ConfigurationProfile (%s): %s", d.Id(), err) + return fmt.Errorf("error listing tags for AppConfig Configuration Profile (%s): %w", d.Id(), err) } - if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %s", 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_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) } return nil @@ -200,37 +211,46 @@ func resourceAwsAppconfigConfigurationProfileRead(d *schema.ResourceData, meta i 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.HasChangesExcept("tags", "tags_all") { + confProfID, appID, err := resourceAwsAppconfigConfigurationProfileParseID(d.Id()) - if d.HasChange("description") { - updateInput.Description = aws.String(d.Get("description").(string)) - } + if err != nil { + return err + } - if d.HasChange("name") { - updateInput.Name = aws.String(d.Get("name").(string)) - } + updateInput := &appconfig.UpdateConfigurationProfileInput{ + ApplicationId: aws.String(appID), + ConfigurationProfileId: aws.String(confProfID), + } - if d.HasChange("retrieval_role_arn") { - updateInput.RetrievalRoleArn = aws.String(d.Get("retrieval_role_arn").(string)) - } + if d.HasChange("description") { + updateInput.Description = aws.String(d.Get("description").(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) + if d.HasChange("name") { + updateInput.Name = aws.String(d.Get("name").(string)) } - } - if d.HasChange("validators") { - updateInput.Validators = expandAppconfigValidators(d.Get("validators").([]interface{})) + if d.HasChange("retrieval_role_arn") { + updateInput.RetrievalRoleArn = aws.String(d.Get("retrieval_role_arn").(string)) + } + + if d.HasChange("validator") { + updateInput.Validators = expandAppconfigValidators(d.Get("validator").(*schema.Set).List()) + } + + _, err = conn.UpdateConfigurationProfile(updateInput) + + if err != nil { + return fmt.Errorf("error updating AppConfig Configuration Profile (%s) for Application (%s): %w", confProfID, appID, err) + } } - _, err := conn.UpdateConfigurationProfile(updateInput) - if err != nil { - return fmt.Errorf("error updating AppConfig ConfigurationProfile (%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 Configuration Profile (%s) tags: %w", d.Get("arn").(string), err) + } } return resourceAwsAppconfigConfigurationProfileRead(d, meta) @@ -239,32 +259,115 @@ func resourceAwsAppconfigConfigurationProfileUpdate(d *schema.ResourceData, meta func resourceAwsAppconfigConfigurationProfileDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appconfigconn + confProfID, appID, err := resourceAwsAppconfigConfigurationProfileParseID(d.Id()) + + if err != nil { + return err + } + input := &appconfig.DeleteConfigurationProfileInput{ - ConfigurationProfileId: aws.String(d.Id()), - ApplicationId: aws.String(d.Get("application_id").(string)), + ApplicationId: aws.String(appID), + ConfigurationProfileId: aws.String(confProfID), } - _, err := conn.DeleteConfigurationProfile(input) + _, err = conn.DeleteConfigurationProfile(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { return nil } if err != nil { - return fmt.Errorf("error deleting Appconfig ConfigurationProfile (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting AppConfig Configuration Profile (%s) for Application (%s): %w", confProfID, appID, 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()) +func resourceAwsAppconfigConfigurationProfileParseID(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 configurationProfileID:applicationID", id) + } + + return parts[0], parts[1], nil +} + +func expandAppconfigValidator(tfMap map[string]interface{}) *appconfig.Validator { + if tfMap == nil { + return nil + } + + validator := &appconfig.Validator{} + + // AppConfig API supports empty content + if v, ok := tfMap["content"].(string); ok { + validator.Content = aws.String(v) + } + + if v, ok := tfMap["type"].(string); ok && v != "" { + validator.Type = aws.String(v) + } + + return validator +} + +func expandAppconfigValidators(tfList []interface{}) []*appconfig.Validator { + // AppConfig API requires a 0 length slice instead of a nil value + // when updating from N validators to 0/nil validators + validators := make([]*appconfig.Validator, 0) + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + + if !ok { + continue + } + + validator := expandAppconfigValidator(tfMap) + + if validator == nil { + continue + } + + validators = append(validators, validator) } - d.SetId(parts[1]) - d.Set("application_id", parts[0]) + return validators +} + +func flattenAwsAppconfigValidator(validator *appconfig.Validator) map[string]interface{} { + if validator == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := validator.Content; v != nil { + tfMap["content"] = aws.StringValue(v) + } + + if v := validator.Type; v != nil { + tfMap["type"] = aws.StringValue(v) + } + + return tfMap +} + +func flattenAwsAppconfigValidators(validators []*appconfig.Validator) []interface{} { + if len(validators) == 0 { + return nil + } + + var tfList []interface{} + + for _, validator := range validators { + if validator == nil { + continue + } + + tfList = append(tfList, flattenAwsAppconfigValidator(validator)) + } - return []*schema.ResourceData{d}, nil + return tfList } diff --git a/aws/resource_aws_appconfig_configuration_profile_test.go b/aws/resource_aws_appconfig_configuration_profile_test.go index f594dad9bf63..23d98c250e98 100644 --- a/aws/resource_aws_appconfig_configuration_profile_test.go +++ b/aws/resource_aws_appconfig_configuration_profile_test.go @@ -2,20 +2,22 @@ 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 TestAccAWSAppConfigConfigurationProfile_basic(t *testing.T) { - var profile appconfig.GetConfigurationProfileOutput - profileName := acctest.RandomWithPrefix("tf-acc-test") - profileDesc := acctest.RandomWithPrefix("desc") + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_configuration_profile.test" + appResourceName := "aws_appconfig_application.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, appconfig.EndpointsID), @@ -23,18 +25,20 @@ func TestAccAWSAppConfigConfigurationProfile_basic(t *testing.T) { CheckDestroy: testAccCheckAppConfigConfigurationProfileDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAppConfigConfigurationProfile(profileName, profileDesc), + Config: testAccAWSAppConfigConfigurationProfileConfigName(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigConfigurationProfileExists(resourceName, &profile), - resource.TestCheckResourceAttr(resourceName, "name", profileName), - testAccCheckAWSAppConfigConfigurationProfileARN(resourceName, &profile), + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "appconfig", regexp.MustCompile(`application/[a-z0-9]{4,7}/configurationprofile/[a-z0-9]{4,7}`)), + resource.TestCheckResourceAttrPair(resourceName, "application_id", appResourceName, "id"), + resource.TestMatchResourceAttr(resourceName, "configuration_profile_id", regexp.MustCompile(`[a-z0-9]{4,7}`)), + resource.TestCheckResourceAttr(resourceName, "location_uri", "hosted"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "validator.#", "0"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - resource.TestCheckResourceAttr(resourceName, "description", profileDesc), ), }, { ResourceName: resourceName, - ImportStateIdFunc: testAccAWSAppConfigConfigurationProfileImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -43,10 +47,7 @@ func TestAccAWSAppConfigConfigurationProfile_basic(t *testing.T) { } func TestAccAWSAppConfigConfigurationProfile_disappears(t *testing.T) { - var profile appconfig.GetConfigurationProfileOutput - - profileName := acctest.RandomWithPrefix("tf-acc-test") - profileDesc := acctest.RandomWithPrefix("desc") + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_configuration_profile.test" resource.ParallelTest(t, resource.TestCase{ @@ -56,10 +57,10 @@ func TestAccAWSAppConfigConfigurationProfile_disappears(t *testing.T) { CheckDestroy: testAccCheckAppConfigConfigurationProfileDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSAppConfigConfigurationProfile(profileName, profileDesc), + Config: testAccAWSAppConfigConfigurationProfileConfigName(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigConfigurationProfileExists(resourceName, &profile), - testAccCheckAWSAppConfigConfigurationProfileDisappears(&profile), + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + testAccCheckResourceDisappears(testAccProvider, resourceAwsAppconfigConfigurationProfile(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -67,9 +68,205 @@ func TestAccAWSAppConfigConfigurationProfile_disappears(t *testing.T) { }) } -func TestAccAWSAppConfigConfigurationProfile_Tags(t *testing.T) { - var profile appconfig.GetConfigurationProfileOutput +func TestAccAWSAppConfigConfigurationProfile_Validators_JSON(t *testing.T) { + 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: testAccAWSAppConfigConfigurationProfileConfigValidator_JSON(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "validator.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "validator.*", map[string]string{ + "type": appconfig.ValidatorTypeJsonSchema, + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigConfigurationProfileConfigValidator_NoJSONContent(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "validator.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "validator.*", map[string]string{ + "content": "", + "type": appconfig.ValidatorTypeJsonSchema, + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Validator Removal + Config: testAccAWSAppConfigConfigurationProfileConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "validator.#", "0"), + ), + }, + }, + }) +} + +func TestAccAWSAppConfigConfigurationProfile_Validators_Lambda(t *testing.T) { + 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: testAccAWSAppConfigConfigurationProfileConfigValidator_Lambda(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "validator.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "validator.*.content", "aws_lambda_function.test", "arn"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "validator.*", map[string]string{ + "type": appconfig.ValidatorTypeLambda, + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Validator Removal + Config: testAccAWSAppConfigConfigurationProfileConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "validator.#", "0"), + ), + }, + }, + }) +} + +func TestAccAWSAppConfigConfigurationProfile_Validators_Multiple(t *testing.T) { + 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: testAccAWSAppConfigConfigurationProfileConfigValidator_Multiple(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "validator.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "validator.*", map[string]string{ + "content": "{\"$schema\":\"http://json-schema.org/draft-05/schema#\",\"description\":\"BasicFeatureToggle-1\",\"title\":\"$id$\"}", + "type": appconfig.ValidatorTypeJsonSchema, + }), + resource.TestCheckTypeSetElemAttrPair(resourceName, "validator.*.content", "aws_lambda_function.test", "arn"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "validator.*", map[string]string{ + "type": appconfig.ValidatorTypeLambda, + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigConfigurationProfile_updateName(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + rNameUpdated := acctest.RandomWithPrefix("tf-acc-test-update") + 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: testAccAWSAppConfigConfigurationProfileConfigName(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", rName), + ), + }, + { + Config: testAccAWSAppConfigConfigurationProfileConfigName(rNameUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "name", rNameUpdated), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigConfigurationProfile_updateDescription(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + description := acctest.RandomWithPrefix("tf-acc-test-update") + 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: testAccAWSAppConfigConfigurationProfileConfigDescription(rName, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", rName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSAppConfigConfigurationProfileConfigDescription(rName, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "description", description), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSAppConfigConfigurationProfile_Tags(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appconfig_configuration_profile.test" @@ -82,21 +279,20 @@ func TestAccAWSAppConfigConfigurationProfile_Tags(t *testing.T) { { Config: testAccAWSAppConfigConfigurationProfileTags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigConfigurationProfileExists(resourceName, &profile), + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), 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), + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), @@ -105,7 +301,7 @@ func TestAccAWSAppConfigConfigurationProfile_Tags(t *testing.T) { { Config: testAccAWSAppConfigConfigurationProfileTags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAppConfigConfigurationProfileExists(resourceName, &profile), + testAccCheckAWSAppConfigConfigurationProfileExists(resourceName), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), @@ -122,43 +318,36 @@ func testAccCheckAppConfigConfigurationProfileDestroy(s *terraform.State) error continue } + confProfID, appID, err := resourceAwsAppconfigConfigurationProfileParseID(rs.Primary.ID) + + if err != nil { + return err + } + input := &appconfig.GetConfigurationProfileInput{ - ApplicationId: aws.String(rs.Primary.Attributes["application_id"]), - ConfigurationProfileId: aws.String(rs.Primary.ID), + ApplicationId: aws.String(appID), + ConfigurationProfileId: aws.String(confProfID), } output, err := conn.GetConfigurationProfile(input) - if isAWSErr(err, appconfig.ErrCodeResourceNotFoundException, "") { + if tfawserr.ErrCodeEquals(err, appconfig.ErrCodeResourceNotFoundException) { continue } if err != nil { - return err + return fmt.Errorf("error reading AppConfig Configuration Profile (%s) for Application (%s): %w", confProfID, appID, err) } if output != nil { - return fmt.Errorf("AppConfig ConfigurationProfile (%s) still exists", rs.Primary.ID) + return fmt.Errorf("AppConfig Configuration Profile (%s) for Application (%s) still exists", confProfID, appID) } } 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 { +func testAccCheckAWSAppConfigConfigurationProfileExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -169,39 +358,66 @@ func testAccCheckAWSAppConfigConfigurationProfileExists(resourceName string, pro return fmt.Errorf("Resource (%s) ID not set", resourceName) } + confProfID, appID, err := resourceAwsAppconfigConfigurationProfileParseID(rs.Primary.ID) + + if err != nil { + return err + } + 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), + ApplicationId: aws.String(appID), + ConfigurationProfileId: aws.String(confProfID), }) + if err != nil { - return err + return fmt.Errorf("error reading AppConfig Configuration Profile (%s) for Application (%s): %w", confProfID, appID, err) } - *profile = *output + if output == nil { + return fmt.Errorf("AppConfig Configuration Profile (%s) for Application (%s) not found", confProfID, appID) + } 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 testAccAWSAppConfigConfigurationProfileConfigName(rName string) string { + return composeConfig( + testAccAWSAppConfigApplicationConfigName(rName), + fmt.Sprintf(` +resource "aws_appconfig_configuration_profile" "test" { + application_id = aws_appconfig_application.test.id + name = %q + location_uri = "hosted" +} +`, rName)) } -func testAccAWSAppConfigConfigurationProfile(profileName, profileDesc string) string { - appName := acctest.RandomWithPrefix("tf-acc-test") - appDesc := acctest.RandomWithPrefix("desc") - return testAccAWSAppConfigApplicationConfigDescription(appName, appDesc) + fmt.Sprintf(` +func testAccAWSAppConfigConfigurationProfileConfigDescription(rName, description string) string { + return composeConfig( + testAccAWSAppConfigApplicationConfigDescription(rName, description), + fmt.Sprintf(` resource "aws_appconfig_configuration_profile" "test" { + application_id = aws_appconfig_application.test.id name = %[1]q description = %[2]q + location_uri = "hosted" +} +`, rName, description)) +} + +func testAccAWSAppConfigConfigurationProfileConfigValidator_JSON(rName string) string { + return composeConfig( + testAccAWSAppConfigApplicationConfigName(rName), + fmt.Sprintf(` +resource "aws_appconfig_configuration_profile" "test" { application_id = aws_appconfig_application.test.id + name = %q location_uri = "hosted" - validators { - type = "JSON_SCHEMA" + + validator { content = jsonencode({ "$schema" = "http://json-schema.org/draft-04/schema#" title = "$id$" @@ -215,47 +431,138 @@ resource "aws_appconfig_configuration_profile" "test" { } minProperties = 1 }) + + type = "JSON_SCHEMA" } } -`, profileName, profileDesc) +`, rName)) } -func testAccAWSAppConfigConfigurationProfileTags1(rName, tagKey1, tagValue1 string) string { - return testAccAWSAppConfigApplicationTags1(rName, tagKey1, tagValue1) + fmt.Sprintf(` +func testAccAWSAppConfigConfigurationProfileConfigValidator_NoJSONContent(rName string) string { + return composeConfig( + testAccAWSAppConfigApplicationConfigName(rName), + fmt.Sprintf(` +resource "aws_appconfig_configuration_profile" "test" { + application_id = aws_appconfig_application.test.id + name = %q + location_uri = "hosted" + + validator { + type = "JSON_SCHEMA" + } +} +`, rName)) +} + +func testAccAWSAppConfigApplicationConfigLambdaBase(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "lambda" { + name = "%[1]s-lambda" + + assume_role_policy = <` or the Amazon Resource Name (ARN). For a parameter, specify either the parameter name in the format `ssm-parameter://` or the ARN. For an Amazon S3 object, specify the URI in the following format: `s3:///`. +* `name` - (Required) The name for the configuration profile. Must be between 1 and 64 characters in length. +* `description` - (Optional) The description of the configuration profile. Can be at most 1024 characters. +* `retrieval_role_arn` - (Optional) The ARN of an IAM role with permission to access the configuration at the specified `location_uri`. A retrieval role ARN is not required for configurations stored in the AWS AppConfig `hosted` configuration store. It is required for all other sources that store your configuration. +* `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. +* `validator` - (Optional) A set of methods for validating the configuration. Maximum of 2. See [Validator](#validator) below for more details. + +### Validator -### validator +The `validator` block supports the following: -- `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` +* `content` - (Optional, Required when `type` is `LAMBDA`) Either the JSON Schema content or the Amazon Resource Name (ARN) of an AWS Lambda function. +* `type` - (Optional) The type of validator. Valid values: `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 +* `arn` - The Amazon Resource Name (ARN) of the AppConfig Configuration Profile. +* `configuration_profile_id` - The configuration profile ID. +* `id` - The AppConfig configuration profile ID and application ID separated by a colon (`:`). +* `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_configuration_profile` can be imported by the Application ID and Configuration Profile ID, e.g. +AppConfig Configuration Profiles can be imported by using the configuration profile ID and application ID separated by a colon (`:`), e.g. ``` -$ terraform import aws_appconfig_configuration_profile.test 71abcde/11xxxxx +$ terraform import aws_appconfig_configuration_profile.example 71abcde:11xxxxx ``` From 9ed0d31da9dee9652bbbd82c6dacaf81303b7c2d Mon Sep 17 00:00:00 2001 From: Andy Richardson Date: Mon, 12 Jul 2021 11:37:08 +0100 Subject: [PATCH 1125/1208] Amend misleading module name --- website/docs/r/lambda_function.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/lambda_function.html.markdown b/website/docs/r/lambda_function.html.markdown index 3a41dc3f529c..f9266d2371b4 100644 --- a/website/docs/r/lambda_function.html.markdown +++ b/website/docs/r/lambda_function.html.markdown @@ -47,7 +47,7 @@ resource "aws_lambda_function" "test_lambda" { filename = "lambda_function_payload.zip" function_name = "lambda_function_name" role = aws_iam_role.iam_for_lambda.arn - handler = "exports.test" + handler = "index.test" # The filebase64sha256() function is available in Terraform 0.11.12 and later # For Terraform 0.11.11 and earlier, use the base64sha256() function and the file() function: From f97a52e4e2a55da63e8cd101d63f095266243c23 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 12 Jul 2021 09:28:04 -0400 Subject: [PATCH 1126/1208] Fix 'terrafmt' errors. --- ...e_aws_dx_gateway_association_proposal_test.go | 16 ++++++++-------- aws/resource_aws_dx_gateway_association_test.go | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association_proposal_test.go b/aws/resource_aws_dx_gateway_association_proposal_test.go index 5cc620a05208..02c976285edf 100644 --- a/aws/resource_aws_dx_gateway_association_proposal_test.go +++ b/aws/resource_aws_dx_gateway_association_proposal_test.go @@ -416,11 +416,11 @@ func testAccDxGatewayAssociationProposalConfig_endOfLifeVpn(rName string, rBgpAs data "aws_caller_identity" "current" {} resource "aws_dx_gateway_association" "test" { -provider = "awsalternate" + provider = "awsalternate" -proposal_id = aws_dx_gateway_association_proposal.test.id -dx_gateway_id = aws_dx_gateway.test.id -associated_gateway_owner_account_id = data.aws_caller_identity.current.account_id + proposal_id = aws_dx_gateway_association_proposal.test.id + dx_gateway_id = aws_dx_gateway.test.id + associated_gateway_owner_account_id = data.aws_caller_identity.current.account_id } `) } @@ -430,11 +430,11 @@ func testAccDxGatewayAssociationProposalConfig_endOfLifeTgw(rName string, rBgpAs data "aws_caller_identity" "current" {} resource "aws_dx_gateway_association" "test" { -provider = "awsalternate" + provider = "awsalternate" -proposal_id = aws_dx_gateway_association_proposal.test.id -dx_gateway_id = aws_dx_gateway.test.id -associated_gateway_owner_account_id = data.aws_caller_identity.current.account_id + proposal_id = aws_dx_gateway_association_proposal.test.id + dx_gateway_id = aws_dx_gateway.test.id + associated_gateway_owner_account_id = data.aws_caller_identity.current.account_id } `) } diff --git a/aws/resource_aws_dx_gateway_association_test.go b/aws/resource_aws_dx_gateway_association_test.go index 9a72d222fea8..8d324e0c4828 100644 --- a/aws/resource_aws_dx_gateway_association_test.go +++ b/aws/resource_aws_dx_gateway_association_test.go @@ -711,10 +711,10 @@ resource "aws_dx_gateway_association_proposal" "test" { } resource "aws_dx_gateway_association_proposal" "test2" { - dx_gateway_id = aws_dx_gateway.test.id - dx_gateway_owner_account_id = aws_dx_gateway.test.owner_account_id - associated_gateway_id = aws_vpn_gateway_attachment.test.vpn_gateway_id - } + dx_gateway_id = aws_dx_gateway.test.id + dx_gateway_owner_account_id = aws_dx_gateway.test.owner_account_id + associated_gateway_id = aws_vpn_gateway_attachment.test.vpn_gateway_id +} # Accepter resource "aws_dx_gateway_association" "test" { From dceee240f1466a3faff1adce7c64a7e0ea411da8 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Mon, 12 Jul 2021 09:52:01 -0400 Subject: [PATCH 1127/1208] 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 000000000000..14d91b6069a8 --- /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 c060a2549173..f8570bba6aac 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 6a17f2120125..585b468fe782 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 413b95f8f941..14f4d67513e9 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 f7471fe0331d..f9c0507c01e7 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 8215e67cf9ac..f08738cfb8d4 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 018261ceed2c..9f38e67fa0f5 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 1482f5ecb801..a898309c10fe 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 ``` From a96caa6c31d68ec18ac23f3e4c90d38af8c8381e Mon Sep 17 00:00:00 2001 From: changelogbot Date: Mon, 12 Jul 2021 14:05:17 +0000 Subject: [PATCH 1128/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c4e572644d1..4b53ab33ee1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,23 @@ ## 3.50.0 (Unreleased) +NOTES: + +* resource/aws_dx_gateway_association_proposal: If an accepted Proposal reaches end-of-life and is removed by AWS do not recreate the resource, instead refreshing Terraform state from the resource's Direct Connect Gateway ID and Associated Gateway ID. ([#19741](https://github.com/hashicorp/terraform-provider-aws/issues/19741)) + FEATURES: +* **New Resource:** `aws_appconfig_application` ([#19307](https://github.com/hashicorp/terraform-provider-aws/issues/19307)) +* **New Resource:** `aws_appconfig_configuration_profile` ([#19320](https://github.com/hashicorp/terraform-provider-aws/issues/19320)) +* **New Resource:** `aws_appconfig_environment` ([#19307](https://github.com/hashicorp/terraform-provider-aws/issues/19307)) * **New Resource:** `aws_config_organization_conformance_pack` ([#17298](https://github.com/hashicorp/terraform-provider-aws/issues/17298)) ENHANCEMENTS: +* resource/aws_cloudwatch_event_target: Add `enable_ecs_managed_tags`, `enable_execute_command`, `placement_constraints`, `propagate_tags`, and `tags` arguments to `ecs_target` block. ([#19975](https://github.com/hashicorp/terraform-provider-aws/issues/19975)) * resource/aws_cognito_user_pool_client: Add the `enable_token_revocation` argument to support targeted sign out ([#20031](https://github.com/hashicorp/terraform-provider-aws/issues/20031)) * resource/aws_fsx_windows_file_system: Add `aliases` argument ([#20054](https://github.com/hashicorp/terraform-provider-aws/issues/20054)) * resource/aws_guardduty_detector: Add `datasources` argument ([#19954](https://github.com/hashicorp/terraform-provider-aws/issues/19954)) +* resource/aws_guardduty_organization_configuration: Add `datasources` argument ([#15241](https://github.com/hashicorp/terraform-provider-aws/issues/15241)) BUG FIXES: From ae6e0e799d6a76ff51313b7b66d48b8e305bf779 Mon Sep 17 00:00:00 2001 From: Shunsuke Suzuki Date: Thu, 13 May 2021 21:38:03 +0900 Subject: [PATCH 1129/1208] 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 f8570bba6aac..724c08aa80d9 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 000000000000..089701267cb9 --- /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 1130/1208] 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 000000000000..dff2ded40737 --- /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 1131/1208] 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 000000000000..44cdab9665fc --- /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 1132/1208] 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 000000000000..d79ead839742 --- /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 1133/1208] 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 724c08aa80d9..bd2642be4db3 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 1134/1208] 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 44cdab9665fc..d34ad401e860 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 1135/1208] 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 d34ad401e860..a024b5a73064 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 1136/1208] 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 089701267cb9..5f4140ecd67f 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 a024b5a73064..053a36d05c94 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 9f38e67fa0f5..570f08ad738d 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 dff2ded40737..139672745bd3 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 ``` From 5bb708888ebcddf2884f0bcabb5f21faa8df05a0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 14:41:45 -0400 Subject: [PATCH 1137/1208] r/s3_bucket: Add delete_marker_replication_status argument --- aws/resource_aws_s3_bucket.go | 65 +++++++++++------------------------ 1 file changed, 20 insertions(+), 45 deletions(-) diff --git a/aws/resource_aws_s3_bucket.go b/aws/resource_aws_s3_bucket.go index 839a64a46f0c..accb259dd5ff 100644 --- a/aws/resource_aws_s3_bucket.go +++ b/aws/resource_aws_s3_bucket.go @@ -524,20 +524,10 @@ func resourceAwsS3Bucket() *schema.Resource { }, }, }, - "delete_marker_replication": { - Type: schema.TypeList, - Optional: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "status": { - Type: schema.TypeString, - Optional: true, - Default: s3.DeleteMarkerReplicationStatusDisabled, - }, - }, - }, + "delete_marker_replication_status": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{s3.DeleteMarkerReplicationStatusEnabled}, false), }, }, }, @@ -2125,18 +2115,21 @@ func resourceAwsS3BucketReplicationConfigurationUpdate(s3conn *s3.S3, d *schema. rcRule.Filter.Prefix = aws.String(filter["prefix"].(string)) } + if dmr, ok := rr["delete_marker_replication_status"].(string); ok && dmr != "" { + rcRule.DeleteMarkerReplication = &s3.DeleteMarkerReplication{ + Status: aws.String(dmr), + } + } else { + rcRule.DeleteMarkerReplication = &s3.DeleteMarkerReplication{ + Status: aws.String(s3.DeleteMarkerReplicationStatusDisabled), + } + } + } else { // XML schema V1. rcRule.Prefix = aws.String(rr["prefix"].(string)) } - if d, ok := rr["delete_marker_replication"].([]interface{}); ok && len(d) > 0 && d[0] != nil { - dmr := d[0].(map[string]interface{}) - rcRule.DeleteMarkerReplication = &s3.DeleteMarkerReplication{ - Status: aws.String(dmr["status"].(string)), - } - } - rules = append(rules, rcRule) } @@ -2427,14 +2420,10 @@ func flattenAwsS3BucketReplicationConfiguration(r *s3.ReplicationConfiguration) m["tags"] = keyvaluetags.S3KeyValueTags(a.Tags).IgnoreAws().Map() } t["filter"] = []interface{}{m} - } - if dmr := v.DeleteMarkerReplication; dmr != nil { - m := map[string]interface{}{} - if dmr.Status != nil { - m["status"] = aws.StringValue(v.DeleteMarkerReplication.Status) + if v.DeleteMarkerReplication != nil && v.DeleteMarkerReplication.Status != nil && aws.StringValue(v.DeleteMarkerReplication.Status) == s3.DeleteMarkerReplicationStatusEnabled { + t["delete_marker_replication_status"] = aws.StringValue(v.DeleteMarkerReplication.Status) } - t["delete_marker_replication"] = []interface{}{m} } rules = append(rules, t) @@ -2602,11 +2591,12 @@ func rulesHash(v interface{}) int { if v, ok := m["priority"]; ok { buf.WriteString(fmt.Sprintf("%d-", v.(int))) } - if v, ok := m["delete_marker_replication"].([]interface{}); ok && len(v) > 0 && v[0] != nil { - buf.WriteString(fmt.Sprintf("%d-", deleteMarkerReplicationHash(v[0]))) - } if v, ok := m["filter"].([]interface{}); ok && len(v) > 0 && v[0] != nil { buf.WriteString(fmt.Sprintf("%d-", replicationRuleFilterHash(v[0]))) + + if v, ok := m["delete_marker_replication_status"]; ok && v.(string) == s3.DeleteMarkerReplicationStatusEnabled { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } } return hashcode.String(buf.String()) } @@ -2628,21 +2618,6 @@ func replicationRuleFilterHash(v interface{}) int { return hashcode.String(buf.String()) } -func deleteMarkerReplicationHash(v interface{}) int { - var buf bytes.Buffer - m, ok := v.(map[string]interface{}) - - if !ok { - return 0 - } - - if v, ok := m["status"]; ok { - buf.WriteString(fmt.Sprintf("%s-", v.(string))) - } - - return hashcode.String(buf.String()) -} - func destinationHash(v interface{}) int { var buf bytes.Buffer m, ok := v.(map[string]interface{}) From 74b57c254e78e8bfb30d1a1e02c77ba192b42e39 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 14:42:10 -0400 Subject: [PATCH 1138/1208] tests/r/s3_bucket: Add delete_marker_replication_status argument --- aws/resource_aws_s3_bucket_test.go | 120 ++++++++++++----------------- 1 file changed, 51 insertions(+), 69 deletions(-) diff --git a/aws/resource_aws_s3_bucket_test.go b/aws/resource_aws_s3_bucket_test.go index cf31272e75f6..6fa9c61fb78c 100644 --- a/aws/resource_aws_s3_bucket_test.go +++ b/aws/resource_aws_s3_bucket_test.go @@ -164,7 +164,7 @@ func testS3BucketObjectLockEnabled(conn *s3.S3, bucket string) (bool, error) { return aws.StringValue(output.ObjectLockConfiguration.ObjectLockEnabled) == s3.ObjectLockEnabledEnabled, nil } -func TestAccAWSS3Bucket_basic(t *testing.T) { +func TestAccAWSS3Bucket_Basic_basic(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") region := testAccGetRegion() hostedZoneID, _ := HostedZoneIDForRegion(region) @@ -201,7 +201,7 @@ func TestAccAWSS3Bucket_basic(t *testing.T) { // Support for common Terraform 0.11 pattern // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/7868 -func TestAccAWSS3Bucket_Bucket_EmptyString(t *testing.T) { +func TestAccAWSS3Bucket_Basic_emptyString(t *testing.T) { resourceName := "aws_s3_bucket.test" resource.ParallelTest(t, resource.TestCase{ @@ -227,7 +227,7 @@ func TestAccAWSS3Bucket_Bucket_EmptyString(t *testing.T) { }) } -func TestAccAWSS3Bucket_tagsWithNoSystemTags(t *testing.T) { +func TestAccAWSS3Bucket_Tags_withNoSystemTags(t *testing.T) { resourceName := "aws_s3_bucket.bucket" bucketName := acctest.RandomWithPrefix("tf-test-bucket") @@ -286,7 +286,7 @@ func TestAccAWSS3Bucket_tagsWithNoSystemTags(t *testing.T) { }) } -func TestAccAWSS3Bucket_tagsWithSystemTags(t *testing.T) { +func TestAccAWSS3Bucket_Tags_withSystemTags(t *testing.T) { resourceName := "aws_s3_bucket.bucket" bucketName := acctest.RandomWithPrefix("tf-test-bucket") @@ -371,7 +371,7 @@ func TestAccAWSS3Bucket_tagsWithSystemTags(t *testing.T) { }) } -func TestAccAWSS3Bucket_ignoreTags(t *testing.T) { +func TestAccAWSS3Bucket_Tags_ignoreTags(t *testing.T) { resourceName := "aws_s3_bucket.bucket" bucketName := acctest.RandomWithPrefix("tf-acc-test") @@ -416,7 +416,7 @@ func TestAccAWSS3Bucket_ignoreTags(t *testing.T) { }) } -func TestAccAWSS3Bucket_withTags(t *testing.T) { +func TestAccAWSS3Bucket_Tags_basic(t *testing.T) { rInt := acctest.RandInt() resourceName := "aws_s3_bucket.bucket1" @@ -439,7 +439,7 @@ func TestAccAWSS3Bucket_withTags(t *testing.T) { }) } -func TestAccAWSS3Bucket_namePrefix(t *testing.T) { +func TestAccAWSS3Bucket_Basic_namePrefix(t *testing.T) { resourceName := "aws_s3_bucket.test" resource.ParallelTest(t, resource.TestCase{ @@ -465,7 +465,7 @@ func TestAccAWSS3Bucket_namePrefix(t *testing.T) { }) } -func TestAccAWSS3Bucket_generatedName(t *testing.T) { +func TestAccAWSS3Bucket_Basic_generatedName(t *testing.T) { resourceName := "aws_s3_bucket.test" resource.ParallelTest(t, resource.TestCase{ @@ -490,7 +490,7 @@ func TestAccAWSS3Bucket_generatedName(t *testing.T) { }) } -func TestAccAWSS3Bucket_acceleration(t *testing.T) { +func TestAccAWSS3Bucket_Basic_acceleration(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -527,7 +527,7 @@ func TestAccAWSS3Bucket_acceleration(t *testing.T) { }) } -func TestAccAWSS3Bucket_RequestPayer(t *testing.T) { +func TestAccAWSS3Bucket_Basic_requestPayer(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -563,7 +563,7 @@ func TestAccAWSS3Bucket_RequestPayer(t *testing.T) { }) } -func TestAccAWSS3Bucket_Policy(t *testing.T) { +func TestAccAWSS3Bucket_Security_policy(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") partition := testAccGetPartition() resourceName := "aws_s3_bucket.bucket" @@ -615,7 +615,7 @@ func TestAccAWSS3Bucket_Policy(t *testing.T) { }) } -func TestAccAWSS3Bucket_UpdateAcl(t *testing.T) { +func TestAccAWSS3Bucket_Security_updateACL(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -649,7 +649,7 @@ func TestAccAWSS3Bucket_UpdateAcl(t *testing.T) { }) } -func TestAccAWSS3Bucket_UpdateGrant(t *testing.T) { +func TestAccAWSS3Bucket_Security_updateGrant(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -707,7 +707,7 @@ func TestAccAWSS3Bucket_UpdateGrant(t *testing.T) { }) } -func TestAccAWSS3Bucket_AclToGrant(t *testing.T) { +func TestAccAWSS3Bucket_Security_ACLToGrant(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -737,7 +737,7 @@ func TestAccAWSS3Bucket_AclToGrant(t *testing.T) { }) } -func TestAccAWSS3Bucket_GrantToAcl(t *testing.T) { +func TestAccAWSS3Bucket_Security_GrantToACL(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -767,7 +767,7 @@ func TestAccAWSS3Bucket_GrantToAcl(t *testing.T) { }) } -func TestAccAWSS3Bucket_Website_Simple(t *testing.T) { +func TestAccAWSS3Bucket_Web_simple(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") region := testAccGetRegion() resourceName := "aws_s3_bucket.bucket" @@ -812,7 +812,7 @@ func TestAccAWSS3Bucket_Website_Simple(t *testing.T) { }) } -func TestAccAWSS3Bucket_WebsiteRedirect(t *testing.T) { +func TestAccAWSS3Bucket_Web_redirect(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") region := testAccGetRegion() resourceName := "aws_s3_bucket.bucket" @@ -857,7 +857,7 @@ func TestAccAWSS3Bucket_WebsiteRedirect(t *testing.T) { }) } -func TestAccAWSS3Bucket_WebsiteRoutingRules(t *testing.T) { +func TestAccAWSS3Bucket_Web_routingRules(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") region := testAccGetRegion() resourceName := "aws_s3_bucket.bucket" @@ -909,7 +909,7 @@ func TestAccAWSS3Bucket_WebsiteRoutingRules(t *testing.T) { }) } -func TestAccAWSS3Bucket_enableDefaultEncryption_whenTypical(t *testing.T) { +func TestAccAWSS3Bucket_Security_enableDefaultEncryptionWhenTypical(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.arbitrary" @@ -940,7 +940,7 @@ func TestAccAWSS3Bucket_enableDefaultEncryption_whenTypical(t *testing.T) { }) } -func TestAccAWSS3Bucket_enableDefaultEncryption_whenAES256IsUsed(t *testing.T) { +func TestAccAWSS3Bucket_Security_enableDefaultEncryptionWhenAES256IsUsed(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.arbitrary" @@ -971,7 +971,7 @@ func TestAccAWSS3Bucket_enableDefaultEncryption_whenAES256IsUsed(t *testing.T) { }) } -func TestAccAWSS3Bucket_disableDefaultEncryption_whenDefaultEncryptionIsEnabled(t *testing.T) { +func TestAccAWSS3Bucket_Security_disableDefaultEncryptionWhenDefaultEncryptionIsEnabled(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.arbitrary" @@ -1004,7 +1004,7 @@ func TestAccAWSS3Bucket_disableDefaultEncryption_whenDefaultEncryptionIsEnabled( }) } -func TestAccAWSS3Bucket_bucketKeyEnabled(t *testing.T) { +func TestAccAWSS3Bucket_Basic_keyEnabled(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.arbitrary" @@ -1036,10 +1036,10 @@ func TestAccAWSS3Bucket_bucketKeyEnabled(t *testing.T) { }) } -// Test TestAccAWSS3Bucket_shouldFailNotFound is designed to fail with a "plan +// Test TestAccAWSS3Bucket_Basic_shouldFailNotFound is designed to fail with a "plan // not empty" error in Terraform, to check against regresssions. // See https://github.com/hashicorp/terraform/pull/2925 -func TestAccAWSS3Bucket_shouldFailNotFound(t *testing.T) { +func TestAccAWSS3Bucket_Basic_shouldFailNotFound(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -1061,7 +1061,7 @@ func TestAccAWSS3Bucket_shouldFailNotFound(t *testing.T) { }) } -func TestAccAWSS3Bucket_Versioning(t *testing.T) { +func TestAccAWSS3Bucket_Manage_versioning(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -1102,7 +1102,7 @@ func TestAccAWSS3Bucket_Versioning(t *testing.T) { }) } -func TestAccAWSS3Bucket_Cors_Update(t *testing.T) { +func TestAccAWSS3Bucket_Security_corsUpdate(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -1187,7 +1187,7 @@ func TestAccAWSS3Bucket_Cors_Update(t *testing.T) { }) } -func TestAccAWSS3Bucket_Cors_Delete(t *testing.T) { +func TestAccAWSS3Bucket_Security_corsDelete(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -1227,7 +1227,7 @@ func TestAccAWSS3Bucket_Cors_Delete(t *testing.T) { }) } -func TestAccAWSS3Bucket_Cors_EmptyOrigin(t *testing.T) { +func TestAccAWSS3Bucket_Security_corsEmptyOrigin(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -1265,7 +1265,7 @@ func TestAccAWSS3Bucket_Cors_EmptyOrigin(t *testing.T) { }) } -func TestAccAWSS3Bucket_Logging(t *testing.T) { +func TestAccAWSS3Bucket_Security_logging(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -1292,7 +1292,7 @@ func TestAccAWSS3Bucket_Logging(t *testing.T) { }) } -func TestAccAWSS3Bucket_LifecycleBasic(t *testing.T) { +func TestAccAWSS3Bucket_Manage_lifecycleBasic(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -1409,7 +1409,7 @@ func TestAccAWSS3Bucket_LifecycleBasic(t *testing.T) { }) } -func TestAccAWSS3Bucket_LifecycleExpireMarkerOnly(t *testing.T) { +func TestAccAWSS3Bucket_Manage_lifecycleExpireMarkerOnly(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.bucket" @@ -1447,7 +1447,7 @@ func TestAccAWSS3Bucket_LifecycleExpireMarkerOnly(t *testing.T) { } // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/11420 -func TestAccAWSS3Bucket_LifecycleRule_Expiration_EmptyConfigurationBlock(t *testing.T) { +func TestAccAWSS3Bucket_Manage_lifecycleRuleExpirationEmptyConfigurationBlock(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_s3_bucket.bucket" @@ -1468,7 +1468,7 @@ func TestAccAWSS3Bucket_LifecycleRule_Expiration_EmptyConfigurationBlock(t *test } // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/15138 -func TestAccAWSS3Bucket_LifecycleRule_AbortIncompleteMultipartUploadDays_NoExpiration(t *testing.T) { +func TestAccAWSS3Bucket_Manage_lifecycleRuleAbortIncompleteMultipartUploadDaysNoExpiration(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_s3_bucket.bucket" @@ -1494,7 +1494,7 @@ func TestAccAWSS3Bucket_LifecycleRule_AbortIncompleteMultipartUploadDays_NoExpir }) } -func TestAccAWSS3Bucket_Replication(t *testing.T) { +func TestAccAWSS3Bucket_Replication_basic(t *testing.T) { rInt := acctest.RandInt() alternateRegion := testAccGetAlternateRegion() region := testAccGetRegion() @@ -1612,7 +1612,7 @@ func TestAccAWSS3Bucket_Replication(t *testing.T) { }) } -func TestAccAWSS3Bucket_Replication_MultipleDestinations_EmptyFilter(t *testing.T) { +func TestAccAWSS3Bucket_Replication_multipleDestinationsEmptyFilter(t *testing.T) { rInt := acctest.RandInt() alternateRegion := testAccGetAlternateRegion() region := testAccGetRegion() @@ -1679,7 +1679,7 @@ func TestAccAWSS3Bucket_Replication_MultipleDestinations_EmptyFilter(t *testing. }) } -func TestAccAWSS3Bucket_Replication_MultipleDestinations_NonEmptyFilter(t *testing.T) { +func TestAccAWSS3Bucket_Replication_multipleDestinationsNonEmptyFilter(t *testing.T) { rInt := acctest.RandInt() alternateRegion := testAccGetAlternateRegion() region := testAccGetRegion() @@ -1749,7 +1749,7 @@ func TestAccAWSS3Bucket_Replication_MultipleDestinations_NonEmptyFilter(t *testi }) } -func TestAccAWSS3Bucket_Replication_MultipleDestinations_TwoDestination(t *testing.T) { +func TestAccAWSS3Bucket_Replication_twoDestination(t *testing.T) { // This tests 2 destinations since GovCloud and possibly other non-standard partitions allow a max of 2 rInt := acctest.RandInt() alternateRegion := testAccGetAlternateRegion() @@ -1808,7 +1808,7 @@ func TestAccAWSS3Bucket_Replication_MultipleDestinations_TwoDestination(t *testi }) } -func TestAccAWSS3Bucket_ReplicationConfiguration_Rule_Destination_AccessControlTranslation(t *testing.T) { +func TestAccAWSS3Bucket_Replication_configurationRuleDestinationAccessControlTranslation(t *testing.T) { rInt := acctest.RandInt() region := testAccGetRegion() partition := testAccGetPartition() @@ -1901,7 +1901,7 @@ func TestAccAWSS3Bucket_ReplicationConfiguration_Rule_Destination_AccessControlT } // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/12480 -func TestAccAWSS3Bucket_ReplicationConfiguration_Rule_Destination_AddAccessControlTranslation(t *testing.T) { +func TestAccAWSS3Bucket_Replication_configurationRuleDestinationAddAccessControlTranslation(t *testing.T) { rInt := acctest.RandInt() region := testAccGetRegion() partition := testAccGetPartition() @@ -1983,7 +1983,7 @@ func TestAccAWSS3Bucket_ReplicationConfiguration_Rule_Destination_AddAccessContr } // StorageClass issue: https://github.com/hashicorp/terraform/issues/10909 -func TestAccAWSS3Bucket_ReplicationWithoutStorageClass(t *testing.T) { +func TestAccAWSS3Bucket_Replication_withoutStorageClass(t *testing.T) { rInt := acctest.RandInt() alternateRegion := testAccGetAlternateRegion() region := testAccGetRegion() @@ -2019,7 +2019,7 @@ func TestAccAWSS3Bucket_ReplicationWithoutStorageClass(t *testing.T) { }) } -func TestAccAWSS3Bucket_ReplicationExpectVersioningValidationError(t *testing.T) { +func TestAccAWSS3Bucket_Replication_expectVersioningValidationError(t *testing.T) { rInt := acctest.RandInt() // record the initialized providers so that we can use them to check for the instances in each region @@ -2043,7 +2043,7 @@ func TestAccAWSS3Bucket_ReplicationExpectVersioningValidationError(t *testing.T) } // Prefix issue: https://github.com/hashicorp/terraform-provider-aws/issues/6340 -func TestAccAWSS3Bucket_ReplicationWithoutPrefix(t *testing.T) { +func TestAccAWSS3Bucket_Replication_withoutPrefix(t *testing.T) { rInt := acctest.RandInt() alternateRegion := testAccGetAlternateRegion() region := testAccGetRegion() @@ -2079,7 +2079,7 @@ func TestAccAWSS3Bucket_ReplicationWithoutPrefix(t *testing.T) { }) } -func TestAccAWSS3Bucket_ReplicationSchemaV2(t *testing.T) { +func TestAccAWSS3Bucket_Replication_schemaV2(t *testing.T) { rInt := acctest.RandInt() alternateRegion := testAccGetAlternateRegion() region := testAccGetRegion() @@ -2296,7 +2296,7 @@ func TestAccAWSS3Bucket_ReplicationSchemaV2(t *testing.T) { }) } -func TestAccAWSS3Bucket_SameRegionReplicationSchemaV2(t *testing.T) { +func TestAccAWSS3Bucket_Replication_schemaV2SameRegion(t *testing.T) { resourceName := "aws_s3_bucket.bucket" rName := acctest.RandomWithPrefix("tf-acc-test") destinationResourceName := "aws_s3_bucket.destination" @@ -2331,7 +2331,7 @@ func TestAccAWSS3Bucket_SameRegionReplicationSchemaV2(t *testing.T) { }, Priority: aws.Int64(0), DeleteMarkerReplication: &s3.DeleteMarkerReplication{ - Status: aws.String(s3.DeleteMarkerReplicationStatusDisabled), + Status: aws.String(s3.DeleteMarkerReplicationStatusEnabled), }, }, }, @@ -2350,7 +2350,7 @@ func TestAccAWSS3Bucket_SameRegionReplicationSchemaV2(t *testing.T) { }) } -func TestAccAWSS3Bucket_objectLock(t *testing.T) { +func TestAccAWSS3Bucket_Manage_objectLock(t *testing.T) { bucketName := acctest.RandomWithPrefix("tf-test-bucket") resourceName := "aws_s3_bucket.arbitrary" @@ -2390,7 +2390,7 @@ func TestAccAWSS3Bucket_objectLock(t *testing.T) { }) } -func TestAccAWSS3Bucket_forceDestroy(t *testing.T) { +func TestAccAWSS3Bucket_Basic_forceDestroy(t *testing.T) { resourceName := "aws_s3_bucket.bucket" bucketName := acctest.RandomWithPrefix("tf-test-bucket") @@ -2416,7 +2416,7 @@ func TestAccAWSS3Bucket_forceDestroy(t *testing.T) { // While the aws_s3_bucket_object resource automatically cleans the key // to not contain these extra slashes, out-of-band handling and other AWS // services may create keys with extra slashes (empty "directory" prefixes). -func TestAccAWSS3Bucket_forceDestroyWithEmptyPrefixes(t *testing.T) { +func TestAccAWSS3Bucket_Basic_forceDestroyWithEmptyPrefixes(t *testing.T) { resourceName := "aws_s3_bucket.bucket" bucketName := acctest.RandomWithPrefix("tf-test-bucket") @@ -2437,7 +2437,7 @@ func TestAccAWSS3Bucket_forceDestroyWithEmptyPrefixes(t *testing.T) { }) } -func TestAccAWSS3Bucket_forceDestroyWithObjectLockEnabled(t *testing.T) { +func TestAccAWSS3Bucket_Basic_forceDestroyWithObjectLockEnabled(t *testing.T) { resourceName := "aws_s3_bucket.bucket" bucketName := acctest.RandomWithPrefix("tf-test-bucket") @@ -4574,9 +4574,7 @@ resource "aws_s3_bucket" "bucket" { prefix = "testprefix" } - delete_marker_replication { - status = "Enabled" - } + delete_marker_replication_status = "Enabled" destination { bucket = aws_s3_bucket.destination.arn @@ -4617,8 +4615,6 @@ resource "aws_s3_bucket" "bucket" { prefix = "foo" } - delete_marker_replication {} - destination { bucket = aws_s3_bucket.destination.arn storage_class = "STANDARD" @@ -4650,9 +4646,7 @@ resource "aws_s3_bucket" "bucket" { prefix = "foo" } - delete_marker_replication { - status = "Enabled" - } + delete_marker_replication_status = "Enabled" destination { bucket = aws_s3_bucket.destination.arn @@ -4689,10 +4683,6 @@ resource "aws_s3_bucket" "bucket" { } } - delete_marker_replication { - status = "Disabled" - } - destination { bucket = aws_s3_bucket.destination.arn storage_class = "STANDARD" @@ -4731,10 +4721,6 @@ resource "aws_s3_bucket" "bucket" { } } - delete_marker_replication { - status = "Disabled" - } - destination { bucket = aws_s3_bucket.destination.arn storage_class = "STANDARD" @@ -4770,10 +4756,6 @@ resource "aws_s3_bucket" "bucket" { } } - delete_marker_replication { - status = "Disabled" - } - destination { bucket = aws_s3_bucket.destination.arn storage_class = "STANDARD" From fa38dd5bb3dee9919454770284191646af2f75ab Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 14:42:28 -0400 Subject: [PATCH 1139/1208] docs/r/s3_bucket: Add delete_marker_replication_status argument --- website/docs/r/s3_bucket.html.markdown | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/website/docs/r/s3_bucket.html.markdown b/website/docs/r/s3_bucket.html.markdown index cf54e1f364c5..203237f3a236 100644 --- a/website/docs/r/s3_bucket.html.markdown +++ b/website/docs/r/s3_bucket.html.markdown @@ -429,14 +429,14 @@ The `replication_configuration` object supports the following: The `rules` object supports the following: +* `delete_marker_replication_status` - (Optional) Whether delete markers are replicated. The only valid value is `Enabled`. To disable, omit this argument. This argument is only valid with V2 replication configurations (i.e., when `filter` is used). +* `destination` - (Required) Specifies the destination for the rule (documented below). +* `filter` - (Optional) Filter that identifies subset of objects to which the replication rule applies (documented below). * `id` - (Optional) Unique identifier for the rule. Must be less than or equal to 255 characters in length. +* `prefix` - (Optional) Object keyname prefix identifying one or more objects to which the rule applies. Must be less than or equal to 1024 characters in length. * `priority` - (Optional) The priority associated with the rule. -* `destination` - (Required) Specifies the destination for the rule (documented below). * `source_selection_criteria` - (Optional) Specifies special object selection criteria (documented below). -* `prefix` - (Optional) Object keyname prefix identifying one or more objects to which the rule applies. Must be less than or equal to 1024 characters in length. * `status` - (Required) The status of the rule. Either `Enabled` or `Disabled`. The rule is ignored if status is not Enabled. -* `filter` - (Optional) Filter that identifies subset of objects to which the replication rule applies (documented below). -* `delete_marker_replication` - (Optional) Specifies whether delete markers are replicated (documented below). ~> **NOTE on `prefix` and `filter`:** Amazon S3's latest version of the replication configuration is V2, which includes the `filter` attribute for replication rules. With the `filter` attribute, you can specify object filters based on the object key prefix, tags, or both to scope the objects that the rule applies to. @@ -445,10 +445,6 @@ Replication configuration V1 supports filtering based on only the `prefix` attri * For a specific rule, `prefix` conflicts with `filter` * If any rule has `filter` specified then they all must * `priority` is optional (with a default value of `0`) but must be unique between multiple rules -* If a rule has `filter` then it **must** have a `delete_marker_replication` object -* If a rule has `prefix` then it **must not** have a `delete_marker_replication` object - -~> **NOTE:** Delete markers are always replicated when using `prefix` in a rule and is not configurable. The default behavior when using `filter` can be achieved by providing an empty configuration block `delete_marker_replication {}`. ~> **NOTE:** Replication to multiple destination buckets requires that `priority` is specified in the `rules` object. If the corresponding rule requires no filter, an empty configuration block `filter {}` must be specified. @@ -476,10 +472,6 @@ The `filter` object supports the following: * `tags` - (Optional) A map of tags that identifies subset of objects to which the rule applies. The rule applies only to objects having all the tags in its tagset. -The `delete_marker_replication` object supports the following: - -* `status` - (Optional) The delete marker replication status. Either `Enabled` or `Disabled`. Default `Disabled`. If `tags` is set in the `filter` object, then `status` must be set to `Disabled`. - The `server_side_encryption_configuration` object supports the following: * `rule` - (required) A single object for server-side encryption by default configuration. (documented below) From 9cb7da5ef598f00b46a18e3afe86a051869dd7ff Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 14:44:12 -0400 Subject: [PATCH 1140/1208] r/s3_bucket: Update changelog --- .changelog/19323.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/19323.txt b/.changelog/19323.txt index 5dac05347264..a4855edd4c65 100644 --- a/.changelog/19323.txt +++ b/.changelog/19323.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_s3_bucket: Add the delete_marker_replication option to s3 bucket replication_configuration v2 rules +resource/aws_s3_bucket: Add the delete_marker_replication_status argument for V2 replication configurations ``` From 7520f9ab9750bfc3cdb33f8bb20edd29fa368a4f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 14:45:28 -0400 Subject: [PATCH 1141/1208] r/s3_bucket: Remove errant newline --- aws/resource_aws_s3_bucket.go | 1 - 1 file changed, 1 deletion(-) diff --git a/aws/resource_aws_s3_bucket.go b/aws/resource_aws_s3_bucket.go index accb259dd5ff..54af265517f1 100644 --- a/aws/resource_aws_s3_bucket.go +++ b/aws/resource_aws_s3_bucket.go @@ -2124,7 +2124,6 @@ func resourceAwsS3BucketReplicationConfigurationUpdate(s3conn *s3.S3, d *schema. Status: aws.String(s3.DeleteMarkerReplicationStatusDisabled), } } - } else { // XML schema V1. rcRule.Prefix = aws.String(rr["prefix"].(string)) From af79ce02e08456330cd89bc78340ed64276c7739 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 14:47:32 -0400 Subject: [PATCH 1142/1208] r/s3_bucket: Linty McLinterface --- aws/resource_aws_s3_bucket_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_s3_bucket_test.go b/aws/resource_aws_s3_bucket_test.go index 6fa9c61fb78c..3897510930c8 100644 --- a/aws/resource_aws_s3_bucket_test.go +++ b/aws/resource_aws_s3_bucket_test.go @@ -4646,7 +4646,7 @@ resource "aws_s3_bucket" "bucket" { prefix = "foo" } - delete_marker_replication_status = "Enabled" + delete_marker_replication_status = "Enabled" destination { bucket = aws_s3_bucket.destination.arn From 1aa38493a74bcdf3009957c487b9894e1c3b9cb6 Mon Sep 17 00:00:00 2001 From: Eric Searcy Date: Mon, 12 Jul 2021 12:37:22 -0700 Subject: [PATCH 1143/1208] Remove ECR docs policy reference to IAM ECR policy is JSON and has an attribute name of "policy" but otherwise has nothing to do with the IAM policies that the second sentence of the attribute description links to. --- website/docs/r/ecr_lifecycle_policy.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/ecr_lifecycle_policy.html.markdown b/website/docs/r/ecr_lifecycle_policy.html.markdown index 35412f0ad817..75da0372254d 100644 --- a/website/docs/r/ecr_lifecycle_policy.html.markdown +++ b/website/docs/r/ecr_lifecycle_policy.html.markdown @@ -85,7 +85,7 @@ EOF The following arguments are supported: * `repository` - (Required) Name of the repository to apply the policy. -* `policy` - (Required) The policy document. This is a JSON formatted string. See more details about [Policy Parameters](http://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html#lifecycle_policy_parameters) in the official AWS docs. For more information about building IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). +* `policy` - (Required) The policy document. This is a JSON formatted string. See more details about [Policy Parameters](http://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html#lifecycle_policy_parameters) in the official AWS docs. ## Attributes Reference From ab6facf62b30c72425453d445844d5e1b296bc23 Mon Sep 17 00:00:00 2001 From: Bartosz Janda Date: Sat, 29 May 2021 18:10:16 +0200 Subject: [PATCH 1144/1208] Add encrypted SES SMTP password --- .changelog/19579.txt | 3 +++ aws/resource_aws_iam_access_key.go | 24 +++++++++++++---- aws/resource_aws_iam_access_key_test.go | 29 ++++++++++++++++----- website/docs/r/iam_access_key.html.markdown | 3 ++- 4 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 .changelog/19579.txt diff --git a/.changelog/19579.txt b/.changelog/19579.txt new file mode 100644 index 000000000000..909b9e825e08 --- /dev/null +++ b/.changelog/19579.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_iam_access_key: Add encrypted SES SMTP password +``` \ No newline at end of file diff --git a/aws/resource_aws_iam_access_key.go b/aws/resource_aws_iam_access_key.go index 0b396760eb50..560904020ef4 100644 --- a/aws/resource_aws_iam_access_key.go +++ b/aws/resource_aws_iam_access_key.go @@ -91,6 +91,10 @@ func resourceAwsIamAccessKey() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "encrypted_ses_smtp_password_v4": { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -117,6 +121,11 @@ func resourceAwsIamAccessKeyCreate(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("CreateAccessKey response did not contain a Secret Access Key as expected") } + sesSMTPPasswordV4, err := sesSmtpPasswordFromSecretKeySigV4(createResp.AccessKey.SecretAccessKey, meta.(*AWSClient).region) + if err != nil { + return fmt.Errorf("error getting SES SigV4 SMTP Password from Secret Access Key: %s", err) + } + if v, ok := d.GetOk("pgp_key"); ok { pgpKey := v.(string) encryptionKey, err := encryption.RetrieveGPGKey(pgpKey) @@ -130,17 +139,22 @@ func resourceAwsIamAccessKeyCreate(d *schema.ResourceData, meta interface{}) err d.Set("key_fingerprint", fingerprint) d.Set("encrypted_secret", encrypted) + + _, encrypted, err = encryption.EncryptValue(encryptionKey, sesSMTPPasswordV4, "SES SMTP password") + if err != nil { + return err + } + + d.Set("encrypted_ses_smtp_password_v4", encrypted) } else { if err := d.Set("secret", createResp.AccessKey.SecretAccessKey); err != nil { return err } - } - sesSMTPPasswordV4, err := sesSmtpPasswordFromSecretKeySigV4(createResp.AccessKey.SecretAccessKey, meta.(*AWSClient).region) - if err != nil { - return fmt.Errorf("error getting SES SigV4 SMTP Password from Secret Access Key: %s", err) + if err := d.Set("ses_smtp_password_v4", sesSMTPPasswordV4); err != nil { + return err + } } - d.Set("ses_smtp_password_v4", sesSMTPPasswordV4) if v, ok := d.GetOk("status"); ok && v.(string) == iam.StatusTypeInactive { input := &iam.UpdateAccessKeyInput{ diff --git a/aws/resource_aws_iam_access_key_test.go b/aws/resource_aws_iam_access_key_test.go index f22bf919cc2b..875ad79a69ab 100644 --- a/aws/resource_aws_iam_access_key_test.go +++ b/aws/resource_aws_iam_access_key_test.go @@ -33,13 +33,17 @@ func TestAccAWSAccessKey_basic(t *testing.T) { testAccCheckAWSAccessKeyAttributes(&conf, "Active"), testAccCheckResourceAttrRfc3339("aws_iam_access_key.a_key", "create_date"), resource.TestCheckResourceAttrSet("aws_iam_access_key.a_key", "secret"), + resource.TestCheckNoResourceAttr("aws_iam_access_key.a_key", "encrypted_secret"), + resource.TestCheckNoResourceAttr("aws_iam_access_key.a_key", "key_fingerprint"), + resource.TestCheckResourceAttrSet("aws_iam_access_key.a_key", "ses_smtp_password_v4"), + resource.TestCheckNoResourceAttr("aws_iam_access_key.a_key", "encrypted_ses_smtp_password_v4"), ), }, { ResourceName: "aws_iam_access_key.a_key", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"encrypted_secret", "key_fingerprint", "pgp_key", "secret", "ses_smtp_password_v4"}, + ImportStateVerifyIgnore: []string{"encrypted_secret", "key_fingerprint", "pgp_key", "secret", "ses_smtp_password_v4", "encrypted_ses_smtp_password_v4"}, }, }, }) @@ -67,13 +71,17 @@ func TestAccAWSAccessKey_encrypted(t *testing.T) { "aws_iam_access_key.a_key", "encrypted_secret"), resource.TestCheckResourceAttrSet( "aws_iam_access_key.a_key", "key_fingerprint"), + resource.TestCheckNoResourceAttr( + "aws_iam_access_key.a_key", "ses_smtp_password_v4"), + resource.TestCheckResourceAttrSet( + "aws_iam_access_key.a_key", "encrypted_ses_smtp_password_v4"), ), }, { ResourceName: "aws_iam_access_key.a_key", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"encrypted_secret", "key_fingerprint", "pgp_key", "secret", "ses_smtp_password_v4"}, + ImportStateVerifyIgnore: []string{"encrypted_secret", "key_fingerprint", "pgp_key", "secret", "ses_smtp_password_v4", "encrypted_ses_smtp_password_v4"}, }, }, }) @@ -100,7 +108,7 @@ func TestAccAWSAccessKey_Status(t *testing.T) { ResourceName: "aws_iam_access_key.a_key", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"encrypted_secret", "key_fingerprint", "pgp_key", "secret", "ses_smtp_password_v4"}, + ImportStateVerifyIgnore: []string{"encrypted_secret", "key_fingerprint", "pgp_key", "secret", "ses_smtp_password_v4", "encrypted_ses_smtp_password_v4"}, }, { Config: testAccAWSAccessKeyConfig_Status(rName, iam.StatusTypeActive), @@ -205,14 +213,23 @@ func testDecryptSecretKeyAndTest(nAccessKey, key string) resource.TestCheckFunc return fmt.Errorf("Not found: %s", nAccessKey) } - password, ok := keyResource.Primary.Attributes["encrypted_secret"] + secret, ok := keyResource.Primary.Attributes["encrypted_secret"] + if !ok { + return errors.New("No secret in state") + } + + password, ok := keyResource.Primary.Attributes["encrypted_ses_smtp_password_v4"] if !ok { return errors.New("No password in state") } - // We can't verify that the decrypted password is correct, because we don't + // We can't verify that the decrypted secret or password is correct, because we don't // have it. We can verify that decrypting it does not error - _, err := pgpkeys.DecryptBytes(password, key) + _, err := pgpkeys.DecryptBytes(secret, key) + if err != nil { + return fmt.Errorf("Error decrypting secret: %s", err) + } + _, err = pgpkeys.DecryptBytes(password, key) if err != nil { return fmt.Errorf("Error decrypting password: %s", err) } diff --git a/website/docs/r/iam_access_key.html.markdown b/website/docs/r/iam_access_key.html.markdown index 221d074640fe..42da5509d17c 100644 --- a/website/docs/r/iam_access_key.html.markdown +++ b/website/docs/r/iam_access_key.html.markdown @@ -85,6 +85,7 @@ In addition to all arguments above, the following attributes are exported: * `secret` - The secret access key. This attribute is not available for imported resources. Note that this will be written to the state file. If you use this, please protect your backend state file judiciously. Alternatively, you may supply a `pgp_key` instead, which will prevent the secret from being stored in plaintext, at the cost of preventing the use of the secret key in automation. * `encrypted_secret` - The encrypted secret, base64 encoded, if `pgp_key` was specified. This attribute is not available for imported resources. The encrypted secret may be decrypted using the command line, for example: `terraform output -raw encrypted_secret | base64 --decode | keybase pgp decrypt`. * `ses_smtp_password_v4` - The secret access key converted into an SES SMTP password by applying [AWS's documented Sigv4 conversion algorithm](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html#smtp-credentials-convert). This attribute is not available for imported resources. As SigV4 is region specific, valid Provider regions are `ap-south-1`, `ap-southeast-2`, `eu-central-1`, `eu-west-1`, `us-east-1` and `us-west-2`. See current [AWS SES regions](https://docs.aws.amazon.com/general/latest/gr/rande.html#ses_region). +* `encrypted_ses_smtp_password_v4` - The encrypted SES SMTP password, base64 encoded, if `pgp_key` was specified. This attribute is not available for imported resources. The encrypted password may be decrypted using the command line, for example: `terraform output -raw encrypted_ses_smtp_password_v4 | base64 --decode | keybase pgp decrypt`. ## Import @@ -94,4 +95,4 @@ IAM Access Keys can be imported using the identifier, e.g. $ terraform import aws_iam_access_key.example AKIA1234567890 ``` -Resource attributes such as `encrypted_secret`, `key_fingerprint`, `pgp_key`, `secret`, and `ses_smtp_password_v4` are not available for imported resources as this information cannot be read from the IAM API. +Resource attributes such as `encrypted_secret`, `key_fingerprint`, `pgp_key`, `secret`, `ses_smtp_password_v4`, and `encrypted_ses_smtp_password_v4` are not available for imported resources as this information cannot be read from the IAM API. From 4dbfa0d54a768f5167aa92e682d55a1a73870aa4 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 16:47:19 -0400 Subject: [PATCH 1145/1208] r/iam_access_key: Clean up arg order --- aws/resource_aws_iam_access_key.go | 51 ++++++++++++++---------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/aws/resource_aws_iam_access_key.go b/aws/resource_aws_iam_access_key.go index 560904020ef4..98623dfbc9ca 100644 --- a/aws/resource_aws_iam_access_key.go +++ b/aws/resource_aws_iam_access_key.go @@ -50,19 +50,26 @@ func resourceAwsIamAccessKey() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "user": { + "create_date": { Type: schema.TypeString, - Required: true, - ForceNew: true, + Computed: true, }, - "status": { + "encrypted_secret": { + Type: schema.TypeString, + Computed: true, + }, + "encrypted_ses_smtp_password_v4": { Type: schema.TypeString, + Computed: true, + }, + "key_fingerprint": { + Type: schema.TypeString, + Computed: true, + }, + "pgp_key": { + Type: schema.TypeString, + ForceNew: true, Optional: true, - Default: "Active", - ValidateFunc: validation.StringInSlice([]string{ - iam.StatusTypeActive, - iam.StatusTypeInactive, - }, false), }, "secret": { Type: schema.TypeString, @@ -74,26 +81,16 @@ func resourceAwsIamAccessKey() *schema.Resource { Computed: true, Sensitive: true, }, - "pgp_key": { - Type: schema.TypeString, - ForceNew: true, - Optional: true, - }, - "create_date": { - Type: schema.TypeString, - Computed: true, - }, - "encrypted_secret": { - Type: schema.TypeString, - Computed: true, - }, - "key_fingerprint": { - Type: schema.TypeString, - Computed: true, + "status": { + Type: schema.TypeString, + Optional: true, + Default: iam.StatusTypeActive, + ValidateFunc: validation.StringInSlice(iam.StatusType_Values(), false), }, - "encrypted_ses_smtp_password_v4": { + "user": { Type: schema.TypeString, - Computed: true, + Required: true, + ForceNew: true, }, }, } From 5f898383f470dfa85d72d4049cb44fbcf14a57c3 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 16:48:08 -0400 Subject: [PATCH 1146/1208] tests/r/iam_access_key: Standardize tests --- aws/resource_aws_iam_access_key_test.go | 88 ++++++++++++------------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/aws/resource_aws_iam_access_key_test.go b/aws/resource_aws_iam_access_key_test.go index 875ad79a69ab..54e5120163ef 100644 --- a/aws/resource_aws_iam_access_key_test.go +++ b/aws/resource_aws_iam_access_key_test.go @@ -18,7 +18,8 @@ import ( func TestAccAWSAccessKey_basic(t *testing.T) { var conf iam.AccessKeyMetadata - rName := fmt.Sprintf("test-user-%d", acctest.RandInt()) + resourceName := "aws_iam_access_key.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -29,18 +30,18 @@ func TestAccAWSAccessKey_basic(t *testing.T) { { Config: testAccAWSAccessKeyConfig(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAccessKeyExists("aws_iam_access_key.a_key", &conf), + testAccCheckAWSAccessKeyExists(resourceName, &conf), testAccCheckAWSAccessKeyAttributes(&conf, "Active"), - testAccCheckResourceAttrRfc3339("aws_iam_access_key.a_key", "create_date"), - resource.TestCheckResourceAttrSet("aws_iam_access_key.a_key", "secret"), - resource.TestCheckNoResourceAttr("aws_iam_access_key.a_key", "encrypted_secret"), - resource.TestCheckNoResourceAttr("aws_iam_access_key.a_key", "key_fingerprint"), - resource.TestCheckResourceAttrSet("aws_iam_access_key.a_key", "ses_smtp_password_v4"), - resource.TestCheckNoResourceAttr("aws_iam_access_key.a_key", "encrypted_ses_smtp_password_v4"), + testAccCheckResourceAttrRfc3339(resourceName, "create_date"), + resource.TestCheckResourceAttrSet(resourceName, "secret"), + resource.TestCheckNoResourceAttr(resourceName, "encrypted_secret"), + resource.TestCheckNoResourceAttr(resourceName, "key_fingerprint"), + resource.TestCheckResourceAttrSet(resourceName, "ses_smtp_password_v4"), + resource.TestCheckNoResourceAttr(resourceName, "encrypted_ses_smtp_password_v4"), ), }, { - ResourceName: "aws_iam_access_key.a_key", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"encrypted_secret", "key_fingerprint", "pgp_key", "secret", "ses_smtp_password_v4", "encrypted_ses_smtp_password_v4"}, @@ -51,7 +52,8 @@ func TestAccAWSAccessKey_basic(t *testing.T) { func TestAccAWSAccessKey_encrypted(t *testing.T) { var conf iam.AccessKeyMetadata - rName := fmt.Sprintf("test-user-%d", acctest.RandInt()) + resourceName := "aws_iam_access_key.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -62,23 +64,18 @@ func TestAccAWSAccessKey_encrypted(t *testing.T) { { Config: testAccAWSAccessKeyConfig_encrypted(rName, testPubKey1), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAccessKeyExists("aws_iam_access_key.a_key", &conf), + testAccCheckAWSAccessKeyExists(resourceName, &conf), testAccCheckAWSAccessKeyAttributes(&conf, "Active"), - testDecryptSecretKeyAndTest("aws_iam_access_key.a_key", testPrivKey1), - resource.TestCheckNoResourceAttr( - "aws_iam_access_key.a_key", "secret"), - resource.TestCheckResourceAttrSet( - "aws_iam_access_key.a_key", "encrypted_secret"), - resource.TestCheckResourceAttrSet( - "aws_iam_access_key.a_key", "key_fingerprint"), - resource.TestCheckNoResourceAttr( - "aws_iam_access_key.a_key", "ses_smtp_password_v4"), - resource.TestCheckResourceAttrSet( - "aws_iam_access_key.a_key", "encrypted_ses_smtp_password_v4"), + testDecryptSecretKeyAndTest(resourceName, testPrivKey1), + resource.TestCheckNoResourceAttr(resourceName, "secret"), + resource.TestCheckResourceAttrSet(resourceName, "encrypted_secret"), + resource.TestCheckResourceAttrSet(resourceName, "key_fingerprint"), + resource.TestCheckNoResourceAttr(resourceName, "ses_smtp_password_v4"), + resource.TestCheckResourceAttrSet(resourceName, "encrypted_ses_smtp_password_v4"), ), }, { - ResourceName: "aws_iam_access_key.a_key", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"encrypted_secret", "key_fingerprint", "pgp_key", "secret", "ses_smtp_password_v4", "encrypted_ses_smtp_password_v4"}, @@ -87,9 +84,10 @@ func TestAccAWSAccessKey_encrypted(t *testing.T) { }) } -func TestAccAWSAccessKey_Status(t *testing.T) { +func TestAccAWSAccessKey_status(t *testing.T) { var conf iam.AccessKeyMetadata - rName := fmt.Sprintf("test-user-%d", acctest.RandInt()) + resourceName := "aws_iam_access_key.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -100,12 +98,12 @@ func TestAccAWSAccessKey_Status(t *testing.T) { { Config: testAccAWSAccessKeyConfig_Status(rName, iam.StatusTypeInactive), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAccessKeyExists("aws_iam_access_key.a_key", &conf), - resource.TestCheckResourceAttr("aws_iam_access_key.a_key", "status", iam.StatusTypeInactive), + testAccCheckAWSAccessKeyExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "status", iam.StatusTypeInactive), ), }, { - ResourceName: "aws_iam_access_key.a_key", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"encrypted_secret", "key_fingerprint", "pgp_key", "secret", "ses_smtp_password_v4", "encrypted_ses_smtp_password_v4"}, @@ -113,15 +111,15 @@ func TestAccAWSAccessKey_Status(t *testing.T) { { Config: testAccAWSAccessKeyConfig_Status(rName, iam.StatusTypeActive), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAccessKeyExists("aws_iam_access_key.a_key", &conf), - resource.TestCheckResourceAttr("aws_iam_access_key.a_key", "status", iam.StatusTypeActive), + testAccCheckAWSAccessKeyExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "status", iam.StatusTypeActive), ), }, { Config: testAccAWSAccessKeyConfig_Status(rName, iam.StatusTypeInactive), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAccessKeyExists("aws_iam_access_key.a_key", &conf), - resource.TestCheckResourceAttr("aws_iam_access_key.a_key", "status", iam.StatusTypeInactive), + testAccCheckAWSAccessKeyExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "status", iam.StatusTypeInactive), ), }, }, @@ -194,7 +192,7 @@ func testAccCheckAWSAccessKeyExists(n string, res *iam.AccessKeyMetadata) resour func testAccCheckAWSAccessKeyAttributes(accessKeyMetadata *iam.AccessKeyMetadata, status string) resource.TestCheckFunc { return func(s *terraform.State) error { - if !strings.Contains(*accessKeyMetadata.UserName, "test-user") { + if !strings.Contains(*accessKeyMetadata.UserName, "tf-acc-test") { return fmt.Errorf("Bad username: %s", *accessKeyMetadata.UserName) } @@ -240,27 +238,27 @@ func testDecryptSecretKeyAndTest(nAccessKey, key string) resource.TestCheckFunc func testAccAWSAccessKeyConfig(rName string) string { return fmt.Sprintf(` -resource "aws_iam_user" "a_user" { - name = "%s" +resource "aws_iam_user" "test" { + name = %[1]q } -resource "aws_iam_access_key" "a_key" { - user = aws_iam_user.a_user.name +resource "aws_iam_access_key" "test" { + user = aws_iam_user.test.name } `, rName) } func testAccAWSAccessKeyConfig_encrypted(rName, key string) string { return fmt.Sprintf(` -resource "aws_iam_user" "a_user" { - name = "%s" +resource "aws_iam_user" "test" { + name = %[1]q } -resource "aws_iam_access_key" "a_key" { - user = aws_iam_user.a_user.name +resource "aws_iam_access_key" "test" { + user = aws_iam_user.test.name pgp_key = < Date: Mon, 12 Jul 2021 16:48:38 -0400 Subject: [PATCH 1147/1208] docs/r/iam_access_key: Clean up docs --- website/docs/r/iam_access_key.html.markdown | 22 +++++++++------------ 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/website/docs/r/iam_access_key.html.markdown b/website/docs/r/iam_access_key.html.markdown index 42da5509d17c..05c10cd618f2 100644 --- a/website/docs/r/iam_access_key.html.markdown +++ b/website/docs/r/iam_access_key.html.markdown @@ -67,25 +67,21 @@ output "aws_iam_smtp_password_v4" { The following arguments are supported: -* `user` - (Required) The IAM user to associate with this access key. -* `pgp_key` - (Optional) Either a base-64 encoded PGP public key, or a - keybase username in the form `keybase:some_person_that_exists`, for use - in the `encrypted_secret` output attribute. -* `status` - (Optional) The access key status to apply. Defaults to `Active`. -Valid values are `Active` and `Inactive`. +* `pgp_key` - (Optional) Either a base-64 encoded PGP public key, or a keybase username in the form `keybase:some_person_that_exists`, for use in the `encrypted_secret` output attribute. +* `status` - (Optional) Access key status to apply. Defaults to `Active`. Valid values are `Active` and `Inactive`. +* `user` - (Required) IAM user to associate with this access key. ## Attributes Reference In addition to all arguments above, the following attributes are exported: * `create_date` - Date and time in [RFC3339 format](https://tools.ietf.org/html/rfc3339#section-5.8) that the access key was created. -* `id` - The access key ID. -* `user` - The IAM user associated with this access key. -* `key_fingerprint` - The fingerprint of the PGP key used to encrypt the secret. This attribute is not available for imported resources. -* `secret` - The secret access key. This attribute is not available for imported resources. Note that this will be written to the state file. If you use this, please protect your backend state file judiciously. Alternatively, you may supply a `pgp_key` instead, which will prevent the secret from being stored in plaintext, at the cost of preventing the use of the secret key in automation. -* `encrypted_secret` - The encrypted secret, base64 encoded, if `pgp_key` was specified. This attribute is not available for imported resources. The encrypted secret may be decrypted using the command line, for example: `terraform output -raw encrypted_secret | base64 --decode | keybase pgp decrypt`. -* `ses_smtp_password_v4` - The secret access key converted into an SES SMTP password by applying [AWS's documented Sigv4 conversion algorithm](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html#smtp-credentials-convert). This attribute is not available for imported resources. As SigV4 is region specific, valid Provider regions are `ap-south-1`, `ap-southeast-2`, `eu-central-1`, `eu-west-1`, `us-east-1` and `us-west-2`. See current [AWS SES regions](https://docs.aws.amazon.com/general/latest/gr/rande.html#ses_region). -* `encrypted_ses_smtp_password_v4` - The encrypted SES SMTP password, base64 encoded, if `pgp_key` was specified. This attribute is not available for imported resources. The encrypted password may be decrypted using the command line, for example: `terraform output -raw encrypted_ses_smtp_password_v4 | base64 --decode | keybase pgp decrypt`. +* `encrypted_secret` - Encrypted secret, base64 encoded, if `pgp_key` was specified. This attribute is not available for imported resources. The encrypted secret may be decrypted using the command line, for example: `terraform output -raw encrypted_secret | base64 --decode | keybase pgp decrypt`. +* `encrypted_ses_smtp_password_v4` - Encrypted SES SMTP password, base64 encoded, if `pgp_key` was specified. This attribute is not available for imported resources. The encrypted password may be decrypted using the command line, for example: `terraform output -raw encrypted_ses_smtp_password_v4 | base64 --decode | keybase pgp decrypt`. +* `id` - Access key ID. +* `key_fingerprint` - Fingerprint of the PGP key used to encrypt the secret. This attribute is not available for imported resources. +* `secret` - Secret access key. This attribute is not available for imported resources. Note that this will be written to the state file. If you use this, please protect your backend state file judiciously. Alternatively, you may supply a `pgp_key` instead, which will prevent the secret from being stored in plaintext, at the cost of preventing the use of the secret key in automation. +* `ses_smtp_password_v4` - Secret access key converted into an SES SMTP password by applying [AWS's documented Sigv4 conversion algorithm](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html#smtp-credentials-convert). This attribute is not available for imported resources. As SigV4 is region specific, valid Provider regions are `ap-south-1`, `ap-southeast-2`, `eu-central-1`, `eu-west-1`, `us-east-1` and `us-west-2`. See current [AWS SES regions](https://docs.aws.amazon.com/general/latest/gr/rande.html#ses_region). ## Import From bf37d1478dbbb29bd93a71926993db09fa294a42 Mon Sep 17 00:00:00 2001 From: Angel Alonso Date: Mon, 17 May 2021 19:28:26 +0200 Subject: [PATCH 1148/1208] Implemented Scope-down statements on WAFv2 Web ACL Managed Rules --- aws/resource_aws_wafv2_web_acl.go | 21 ++++++++++---- aws/resource_aws_wafv2_web_acl_test.go | 32 +++++++++++++++------- website/docs/r/wafv2_web_acl.html.markdown | 6 ++++ 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/aws/resource_aws_wafv2_web_acl.go b/aws/resource_aws_wafv2_web_acl.go index ee635a360c93..7fc61107382b 100644 --- a/aws/resource_aws_wafv2_web_acl.go +++ b/aws/resource_aws_wafv2_web_acl.go @@ -359,7 +359,7 @@ func wafv2WebACLRootStatementSchema(level int) *schema.Schema { "byte_match_statement": wafv2ByteMatchStatementSchema(), "geo_match_statement": wafv2GeoMatchStatementSchema(), "ip_set_reference_statement": wafv2IpSetReferenceStatementSchema(), - "managed_rule_group_statement": wafv2ManagedRuleGroupStatementSchema(), + "managed_rule_group_statement": wafv2ManagedRuleGroupStatementSchema(level), "not_statement": wafv2StatementSchema(level), "or_statement": wafv2StatementSchema(level), "rate_based_statement": wafv2RateBasedStatementSchema(level), @@ -373,7 +373,7 @@ func wafv2WebACLRootStatementSchema(level int) *schema.Schema { } } -func wafv2ManagedRuleGroupStatementSchema() *schema.Schema { +func wafv2ManagedRuleGroupStatementSchema(level int) *schema.Schema { return &schema.Schema{ Type: schema.TypeList, Optional: true, @@ -391,6 +391,7 @@ func wafv2ManagedRuleGroupStatementSchema() *schema.Schema { Required: true, ValidateFunc: validation.StringLenBetween(1, 128), }, + "scope_down_statement": wafv2ScopeDownStatementSchema(level - 1), }, }, } @@ -626,11 +627,18 @@ func expandWafv2ManagedRuleGroupStatement(l []interface{}) *wafv2.ManagedRuleGro } m := l[0].(map[string]interface{}) - return &wafv2.ManagedRuleGroupStatement{ + r := &wafv2.ManagedRuleGroupStatement{ ExcludedRules: expandWafv2ExcludedRules(m["excluded_rule"].([]interface{})), Name: aws.String(m["name"].(string)), VendorName: aws.String(m["vendor_name"].(string)), } + + s := m["scope_down_statement"].([]interface{}) + if len(s) > 0 && s[0] != nil { + r.ScopeDownStatement = expandWafv2Statement(s[0].(map[string]interface{})) + } + + return r } func expandWafv2RateBasedStatement(l []interface{}) *wafv2.RateBasedStatement { @@ -824,9 +832,10 @@ func flattenWafv2ManagedRuleGroupStatement(r *wafv2.ManagedRuleGroupStatement) i } m := map[string]interface{}{ - "excluded_rule": flattenWafv2ExcludedRules(r.ExcludedRules), - "name": aws.StringValue(r.Name), - "vendor_name": aws.StringValue(r.VendorName), + "excluded_rule": flattenWafv2ExcludedRules(r.ExcludedRules), + "name": aws.StringValue(r.Name), + "vendor_name": aws.StringValue(r.VendorName), + "scope_down_statement": nil, } return []interface{}{m} diff --git a/aws/resource_aws_wafv2_web_acl_test.go b/aws/resource_aws_wafv2_web_acl_test.go index aa59aa5e35ed..84ba41615475 100644 --- a/aws/resource_aws_wafv2_web_acl_test.go +++ b/aws/resource_aws_wafv2_web_acl_test.go @@ -566,10 +566,11 @@ func TestAccAwsWafv2WebACL_ManagedRuleGroupStatement(t *testing.T) { "override_action.0.count.#": "0", "override_action.0.none.#": "1", "statement.#": "1", - "statement.0.managed_rule_group_statement.#": "1", - "statement.0.managed_rule_group_statement.0.name": "AWSManagedRulesCommonRuleSet", - "statement.0.managed_rule_group_statement.0.vendor_name": "AWS", - "statement.0.managed_rule_group_statement.0.excluded_rule.#": "0", + "statement.0.managed_rule_group_statement.#": "1", + "statement.0.managed_rule_group_statement.0.name": "AWSManagedRulesCommonRuleSet", + "statement.0.managed_rule_group_statement.0.vendor_name": "AWS", + "statement.0.managed_rule_group_statement.0.excluded_rule.#": "0", + "statement.0.managed_rule_group_statement.0.scope_down_statement.#": "0", }), ), }, @@ -587,12 +588,17 @@ func TestAccAwsWafv2WebACL_ManagedRuleGroupStatement(t *testing.T) { "override_action.0.count.#": "1", "override_action.0.none.#": "0", "statement.#": "1", - "statement.0.managed_rule_group_statement.#": "1", - "statement.0.managed_rule_group_statement.0.name": "AWSManagedRulesCommonRuleSet", - "statement.0.managed_rule_group_statement.0.vendor_name": "AWS", - "statement.0.managed_rule_group_statement.0.excluded_rule.#": "2", - "statement.0.managed_rule_group_statement.0.excluded_rule.0.name": "SizeRestrictions_QUERYSTRING", - "statement.0.managed_rule_group_statement.0.excluded_rule.1.name": "NoUserAgent_HEADER", + "statement.0.managed_rule_group_statement.#": "1", + "statement.0.managed_rule_group_statement.0.name": "AWSManagedRulesCommonRuleSet", + "statement.0.managed_rule_group_statement.0.vendor_name": "AWS", + "statement.0.managed_rule_group_statement.0.excluded_rule.#": "2", + "statement.0.managed_rule_group_statement.0.excluded_rule.0.name": "SizeRestrictions_QUERYSTRING", + "statement.0.managed_rule_group_statement.0.excluded_rule.1.name": "NoUserAgent_HEADER", + "statement.0.managed_rule_group_statement.0.scope_down_statement.#": "1", + "statement.0.managed_rule_group_statement.0.scope_down_statement.0.geo_match_statement.#": "1", + "statement.0.managed_rule_group_statement.0.scope_down_statement.0.geo_match_statement.0.country_codes.#": "2", + "statement.0.managed_rule_group_statement.0.scope_down_statement.0.geo_match_statement.0.country_codes.0": "US", + "statement.0.managed_rule_group_statement.0.scope_down_statement.0.geo_match_statement.0.country_codes.1": "NL", }), ), }, @@ -2115,6 +2121,12 @@ resource "aws_wafv2_web_acl" "test" { excluded_rule { name = "NoUserAgent_HEADER" } + + scope_down_statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } } } diff --git a/website/docs/r/wafv2_web_acl.html.markdown b/website/docs/r/wafv2_web_acl.html.markdown index 14640f4fc275..d7917c0c7d38 100644 --- a/website/docs/r/wafv2_web_acl.html.markdown +++ b/website/docs/r/wafv2_web_acl.html.markdown @@ -47,6 +47,12 @@ resource "aws_wafv2_web_acl" "example" { excluded_rule { name = "NoUserAgent_HEADER" } + + scope_down_statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } } } From 65b43e6dbc1fb65d98da87a32fdd583c8e44b25b Mon Sep 17 00:00:00 2001 From: Angel Alonso Date: Mon, 17 May 2021 19:48:02 +0200 Subject: [PATCH 1149/1208] Added changelog --- .changelog/19407.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19407.txt diff --git a/.changelog/19407.txt b/.changelog/19407.txt new file mode 100644 index 000000000000..47e0a8ea76c5 --- /dev/null +++ b/.changelog/19407.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_wafv2_web_acl: Support `scope_down_statement` on `managed_rule_group_statement` +``` \ No newline at end of file From 3bbbf300dc7d7c1d3bac5cc8a66c3d00d349c581 Mon Sep 17 00:00:00 2001 From: Angel Alonso Date: Fri, 18 Jun 2021 10:45:56 +0200 Subject: [PATCH 1150/1208] Added scope_down_statement to flattened managed_rule_group_statement Co-authored-by: Jack Shubatt --- aws/resource_aws_wafv2_web_acl.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aws/resource_aws_wafv2_web_acl.go b/aws/resource_aws_wafv2_web_acl.go index 7fc61107382b..18c71038b574 100644 --- a/aws/resource_aws_wafv2_web_acl.go +++ b/aws/resource_aws_wafv2_web_acl.go @@ -838,6 +838,9 @@ func flattenWafv2ManagedRuleGroupStatement(r *wafv2.ManagedRuleGroupStatement) i "scope_down_statement": nil, } +if r.ScopeDownStatement != nil { + m["scope_down_statement"] = []interface{}{flattenWafv2Statement(r.ScopeDownStatement)} +} return []interface{}{m} } From 1768615f53692e3fd9d222715103d2155bd0e5be Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 10 Feb 2021 12:16:11 -0800 Subject: [PATCH 1151/1208] Updates finder.SecurityGroupByID() to return resource.NotFoundError --- aws/internal/service/ec2/finder/finder.go | 17 ++++++++++++++--- aws/internal/service/ec2/waiter/status.go | 7 +------ aws/resource_aws_default_security_group.go | 17 +++++++++-------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/aws/internal/service/ec2/finder/finder.go b/aws/internal/service/ec2/finder/finder.go index 81d99aff35b0..87b8987c6350 100644 --- a/aws/internal/service/ec2/finder/finder.go +++ b/aws/internal/service/ec2/finder/finder.go @@ -408,17 +408,28 @@ func RouteByPrefixListIDDestination(conn *ec2.EC2, routeTableID, prefixListID st } // SecurityGroupByID looks up a security group by ID. When not found, returns nil and potentially an API error. +// SecurityGroupByID looks up a security group by ID. Returns a resource.NotFoundError if not found. func SecurityGroupByID(conn *ec2.EC2, id string) (*ec2.SecurityGroup, error) { - req := &ec2.DescribeSecurityGroupsInput{ + input := &ec2.DescribeSecurityGroupsInput{ GroupIds: aws.StringSlice([]string{id}), } - result, err := conn.DescribeSecurityGroups(req) + result, err := conn.DescribeSecurityGroups(input) + if tfawserr.ErrCodeEquals(err, tfec2.InvalidSecurityGroupIDNotFound) || + tfawserr.ErrCodeEquals(err, tfec2.InvalidGroupNotFound) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } if err != nil { return nil, err } if result == nil || len(result.SecurityGroups) == 0 || result.SecurityGroups[0] == nil { - return nil, nil + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } } return result.SecurityGroups[0], nil diff --git a/aws/internal/service/ec2/waiter/status.go b/aws/internal/service/ec2/waiter/status.go index 68265ef0f402..6547d450c0ad 100644 --- a/aws/internal/service/ec2/waiter/status.go +++ b/aws/internal/service/ec2/waiter/status.go @@ -314,18 +314,13 @@ const ( func SecurityGroupStatus(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { group, err := finder.SecurityGroupByID(conn, id) - if tfawserr.ErrCodeEquals(err, tfec2.InvalidSecurityGroupIDNotFound) || - tfawserr.ErrCodeEquals(err, tfec2.InvalidGroupNotFound) { + if tfresource.NotFound(err) { return nil, SecurityGroupStatusNotFound, nil } if err != nil { return nil, SecurityGroupStatusUnknown, err } - if group == nil { - return nil, SecurityGroupStatusNotFound, nil - } - return group, SecurityGroupStatusCreated, nil } } diff --git a/aws/resource_aws_default_security_group.go b/aws/resource_aws_default_security_group.go index e9cc15c11a16..97be5dc68d39 100644 --- a/aws/resource_aws_default_security_group.go +++ b/aws/resource_aws_default_security_group.go @@ -14,6 +14,7 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const DefaultSecurityGroupName = "default" @@ -267,14 +268,14 @@ func resourceAwsDefaultSecurityGroupRead(d *schema.ResourceData, meta interface{ ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig group, err := finder.SecurityGroupByID(conn, d.Id()) - if err != nil { - return err - } - if group == nil { + if tfresource.NotFound(err) { log.Printf("[WARN] Security group (%s) not found, removing from state", d.Id()) d.SetId("") return nil } + if err != nil { + return err + } remoteIngressRules := resourceAwsSecurityGroupIPPermGather(d.Id(), group.IpPermissions, group.OwnerId) remoteEgressRules := resourceAwsSecurityGroupIPPermGather(d.Id(), group.IpPermissionsEgress, group.OwnerId) @@ -327,14 +328,14 @@ func resourceAwsDefaultSecurityGroupUpdate(d *schema.ResourceData, meta interfac conn := meta.(*AWSClient).ec2conn group, err := finder.SecurityGroupByID(conn, d.Id()) - if err != nil { - return err - } - if group == nil { + if tfresource.NotFound(err) { log.Printf("[WARN] Security group (%s) not found, removing from state", d.Id()) d.SetId("") return nil } + if err != nil { + return err + } err = resourceAwsSecurityGroupUpdateRules(d, "ingress", meta, group) if err != nil { From c7a95dd4895eff02418244def810dbd7b688f783 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 11 Feb 2021 00:20:28 -0800 Subject: [PATCH 1152/1208] Adds EmptyResult and TooManyResults errors compatible with NotFoundError and expands use of Security Group finder --- aws/data_source_aws_security_group.go | 19 +-- aws/internal/service/ec2/finder/finder.go | 27 ++- aws/internal/tfresource/not_found_error.go | 79 +++++++++ .../tfresource/not_found_error_test.go | 156 ++++++++++++++++++ aws/resource_aws_elb.go | 57 +------ 5 files changed, 271 insertions(+), 67 deletions(-) create mode 100644 aws/internal/tfresource/not_found_error.go create mode 100644 aws/internal/tfresource/not_found_error_test.go diff --git a/aws/data_source_aws_security_group.go b/aws/data_source_aws_security_group.go index bc9e346a9856..1bcb54a89804 100644 --- a/aws/data_source_aws_security_group.go +++ b/aws/data_source_aws_security_group.go @@ -1,14 +1,16 @@ package aws import ( + "errors" "fmt" - "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func dataSourceAwsSecurityGroup() *schema.Resource { @@ -76,19 +78,16 @@ func dataSourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) er req.Filters = nil } - log.Printf("[DEBUG] Reading Security Group: %s", req) - resp, err := conn.DescribeSecurityGroups(req) - if err != nil { - return err - } - if resp == nil || len(resp.SecurityGroups) == 0 { + sg, err := finder.SecurityGroup(conn, req) + if errors.Is(err, tfresource.ErrEmptyResult) { return fmt.Errorf("no matching SecurityGroup found") } - if len(resp.SecurityGroups) > 1 { + if errors.Is(err, tfresource.ErrTooManyResults) { return fmt.Errorf("multiple Security Groups matched; use additional constraints to reduce matches to a single Security Group") } - - sg := resp.SecurityGroups[0] + if err != nil { + return err + } d.SetId(aws.StringValue(sg.GroupId)) d.Set("name", sg.GroupName) diff --git a/aws/internal/service/ec2/finder/finder.go b/aws/internal/service/ec2/finder/finder.go index 87b8987c6350..14ac59610ea2 100644 --- a/aws/internal/service/ec2/finder/finder.go +++ b/aws/internal/service/ec2/finder/finder.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" tfnet "github.com/terraform-providers/terraform-provider-aws/aws/internal/net" tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) // CarrierGatewayByID returns the carrier gateway corresponding to the specified identifier. @@ -413,6 +414,23 @@ func SecurityGroupByID(conn *ec2.EC2, id string) (*ec2.SecurityGroup, error) { input := &ec2.DescribeSecurityGroupsInput{ GroupIds: aws.StringSlice([]string{id}), } + return SecurityGroup(conn, input) +} + +// SecurityGroupByNameAndVpcID looks up a security group by name and VPC ID. Returns a resource.NotFoundError if not found. +func SecurityGroupByNameAndVpcID(conn *ec2.EC2, name, vpcID string) (*ec2.SecurityGroup, error) { + input := &ec2.DescribeSecurityGroupsInput{ + Filters: tfec2.BuildAttributeFilterList( + map[string]string{ + "group-name": name, + "vpc-id": vpcID, + }, + ), + } + return SecurityGroup(conn, input) +} + +func SecurityGroup(conn *ec2.EC2, input *ec2.DescribeSecurityGroupsInput) (*ec2.SecurityGroup, error) { result, err := conn.DescribeSecurityGroups(input) if tfawserr.ErrCodeEquals(err, tfec2.InvalidSecurityGroupIDNotFound) || tfawserr.ErrCodeEquals(err, tfec2.InvalidGroupNotFound) { @@ -426,10 +444,11 @@ func SecurityGroupByID(conn *ec2.EC2, id string) (*ec2.SecurityGroup, error) { } if result == nil || len(result.SecurityGroups) == 0 || result.SecurityGroups[0] == nil { - return nil, &resource.NotFoundError{ - Message: "Empty result", - LastRequest: input, - } + return nil, tfresource.NewEmptyResultError(input) + } + + if len(result.SecurityGroups) > 1 { + return nil, tfresource.NewTooManyResultsError(len(result.SecurityGroups), input) } return result.SecurityGroups[0], nil diff --git a/aws/internal/tfresource/not_found_error.go b/aws/internal/tfresource/not_found_error.go new file mode 100644 index 000000000000..d57ee8ca688b --- /dev/null +++ b/aws/internal/tfresource/not_found_error.go @@ -0,0 +1,79 @@ +package tfresource + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +type EmptyResultError struct { + LastRequest interface{} +} + +var ErrEmptyResult = &EmptyResultError{} + +func NewEmptyResultError(lastRequest interface{}) error { + return &EmptyResultError{ + LastRequest: lastRequest, + } +} + +func (e *EmptyResultError) Error() string { + return "empty result" +} + +func (e *EmptyResultError) Is(err error) bool { + _, ok := err.(*EmptyResultError) + return ok +} + +func (e *EmptyResultError) As(target interface{}) bool { + t, ok := target.(**resource.NotFoundError) + if !ok { + return false + } + + *t = &resource.NotFoundError{ + Message: e.Error(), + LastRequest: e.LastRequest, + } + + return true +} + +type TooManyResultsError struct { + Count int + LastRequest interface{} +} + +var ErrTooManyResults = &TooManyResultsError{} + +func NewTooManyResultsError(count int, lastRequest interface{}) error { + return &TooManyResultsError{ + Count: count, + LastRequest: lastRequest, + } +} + +func (e *TooManyResultsError) Error() string { + return fmt.Sprintf("too many results: wanted 1, got %d", e.Count) +} + +func (e *TooManyResultsError) Is(err error) bool { + _, ok := err.(*TooManyResultsError) + return ok +} + +func (e *TooManyResultsError) As(target interface{}) bool { + t, ok := target.(**resource.NotFoundError) + if !ok { + return false + } + + *t = &resource.NotFoundError{ + Message: e.Error(), + LastRequest: e.LastRequest, + } + + return true +} diff --git a/aws/internal/tfresource/not_found_error_test.go b/aws/internal/tfresource/not_found_error_test.go new file mode 100644 index 000000000000..a96f7b522ae5 --- /dev/null +++ b/aws/internal/tfresource/not_found_error_test.go @@ -0,0 +1,156 @@ +package tfresource + +import ( + "errors" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestEmptyResultErrorAsNotFoundError(t *testing.T) { + lastRequest := 123 + err := NewEmptyResultError(lastRequest) + + var nfe *resource.NotFoundError + ok := errors.As(err, &nfe) + + if !ok { + t.Fatal("expected errors.As() to return true") + } + if nfe.Message != "empty result" { + t.Errorf(`expected Message to be "empty result", got %q`, nfe.Message) + } + if nfe.LastRequest != lastRequest { + t.Errorf("unexpected value for LastRequest") + } +} + +func TestEmptyResultErrorIs(t *testing.T) { + testCases := []struct { + name string + err error + expected bool + }{ + { + name: "compare to nil", + err: nil, + }, + { + name: "other error", + err: errors.New("test"), + }, + { + name: "EmptyResultError with LastRequest", + err: &EmptyResultError{ + LastRequest: 123, + }, + expected: true, + }, + { + name: "ErrEmptyResult", + err: ErrEmptyResult, + expected: true, + }, + { + name: "wrapped other error", + err: fmt.Errorf("test: %w", errors.New("test")), + }, + { + name: "wrapped EmptyResultError with LastRequest", + err: fmt.Errorf("test: %w", &EmptyResultError{ + LastRequest: 123, + }), + expected: true, + }, + { + name: "wrapped ErrEmptyResult", + err: fmt.Errorf("test: %w", ErrEmptyResult), + expected: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + err := &EmptyResultError{} + ok := errors.Is(testCase.err, err) + if ok != testCase.expected { + t.Errorf("got %t, expected %t", ok, testCase.expected) + } + }) + } +} + +func TestTooManyResultsErrorAsNotFoundError(t *testing.T) { + count := 2 + lastRequest := 123 + err := NewTooManyResultsError(count, lastRequest) + + var nfe *resource.NotFoundError + ok := errors.As(err, &nfe) + + if !ok { + t.Fatal("expected errors.As() to return true") + } + if expected := fmt.Sprintf("too many results: wanted 1, got %d", count); nfe.Message != expected { + t.Errorf(`expected Message to be %q, got %q`, expected, nfe.Message) + } + if nfe.LastRequest != lastRequest { + t.Errorf("unexpected value for LastRequest") + } +} + +func TestTooManyResultsErrorIs(t *testing.T) { + testCases := []struct { + name string + err error + expected bool + }{ + { + name: "compare to nil", + err: nil, + }, + { + name: "other error", + err: errors.New("test"), + }, + { + name: "TooManyResultsError with LastRequest", + err: &TooManyResultsError{ + LastRequest: 123, + }, + expected: true, + }, + { + name: "ErrTooManyResults", + err: ErrTooManyResults, + expected: true, + }, + { + name: "wrapped other error", + err: fmt.Errorf("test: %w", errors.New("test")), + }, + { + name: "wrapped TooManyResultsError with LastRequest", + err: fmt.Errorf("test: %w", &TooManyResultsError{ + LastRequest: 123, + }), + expected: true, + }, + { + name: "wrapped ErrTooManyResults", + err: fmt.Errorf("test: %w", ErrTooManyResults), + expected: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + err := &TooManyResultsError{} + ok := errors.Is(testCase.err, err) + if ok != testCase.expected { + t.Errorf("got %t, expected %t", ok, testCase.expected) + } + }) + } +} diff --git a/aws/resource_aws_elb.go b/aws/resource_aws_elb.go index 463665bb0faa..665ef14276f9 100644 --- a/aws/resource_aws_elb.go +++ b/aws/resource_aws_elb.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" ) func resourceAwsElb() *schema.Resource { @@ -405,14 +406,12 @@ func flattenAwsELbResource(d *schema.ResourceData, ec2conn *ec2.EC2, elbconn *el d.Set("source_security_group", group) // Manually look up the ELB Security Group ID, since it's not provided - var elbVpc string if lb.VPCId != nil { - elbVpc = *lb.VPCId - sgId, err := sourceSGIdByName(ec2conn, *lb.SourceSecurityGroup.GroupName, elbVpc) + sg, err := finder.SecurityGroupByNameAndVpcID(ec2conn, aws.StringValue(lb.SourceSecurityGroup.GroupName), aws.StringValue(lb.VPCId)) if err != nil { - return fmt.Errorf("Error looking up ELB Security Group ID: %s", err) + return fmt.Errorf("Error looking up ELB Security Group ID: %w", err) } else { - d.Set("source_security_group_id", sgId) + d.Set("source_security_group_id", aws.StringValue(sg.GroupId)) } } } @@ -828,54 +827,6 @@ func isLoadBalancerNotFound(err error) bool { return ok && elberr.Code() == elb.ErrCodeAccessPointNotFoundException } -func sourceSGIdByName(conn *ec2.EC2, sg, vpcId string) (string, error) { - var filters []*ec2.Filter - var sgFilterName, sgFilterVPCID *ec2.Filter - sgFilterName = &ec2.Filter{ - Name: aws.String("group-name"), - Values: []*string{aws.String(sg)}, - } - - if vpcId != "" { - sgFilterVPCID = &ec2.Filter{ - Name: aws.String("vpc-id"), - Values: []*string{aws.String(vpcId)}, - } - } - - filters = append(filters, sgFilterName) - - if sgFilterVPCID != nil { - filters = append(filters, sgFilterVPCID) - } - - req := &ec2.DescribeSecurityGroupsInput{ - Filters: filters, - } - resp, err := conn.DescribeSecurityGroups(req) - if err != nil { - if ec2err, ok := err.(awserr.Error); ok { - if ec2err.Code() == "InvalidSecurityGroupID.NotFound" || - ec2err.Code() == "InvalidGroup.NotFound" { - resp = nil - err = nil - } - } - - if err != nil { - log.Printf("Error on ELB SG look up: %s", err) - return "", err - } - } - - if resp == nil || len(resp.SecurityGroups) == 0 { - return "", fmt.Errorf("No security groups found for name %s and vpc id %s", sg, vpcId) - } - - group := resp.SecurityGroups[0] - return *group.GroupId, nil -} - func validateAccessLogsInterval(v interface{}, k string) (ws []string, errors []error) { value := v.(int) From f512ab8a1315283d72886299060e1542a37880f8 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 12 Feb 2021 16:54:03 -0800 Subject: [PATCH 1153/1208] Moves error files --- aws/internal/tfresource/{not_found_error.go => finder_errors.go} | 0 .../tfresource/{not_found_error_test.go => finder_errors_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename aws/internal/tfresource/{not_found_error.go => finder_errors.go} (100%) rename aws/internal/tfresource/{not_found_error_test.go => finder_errors_test.go} (100%) diff --git a/aws/internal/tfresource/not_found_error.go b/aws/internal/tfresource/finder_errors.go similarity index 100% rename from aws/internal/tfresource/not_found_error.go rename to aws/internal/tfresource/finder_errors.go diff --git a/aws/internal/tfresource/not_found_error_test.go b/aws/internal/tfresource/finder_errors_test.go similarity index 100% rename from aws/internal/tfresource/not_found_error_test.go rename to aws/internal/tfresource/finder_errors_test.go From 38be8f9eb94b8c6ebbaddc1164f11990c5f370a9 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 25 Mar 2021 17:53:14 -0700 Subject: [PATCH 1154/1208] Removes new error types --- aws/data_source_aws_security_group.go | 16 +- aws/internal/service/ec2/finder/finder.go | 11 +- aws/internal/tfresource/finder_errors.go | 79 --------- aws/internal/tfresource/finder_errors_test.go | 156 ------------------ 4 files changed, 18 insertions(+), 244 deletions(-) delete mode 100644 aws/internal/tfresource/finder_errors.go delete mode 100644 aws/internal/tfresource/finder_errors_test.go diff --git a/aws/data_source_aws_security_group.go b/aws/data_source_aws_security_group.go index 1bcb54a89804..311bcfbb2d5f 100644 --- a/aws/data_source_aws_security_group.go +++ b/aws/data_source_aws_security_group.go @@ -3,14 +3,15 @@ package aws import ( "errors" "fmt" + "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func dataSourceAwsSecurityGroup() *schema.Resource { @@ -79,11 +80,14 @@ func dataSourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) er } sg, err := finder.SecurityGroup(conn, req) - if errors.Is(err, tfresource.ErrEmptyResult) { - return fmt.Errorf("no matching SecurityGroup found") - } - if errors.Is(err, tfresource.ErrTooManyResults) { - return fmt.Errorf("multiple Security Groups matched; use additional constraints to reduce matches to a single Security Group") + var nfe *resource.NotFoundError + if errors.As(err, &nfe) { + if nfe.Message == "empty result" { + return fmt.Errorf("no matching SecurityGroup found") + } + if strings.HasPrefix(nfe.Message, "too many results:") { + return fmt.Errorf("multiple Security Groups matched; use additional constraints to reduce matches to a single Security Group") + } } if err != nil { return err diff --git a/aws/internal/service/ec2/finder/finder.go b/aws/internal/service/ec2/finder/finder.go index 14ac59610ea2..cbf273af1447 100644 --- a/aws/internal/service/ec2/finder/finder.go +++ b/aws/internal/service/ec2/finder/finder.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" tfnet "github.com/terraform-providers/terraform-provider-aws/aws/internal/net" tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) // CarrierGatewayByID returns the carrier gateway corresponding to the specified identifier. @@ -444,11 +443,17 @@ func SecurityGroup(conn *ec2.EC2, input *ec2.DescribeSecurityGroupsInput) (*ec2. } if result == nil || len(result.SecurityGroups) == 0 || result.SecurityGroups[0] == nil { - return nil, tfresource.NewEmptyResultError(input) + return nil, &resource.NotFoundError{ + Message: "empty result", + LastRequest: input, + } } if len(result.SecurityGroups) > 1 { - return nil, tfresource.NewTooManyResultsError(len(result.SecurityGroups), input) + return nil, &resource.NotFoundError{ + Message: fmt.Sprintf("too many results: wanted 1, got %d", len(result.SecurityGroups)), + LastRequest: input, + } } return result.SecurityGroups[0], nil diff --git a/aws/internal/tfresource/finder_errors.go b/aws/internal/tfresource/finder_errors.go deleted file mode 100644 index d57ee8ca688b..000000000000 --- a/aws/internal/tfresource/finder_errors.go +++ /dev/null @@ -1,79 +0,0 @@ -package tfresource - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -type EmptyResultError struct { - LastRequest interface{} -} - -var ErrEmptyResult = &EmptyResultError{} - -func NewEmptyResultError(lastRequest interface{}) error { - return &EmptyResultError{ - LastRequest: lastRequest, - } -} - -func (e *EmptyResultError) Error() string { - return "empty result" -} - -func (e *EmptyResultError) Is(err error) bool { - _, ok := err.(*EmptyResultError) - return ok -} - -func (e *EmptyResultError) As(target interface{}) bool { - t, ok := target.(**resource.NotFoundError) - if !ok { - return false - } - - *t = &resource.NotFoundError{ - Message: e.Error(), - LastRequest: e.LastRequest, - } - - return true -} - -type TooManyResultsError struct { - Count int - LastRequest interface{} -} - -var ErrTooManyResults = &TooManyResultsError{} - -func NewTooManyResultsError(count int, lastRequest interface{}) error { - return &TooManyResultsError{ - Count: count, - LastRequest: lastRequest, - } -} - -func (e *TooManyResultsError) Error() string { - return fmt.Sprintf("too many results: wanted 1, got %d", e.Count) -} - -func (e *TooManyResultsError) Is(err error) bool { - _, ok := err.(*TooManyResultsError) - return ok -} - -func (e *TooManyResultsError) As(target interface{}) bool { - t, ok := target.(**resource.NotFoundError) - if !ok { - return false - } - - *t = &resource.NotFoundError{ - Message: e.Error(), - LastRequest: e.LastRequest, - } - - return true -} diff --git a/aws/internal/tfresource/finder_errors_test.go b/aws/internal/tfresource/finder_errors_test.go deleted file mode 100644 index a96f7b522ae5..000000000000 --- a/aws/internal/tfresource/finder_errors_test.go +++ /dev/null @@ -1,156 +0,0 @@ -package tfresource - -import ( - "errors" - "fmt" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestEmptyResultErrorAsNotFoundError(t *testing.T) { - lastRequest := 123 - err := NewEmptyResultError(lastRequest) - - var nfe *resource.NotFoundError - ok := errors.As(err, &nfe) - - if !ok { - t.Fatal("expected errors.As() to return true") - } - if nfe.Message != "empty result" { - t.Errorf(`expected Message to be "empty result", got %q`, nfe.Message) - } - if nfe.LastRequest != lastRequest { - t.Errorf("unexpected value for LastRequest") - } -} - -func TestEmptyResultErrorIs(t *testing.T) { - testCases := []struct { - name string - err error - expected bool - }{ - { - name: "compare to nil", - err: nil, - }, - { - name: "other error", - err: errors.New("test"), - }, - { - name: "EmptyResultError with LastRequest", - err: &EmptyResultError{ - LastRequest: 123, - }, - expected: true, - }, - { - name: "ErrEmptyResult", - err: ErrEmptyResult, - expected: true, - }, - { - name: "wrapped other error", - err: fmt.Errorf("test: %w", errors.New("test")), - }, - { - name: "wrapped EmptyResultError with LastRequest", - err: fmt.Errorf("test: %w", &EmptyResultError{ - LastRequest: 123, - }), - expected: true, - }, - { - name: "wrapped ErrEmptyResult", - err: fmt.Errorf("test: %w", ErrEmptyResult), - expected: true, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - err := &EmptyResultError{} - ok := errors.Is(testCase.err, err) - if ok != testCase.expected { - t.Errorf("got %t, expected %t", ok, testCase.expected) - } - }) - } -} - -func TestTooManyResultsErrorAsNotFoundError(t *testing.T) { - count := 2 - lastRequest := 123 - err := NewTooManyResultsError(count, lastRequest) - - var nfe *resource.NotFoundError - ok := errors.As(err, &nfe) - - if !ok { - t.Fatal("expected errors.As() to return true") - } - if expected := fmt.Sprintf("too many results: wanted 1, got %d", count); nfe.Message != expected { - t.Errorf(`expected Message to be %q, got %q`, expected, nfe.Message) - } - if nfe.LastRequest != lastRequest { - t.Errorf("unexpected value for LastRequest") - } -} - -func TestTooManyResultsErrorIs(t *testing.T) { - testCases := []struct { - name string - err error - expected bool - }{ - { - name: "compare to nil", - err: nil, - }, - { - name: "other error", - err: errors.New("test"), - }, - { - name: "TooManyResultsError with LastRequest", - err: &TooManyResultsError{ - LastRequest: 123, - }, - expected: true, - }, - { - name: "ErrTooManyResults", - err: ErrTooManyResults, - expected: true, - }, - { - name: "wrapped other error", - err: fmt.Errorf("test: %w", errors.New("test")), - }, - { - name: "wrapped TooManyResultsError with LastRequest", - err: fmt.Errorf("test: %w", &TooManyResultsError{ - LastRequest: 123, - }), - expected: true, - }, - { - name: "wrapped ErrTooManyResults", - err: fmt.Errorf("test: %w", ErrTooManyResults), - expected: true, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - err := &TooManyResultsError{} - ok := errors.Is(testCase.err, err) - if ok != testCase.expected { - t.Errorf("got %t, expected %t", ok, testCase.expected) - } - }) - } -} From f7a03408934ec47063312269f2cb515d97559945 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 25 Mar 2021 20:00:41 -0700 Subject: [PATCH 1155/1208] Replace calls to `DescribeSecurityGroups` with single result with `finder.SecurityGroup...()` --- aws/data_source_aws_elb.go | 5 +- ...esource_aws_default_security_group_test.go | 31 ++-- aws/resource_aws_elb.go | 2 +- aws/resource_aws_emr_cluster_test.go | 68 +++----- ...s_globalaccelerator_endpoint_group_test.go | 23 +-- aws/resource_aws_security_group.go | 149 ++++------------- aws/resource_aws_security_group_rule.go | 98 +++--------- aws/resource_aws_security_group_rule_test.go | 54 ++----- aws/resource_aws_security_group_test.go | 150 ++++++------------ 9 files changed, 162 insertions(+), 418 deletions(-) diff --git a/aws/data_source_aws_elb.go b/aws/data_source_aws_elb.go index dd53bdc9bda4..23ccc7090722 100644 --- a/aws/data_source_aws_elb.go +++ b/aws/data_source_aws_elb.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/service/elb" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" ) func dataSourceAwsElb() *schema.Resource { @@ -261,11 +262,11 @@ func dataSourceAwsElbRead(d *schema.ResourceData, meta interface{}) error { var elbVpc string if lb.VPCId != nil { elbVpc = aws.StringValue(lb.VPCId) - sgId, err := sourceSGIdByName(ec2conn, aws.StringValue(lb.SourceSecurityGroup.GroupName), elbVpc) + sg, err := finder.SecurityGroupByNameAndVpcID(ec2conn, aws.StringValue(lb.SourceSecurityGroup.GroupName), elbVpc) if err != nil { return fmt.Errorf("error looking up ELB Security Group ID: %w", err) } else { - d.Set("source_security_group_id", sgId) + d.Set("source_security_group_id", sg.GroupId) } } } diff --git a/aws/resource_aws_default_security_group_test.go b/aws/resource_aws_default_security_group_test.go index 0792d0654b4e..30bfd9eb01ac 100644 --- a/aws/resource_aws_default_security_group_test.go +++ b/aws/resource_aws_default_security_group_test.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" ) func TestAccAWSDefaultSecurityGroup_Vpc_basic(t *testing.T) { @@ -179,24 +180,19 @@ func testAccCheckAWSDefaultSecurityGroupExists(n string, group *ec2.SecurityGrou } if rs.Primary.ID == "" { - return fmt.Errorf("No Security Group is set") + return fmt.Errorf("No EC2 Default Security Group ID is set") } conn := testAccProvider.Meta().(*AWSClient).ec2conn - req := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(rs.Primary.ID)}, - } - resp, err := conn.DescribeSecurityGroups(req) + + sg, err := finder.SecurityGroupByID(conn, rs.Primary.ID) if err != nil { return err } - if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == rs.Primary.ID { - *group = *resp.SecurityGroups[0] - return nil - } + *group = *sg - return fmt.Errorf("Security Group not found") + return nil } } @@ -213,21 +209,12 @@ func testAccCheckAWSDefaultSecurityGroupEc2ClassicExists(n string, group *ec2.Se conn := testAccProviderEc2Classic.Meta().(*AWSClient).ec2conn - input := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(rs.Primary.ID)}, - } - - resp, err := conn.DescribeSecurityGroups(input) - + sg, err := finder.SecurityGroupByID(conn, rs.Primary.ID) if err != nil { - return fmt.Errorf("error describing EC2 Default Security Group (%s): %w", rs.Primary.ID, err) - } - - if len(resp.SecurityGroups) == 0 || aws.StringValue(resp.SecurityGroups[0].GroupId) != rs.Primary.ID { - return fmt.Errorf("EC2 Default Security Group (%s) not found", rs.Primary.ID) + return err } - *group = *resp.SecurityGroups[0] + *group = *sg return nil } diff --git a/aws/resource_aws_elb.go b/aws/resource_aws_elb.go index 665ef14276f9..06cd1507d0d0 100644 --- a/aws/resource_aws_elb.go +++ b/aws/resource_aws_elb.go @@ -411,7 +411,7 @@ func flattenAwsELbResource(d *schema.ResourceData, ec2conn *ec2.EC2, elbconn *el if err != nil { return fmt.Errorf("Error looking up ELB Security Group ID: %w", err) } else { - d.Set("source_security_group_id", aws.StringValue(sg.GroupId)) + d.Set("source_security_group_id", sg.GroupId) } } } diff --git a/aws/resource_aws_emr_cluster_test.go b/aws/resource_aws_emr_cluster_test.go index 11e4891d379b..a10cca677822 100644 --- a/aws/resource_aws_emr_cluster_test.go +++ b/aws/resource_aws_emr_cluster_test.go @@ -8,12 +8,12 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/emr" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" ) func init() { @@ -26,7 +26,7 @@ func init() { func testSweepEmrClusters(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } conn := client.(*AWSClient).emrconn @@ -71,7 +71,7 @@ func testSweepEmrClusters(region string) error { log.Printf("[WARN] Skipping EMR Cluster sweep for %s: %s", region, err) return nil } - return fmt.Errorf("error retrieving EMR Clusters: %s", err) + return fmt.Errorf("error retrieving EMR Clusters: %w", err) } return nil @@ -1495,25 +1495,24 @@ func testAccCheckAWSEmrDestroy(s *terraform.State) error { continue } - params := &emr.DescribeClusterInput{ + input := &emr.DescribeClusterInput{ ClusterId: aws.String(rs.Primary.ID), } - describe, err := conn.DescribeCluster(params) - - if err == nil { - if describe.Cluster != nil && - *describe.Cluster.Status.State == "WAITING" { - return fmt.Errorf("EMR Cluster still exists") - } + output, err := conn.DescribeCluster(input) + if err != nil { + return err } - providerErr, ok := err.(awserr.Error) - if !ok { - return err + // if output.Cluster != nil && + // *output.Cluster.Status.State == "WAITING" { + // return fmt.Errorf("EMR Cluster still exists") + // } + if output.Cluster == nil || output.Cluster.Status == nil || aws.StringValue(output.Cluster.Status.State) == emr.ClusterStateTerminated { + continue } - log.Printf("[ERROR] %v", providerErr) + return fmt.Errorf("EMR Cluster still exists") } return nil @@ -1533,7 +1532,7 @@ func testAccCheckAWSEmrClusterExists(n string, v *emr.Cluster) resource.TestChec ClusterId: aws.String(rs.Primary.ID), }) if err != nil { - return fmt.Errorf("EMR error: %v", err) + return fmt.Errorf("EMR error: %w", err) } if describe.Cluster == nil || *describe.Cluster.Id != rs.Primary.ID { @@ -1604,7 +1603,7 @@ func testAccCheckAWSEmrClusterDisappears(cluster *emr.Cluster) resource.TestChec } if err != nil { - return fmt.Errorf("error waiting for EMR Cluster (%s) Instances to drain: %s", id, err) + return fmt.Errorf("error waiting for EMR Cluster (%s) Instances to drain: %w", id, err) } return nil @@ -1639,10 +1638,10 @@ func testAccEmrDeleteManagedSecurityGroups(conn *ec2.EC2, vpc *ec2.Vpc) error { } for groupName := range managedSecurityGroups { - securityGroup, err := testAccEmrDescribeManagedSecurityGroup(conn, vpc, groupName) + securityGroup, err := finder.SecurityGroupByNameAndVpcID(conn, groupName, aws.StringValue(vpc.VpcId)) if err != nil { - return fmt.Errorf("error describing EMR Managed Security Group (%s): %s", groupName, err) + return fmt.Errorf("error describing EMR Managed Security Group (%s): %w", groupName, err) } managedSecurityGroups[groupName] = securityGroup @@ -1658,7 +1657,7 @@ func testAccEmrDeleteManagedSecurityGroups(conn *ec2.EC2, vpc *ec2.Vpc) error { err := testAccEmrRevokeManagedSecurityGroup(conn, securityGroup) if err != nil { - return fmt.Errorf("error revoking EMR Managed Security Group (%s): %s", groupName, err) + return fmt.Errorf("error revoking EMR Managed Security Group (%s): %w", groupName, err) } } @@ -1670,40 +1669,13 @@ func testAccEmrDeleteManagedSecurityGroups(conn *ec2.EC2, vpc *ec2.Vpc) error { err := testAccEmrDeleteManagedSecurityGroup(conn, securityGroup) if err != nil { - return fmt.Errorf("error deleting EMR Managed Security Group (%s): %s", groupName, err) + return fmt.Errorf("error deleting EMR Managed Security Group (%s): %w", groupName, err) } } return nil } -func testAccEmrDescribeManagedSecurityGroup(conn *ec2.EC2, vpc *ec2.Vpc, securityGroupName string) (*ec2.SecurityGroup, error) { - input := &ec2.DescribeSecurityGroupsInput{ - Filters: []*ec2.Filter{ - { - Name: aws.String("group-name"), - Values: aws.StringSlice([]string{securityGroupName}), - }, - { - Name: aws.String("vpc-id"), - Values: []*string{vpc.VpcId}, - }, - }, - } - - output, err := conn.DescribeSecurityGroups(input) - - if err != nil { - return nil, err - } - - if output == nil || len(output.SecurityGroups) != 1 { - return nil, nil - } - - return output.SecurityGroups[0], nil -} - func testAccEmrRevokeManagedSecurityGroup(conn *ec2.EC2, securityGroup *ec2.SecurityGroup) error { input := &ec2.RevokeSecurityGroupIngressInput{ GroupId: securityGroup.GroupId, diff --git a/aws/resource_aws_globalaccelerator_endpoint_group_test.go b/aws/resource_aws_globalaccelerator_endpoint_group_test.go index 0dda503b349d..aac2d49854bd 100644 --- a/aws/resource_aws_globalaccelerator_endpoint_group_test.go +++ b/aws/resource_aws_globalaccelerator_endpoint_group_test.go @@ -1,6 +1,7 @@ package aws import ( + "errors" "fmt" "regexp" "testing" @@ -12,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + ec2finder "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/globalaccelerator/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -469,27 +471,18 @@ func testAccCheckGlobalAcceleratorEndpointGroupDeleteGlobalAcceleratorSecurityGr return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn - input := &ec2.DescribeSecurityGroupsInput{ - Filters: buildEC2AttributeFilterList( - map[string]string{ - "group-name": "GlobalAccelerator", - "vpc-id": aws.StringValue(vpc.VpcId), - }, - ), + sg, err := ec2finder.SecurityGroupByNameAndVpcID(conn, "GlobalAccelerator", aws.StringValue(vpc.VpcId)) + var nfe *resource.NotFoundError + if errors.As(err, &nfe) { + // Already gone. + return nil } - - output, err := conn.DescribeSecurityGroups(input) if err != nil { return err } - if len(output.SecurityGroups) == 0 { - // Already gone. - return nil - } - _, err = conn.DeleteSecurityGroup(&ec2.DeleteSecurityGroupInput{ - GroupId: output.SecurityGroups[0].GroupId, + GroupId: sg.GroupId, }) if err != nil { return err diff --git a/aws/resource_aws_security_group.go b/aws/resource_aws_security_group.go index 31a08ea60b35..ffb90175518d 100644 --- a/aws/resource_aws_security_group.go +++ b/aws/resource_aws_security_group.go @@ -2,6 +2,7 @@ package aws import ( "bytes" + "errors" "fmt" "log" "sort" @@ -11,7 +12,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -20,6 +20,8 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" ) func resourceAwsSecurityGroup() *schema.Resource { @@ -262,11 +264,10 @@ func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er securityGroupOpts.GroupName = aws.String(groupName) var err error - log.Printf( - "[DEBUG] Security Group create configuration: %#v", securityGroupOpts) + log.Printf("[DEBUG] Security Group create configuration: %s", securityGroupOpts) createResp, err := conn.CreateSecurityGroup(securityGroupOpts) if err != nil { - return fmt.Errorf("Error creating Security Group: %s", err) + return fmt.Errorf("Error creating Security Group: %w", err) } d.SetId(aws.StringValue(createResp.GroupId)) @@ -274,16 +275,15 @@ func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er log.Printf("[INFO] Security Group ID: %s", d.Id()) // Wait for the security group to truly exist - resp, err := waitForSgToExist(conn, d.Id(), d.Timeout(schema.TimeoutCreate)) + group, err := waiter.SecurityGroupCreated(conn, d.Id(), d.Timeout(schema.TimeoutCreate)) if err != nil { return fmt.Errorf( - "Error waiting for Security Group (%s) to become available: %s", + "Error waiting for Security Group (%s) to become available: %w", d.Id(), err) } // AWS defaults all Security Groups to have an ALLOW ALL egress rule. Here we // revoke that rule, so users don't unknowingly have/use it. - group := resp.(*ec2.SecurityGroup) if group.VpcId != nil && *group.VpcId != "" { log.Printf("[DEBUG] Revoking default egress rule for Security Group for %s", d.Id()) @@ -304,9 +304,7 @@ func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er } if _, err = conn.RevokeSecurityGroupEgress(req); err != nil { - return fmt.Errorf( - "Error revoking default egress rule for Security Group (%s): %s", - d.Id(), err) + return fmt.Errorf("Error revoking default egress rule for Security Group (%s): %w", d.Id(), err) } log.Printf("[DEBUG] Revoking default IPv6 egress rule for Security Group for %s", d.Id()) @@ -330,10 +328,8 @@ func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er if err != nil { //If we have a NotFound or InvalidParameterValue, then we are trying to remove the default IPv6 egress of a non-IPv6 //enabled SG - if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() != "InvalidPermission.NotFound" && !isAWSErr(err, "InvalidParameterValue", "remote-ipv6-range") { - return fmt.Errorf( - "Error revoking default IPv6 egress rule for Security Group (%s): %s", - d.Id(), err) + if !tfawserr.ErrCodeEquals(err, "InvalidPermission.NotFound") && !tfawserr.ErrMessageContains(err, "InvalidParameterValue", "remote-ipv6-range") { + return fmt.Errorf("Error revoking default IPv6 egress rule for Security Group (%s): %w", d.Id(), err) } } @@ -347,25 +343,16 @@ func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - var sgRaw interface{} - var err error - if d.IsNewResource() { - sgRaw, err = waitForSgToExist(conn, d.Id(), d.Timeout(schema.TimeoutRead)) - } else { - sgRaw, _, err = SGStateRefreshFunc(conn, d.Id())() - } - - if err != nil { - return err - } - - if sgRaw == nil { + sg, err := finder.SecurityGroupByID(conn, d.Id()) + var nfe *resource.NotFoundError + if errors.As(err, &nfe) { log.Printf("[WARN] Security group (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - - sg := sgRaw.(*ec2.SecurityGroup) + if err != nil { + return fmt.Errorf("error reading Security Group (%s): %w", d.Id(), err) + } remoteIngressRules := resourceAwsSecurityGroupIPPermGather(d.Id(), sg.IpPermissions, sg.OwnerId) remoteEgressRules := resourceAwsSecurityGroupIPPermGather(d.Id(), sg.IpPermissionsEgress, sg.OwnerId) @@ -394,11 +381,11 @@ func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro d.Set("vpc_id", sg.VpcId) if err := d.Set("ingress", ingressRules); err != nil { - log.Printf("[WARN] Error setting Ingress rule set for (%s): %s", d.Id(), err) + return fmt.Errorf("error setting ingress: %w", err) } if err := d.Set("egress", egressRules); err != nil { - log.Printf("[WARN] Error setting Egress rule set for (%s): %s", d.Id(), err) + return fmt.Errorf("error setting egress: %w", err) } tags := keyvaluetags.Ec2KeyValueTags(sg.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -418,25 +405,11 @@ func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - var sgRaw interface{} - var err error - if d.IsNewResource() { - sgRaw, err = waitForSgToExist(conn, d.Id(), d.Timeout(schema.TimeoutRead)) - } else { - sgRaw, _, err = SGStateRefreshFunc(conn, d.Id())() - } - + group, err := finder.SecurityGroupByID(conn, d.Id()) if err != nil { - return err - } - if sgRaw == nil { - log.Printf("[WARN] Security group (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil + return fmt.Errorf("error updating Security Group (%s): %w", d.Id(), err) } - group := sgRaw.(*ec2.SecurityGroup) - err = resourceAwsSecurityGroupUpdateRules(d, "ingress", meta, group) if err != nil { return err @@ -453,7 +426,7 @@ func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er o, n := d.GetChange("tags_all") if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating EC2 Security Group (%s) tags: %s", d.Id(), err) + return fmt.Errorf("error updating EC2 Security Group (%s) tags: %w", d.Id(), err) } } @@ -466,7 +439,7 @@ func resourceAwsSecurityGroupDelete(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] Security Group destroy: %v", d.Id()) if err := deleteLingeringLambdaENIs(conn, "group-id", d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("error deleting Lambda ENIs using Security Group (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting Lambda ENIs using Security Group (%s): %w", d.Id(), err) } // conditionally revoke rules first before attempting to delete the group @@ -509,37 +482,31 @@ func resourceAwsSecurityGroupDelete(d *schema.ResourceData, meta interface{}) er } } if err != nil { - return fmt.Errorf("Error deleting security group: %s", err) + return fmt.Errorf("Error deleting security group: %w", err) } return nil } // Revoke all ingress/egress rules that a Security Group has func forceRevokeSecurityGroupRules(conn *ec2.EC2, d *schema.ResourceData) error { - sgRaw, _, err := SGStateRefreshFunc(conn, d.Id())() + group, err := finder.SecurityGroupByID(conn, d.Id()) if err != nil { return err } - if sgRaw == nil { - return nil - } - group := sgRaw.(*ec2.SecurityGroup) if len(group.IpPermissions) > 0 { req := &ec2.RevokeSecurityGroupIngressInput{ GroupId: group.GroupId, IpPermissions: group.IpPermissions, } - if group.VpcId == nil || *group.VpcId == "" { + if aws.StringValue(group.VpcId) == "" { req.GroupId = nil req.GroupName = group.GroupName } _, err = conn.RevokeSecurityGroupIngress(req) if err != nil { - return fmt.Errorf( - "Error revoking security group %s rules: %s", - *group.GroupId, err) + return fmt.Errorf("error revoking Security Group (%s) rules: %w", aws.StringValue(group.GroupId), err) } } @@ -551,9 +518,7 @@ func forceRevokeSecurityGroupRules(conn *ec2.EC2, d *schema.ResourceData) error _, err = conn.RevokeSecurityGroupEgress(req) if err != nil { - return fmt.Errorf( - "Error revoking security group %s rules: %s", - *group.GroupId, err) + return fmt.Errorf("error revoking Security Group (%s) rules: %w", aws.StringValue(group.GroupId), err) } } @@ -775,9 +740,7 @@ func resourceAwsSecurityGroupUpdateRules( } if err != nil { - return fmt.Errorf( - "Error revoking security group %s rules: %s", - ruleset, err) + return fmt.Errorf("error revoking Security Group (%s) rules: %w", ruleset, err) } } @@ -805,9 +768,7 @@ func resourceAwsSecurityGroupUpdateRules( } if err != nil { - return fmt.Errorf( - "Error authorizing security group %s rules: %s", - ruleset, err) + return fmt.Errorf("error authorizing Security Group (%s) rules: %w", ruleset, err) } } } @@ -815,50 +776,6 @@ func resourceAwsSecurityGroupUpdateRules( return nil } -// SGStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch -// a security group. -func SGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - req := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(id)}, - } - resp, err := conn.DescribeSecurityGroups(req) - if err != nil { - if ec2err, ok := err.(awserr.Error); ok { - if ec2err.Code() == "InvalidSecurityGroupID.NotFound" || - ec2err.Code() == "InvalidGroup.NotFound" { - resp = nil - err = nil - } - } - - if err != nil { - log.Printf("Error on SGStateRefresh: %s", err) - return nil, "", err - } - } - - if resp == nil { - return nil, "", nil - } - - group := resp.SecurityGroups[0] - return group, "exists", nil - } -} - -func waitForSgToExist(conn *ec2.EC2, id string, timeout time.Duration) (interface{}, error) { - log.Printf("[DEBUG] Waiting for Security Group (%s) to exist", id) - stateConf := &resource.StateChangeConf{ - Pending: []string{""}, - Target: []string{"exists"}, - Refresh: SGStateRefreshFunc(conn, id), - Timeout: timeout, - } - - return stateConf.WaitForState() -} - // matchRules receives the group id, type of rules, and the local / remote maps // of rules. We iterate through the local set of rules trying to find a matching // remote rule, which may be structured differently because of how AWS @@ -1443,7 +1360,7 @@ func deleteLingeringLambdaENIs(conn *ec2.EC2, filterName, resourceId string, tim }) if err != nil { - return fmt.Errorf("error describing ENIs: %s", err) + return fmt.Errorf("error describing ENIs: %w", err) } for _, eni := range resp.NetworkInterfaces { @@ -1475,7 +1392,7 @@ func deleteLingeringLambdaENIs(conn *ec2.EC2, filterName, resourceId string, tim } if err != nil { - return fmt.Errorf("error waiting for Lambda V2N ENI (%s) to become available for detachment: %s", eniId, err) + return fmt.Errorf("error waiting for Lambda V2N ENI (%s) to become available for detachment: %w", eniId, err) } eni = eniRaw.(*ec2.NetworkInterface) @@ -1484,13 +1401,13 @@ func deleteLingeringLambdaENIs(conn *ec2.EC2, filterName, resourceId string, tim err = detachNetworkInterface(conn, eni, timeout) if err != nil { - return fmt.Errorf("error detaching Lambda ENI (%s): %s", eniId, err) + return fmt.Errorf("error detaching Lambda ENI (%s): %w", eniId, err) } err = deleteNetworkInterface(conn, eniId) if err != nil { - return fmt.Errorf("error deleting Lambda ENI (%s): %s", eniId, err) + return fmt.Errorf("error deleting Lambda ENI (%s): %w", eniId, err) } } diff --git a/aws/resource_aws_security_group_rule.go b/aws/resource_aws_security_group_rule.go index c9cdc3888135..7f3bfdf8c4d5 100644 --- a/aws/resource_aws_security_group_rule.go +++ b/aws/resource_aws_security_group_rule.go @@ -10,12 +10,14 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "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/hashcode" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsSecurityGroupRule() *schema.Resource { @@ -155,7 +157,7 @@ func resourceAwsSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{} awsMutexKV.Lock(sg_id) defer awsMutexKV.Unlock(sg_id) - sg, err := findResourceSecurityGroup(conn, sg_id) + sg, err := finder.SecurityGroupByID(conn, sg_id) if err != nil { return err } @@ -209,20 +211,15 @@ func resourceAwsSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{} return fmt.Errorf("Security Group Rule must be type 'ingress' or type 'egress'") } - if autherr != nil { - if awsErr, ok := autherr.(awserr.Error); ok { - if awsErr.Code() == "InvalidPermission.Duplicate" { - return fmt.Errorf(`[WARN] A duplicate Security Group rule was found on (%s). This may be + if tfawserr.ErrCodeEquals(autherr, "InvalidPermission.Duplicate") { + return fmt.Errorf(`[WARN] A duplicate Security Group rule was found on (%s). This may be a side effect of a now-fixed Terraform issue causing two security groups with identical attributes but different source_security_group_ids to overwrite each other in the state. See https://github.com/hashicorp/terraform/pull/2376 for more -information and instructions for recovery. Error message: %s`, sg_id, awsErr.Message()) - } - } - - return fmt.Errorf( - "Error authorizing security group rule type %s: %s", - ruleType, autherr) +information and instructions for recovery. Error: %w`, sg_id, autherr) + } + if autherr != nil { + return fmt.Errorf("Error authorizing security group rule type %s: %w", ruleType, autherr) } var rules []*ec2.IpPermission @@ -230,7 +227,7 @@ information and instructions for recovery. Error message: %s`, sg_id, awsErr.Mes log.Printf("[DEBUG] Computed group rule ID %s", id) err = resource.Retry(5*time.Minute, func() *resource.RetryError { - sg, err := findResourceSecurityGroup(conn, sg_id) + sg, err := finder.SecurityGroupByID(conn, sg_id) if err != nil { log.Printf("[DEBUG] Error finding Security Group (%s) for Rule (%s): %s", sg_id, id, err) @@ -255,9 +252,9 @@ information and instructions for recovery. Error message: %s`, sg_id, awsErr.Mes return nil }) if isResourceTimeoutError(err) { - sg, err := findResourceSecurityGroup(conn, sg_id) + sg, err := finder.SecurityGroupByID(conn, sg_id) if err != nil { - return fmt.Errorf("Error finding security group: %s", err) + return fmt.Errorf("Error finding security group: %w", err) } switch ruleType { @@ -269,7 +266,7 @@ information and instructions for recovery. Error message: %s`, sg_id, awsErr.Mes rule := findRuleMatch(perm, rules, isVPC) if rule == nil { - return fmt.Errorf("Error finding matching security group rule: %s", err) + return fmt.Errorf("Error finding matching security group rule: %w", err) } } if err != nil { @@ -283,17 +280,17 @@ information and instructions for recovery. Error message: %s`, sg_id, awsErr.Mes func resourceAwsSecurityGroupRuleRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn sg_id := d.Get("security_group_id").(string) - sg, err := findResourceSecurityGroup(conn, sg_id) - if _, notFound := err.(securityGroupNotFound); notFound { - // The security group containing this rule no longer exists. + sg, err := finder.SecurityGroupByID(conn, sg_id) + if tfresource.NotFound(err) { + log.Printf("[WARN] Security Group (%s) not found, removing Rule (%s) from state", sg_id, d.Id()) d.SetId("") return nil } if err != nil { - return fmt.Errorf("Error finding security group (%s) for rule (%s): %s", sg_id, d.Id(), err) + return fmt.Errorf("error finding Security Group (%s) for Rule (%s): %w", sg_id, d.Id(), err) } - isVPC := sg.VpcId != nil && *sg.VpcId != "" + isVPC := aws.StringValue(sg.VpcId) != "" var rule *ec2.IpPermission var rules []*ec2.IpPermission @@ -363,7 +360,7 @@ func resourceAwsSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{} awsMutexKV.Lock(sg_id) defer awsMutexKV.Unlock(sg_id) - sg, err := findResourceSecurityGroup(conn, sg_id) + sg, err := finder.SecurityGroupByID(conn, sg_id) if err != nil { return err } @@ -385,14 +382,11 @@ func resourceAwsSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{} _, err = conn.RevokeSecurityGroupIngress(req) if err != nil { - return fmt.Errorf( - "Error revoking security group %s rules: %s", - sg_id, err) + return fmt.Errorf("Error revoking security group %s rules: %w", sg_id, err) } case "egress": - log.Printf("[DEBUG] Revoking security group %#v %s rule: %#v", - sg_id, "egress", perm) + log.Printf("[DEBUG] Revoking security group %#v %s rule: %#v", sg_id, "egress", perm) req := &ec2.RevokeSecurityGroupEgressInput{ GroupId: sg.GroupId, IpPermissions: []*ec2.IpPermission{perm}, @@ -401,49 +395,13 @@ func resourceAwsSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{} _, err = conn.RevokeSecurityGroupEgress(req) if err != nil { - return fmt.Errorf( - "Error revoking security group %s rules: %s", - sg_id, err) + return fmt.Errorf("Error revoking security group %s rules: %w", sg_id, err) } } return nil } -func findResourceSecurityGroup(conn *ec2.EC2, id string) (*ec2.SecurityGroup, error) { - req := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(id)}, - } - resp, err := conn.DescribeSecurityGroups(req) - if err, ok := err.(awserr.Error); ok && err.Code() == "InvalidGroup.NotFound" { - return nil, securityGroupNotFound{id, nil} - } - if err != nil { - return nil, err - } - if resp == nil { - return nil, securityGroupNotFound{id, nil} - } - if len(resp.SecurityGroups) != 1 || resp.SecurityGroups[0] == nil { - return nil, securityGroupNotFound{id, resp.SecurityGroups} - } - - return resp.SecurityGroups[0], nil -} - -type securityGroupNotFound struct { - id string - securityGroups []*ec2.SecurityGroup -} - -func (err securityGroupNotFound) Error() string { - if err.securityGroups == nil { - return fmt.Sprintf("No security group with ID %q", err.id) - } - return fmt.Sprintf("Expected to find one security group with ID %q, got: %#v", - err.id, err.securityGroups) -} - // ByGroupPair implements sort.Interface for []*ec2.UserIDGroupPairs based on // GroupID or GroupName field (only one should be set). type ByGroupPair []*ec2.UserIdGroupPair @@ -902,7 +860,7 @@ func resourceSecurityGroupRuleDescriptionUpdate(conn *ec2.EC2, d *schema.Resourc awsMutexKV.Lock(sg_id) defer awsMutexKV.Unlock(sg_id) - sg, err := findResourceSecurityGroup(conn, sg_id) + sg, err := finder.SecurityGroupByID(conn, sg_id) if err != nil { return err } @@ -922,9 +880,7 @@ func resourceSecurityGroupRuleDescriptionUpdate(conn *ec2.EC2, d *schema.Resourc _, err = conn.UpdateSecurityGroupRuleDescriptionsIngress(req) if err != nil { - return fmt.Errorf( - "Error updating security group %s rule description: %s", - sg_id, err) + return fmt.Errorf("Error updating security group %s rule description: %w", sg_id, err) } case "egress": req := &ec2.UpdateSecurityGroupRuleDescriptionsEgressInput{ @@ -935,9 +891,7 @@ func resourceSecurityGroupRuleDescriptionUpdate(conn *ec2.EC2, d *schema.Resourc _, err = conn.UpdateSecurityGroupRuleDescriptionsEgress(req) if err != nil { - return fmt.Errorf( - "Error updating security group %s rule description: %s", - sg_id, err) + return fmt.Errorf("Error updating security group %s rule description: %w", sg_id, err) } } diff --git a/aws/resource_aws_security_group_rule_test.go b/aws/resource_aws_security_group_rule_test.go index cecb8378ebf1..92f8bcab8198 100644 --- a/aws/resource_aws_security_group_rule_test.go +++ b/aws/resource_aws_security_group_rule_test.go @@ -10,11 +10,12 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" "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" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestIpPermissionIDHash(t *testing.T) { @@ -663,14 +664,11 @@ func TestAccAWSSecurityGroupRule_PrefixListEgress(t *testing.T) { prefixListsOutput, err := conn.DescribePrefixLists(prefixListInput) if err != nil { - _, ok := err.(awserr.Error) - if !ok { - return fmt.Errorf("Error reading VPC Endpoint prefix list: %s", err.Error()) - } + return fmt.Errorf("error reading VPC Endpoint prefix list: %w", err) } if len(prefixListsOutput.PrefixLists) != 1 { - return fmt.Errorf("There are multiple prefix lists associated with the service name '%s'. Unexpected", prefixListsOutput) + return fmt.Errorf("unexpected multiple prefix lists associated with the service: %s", prefixListsOutput) } p = ec2.IpPermission{ @@ -1066,14 +1064,11 @@ func TestAccAWSSecurityGroupRule_MultiDescription(t *testing.T) { prefixListsOutput, err := conn.DescribePrefixLists(prefixListInput) if err != nil { - _, ok := err.(awserr.Error) - if !ok { - return fmt.Errorf("Error reading VPC Endpoint prefix list: %s", err.Error()) - } + return fmt.Errorf("error reading VPC Endpoint prefix list: %w", err) } if len(prefixListsOutput.PrefixLists) != 1 { - return fmt.Errorf("There are multiple prefix lists associated with the service name '%s'. Unexpected", prefixListsOutput) + return fmt.Errorf("unexpected multiple prefix lists associated with the service: %s", prefixListsOutput) } rule4 = ec2.IpPermission{ @@ -1188,27 +1183,15 @@ func testAccCheckAWSSecurityGroupRuleDestroy(s *terraform.State) error { continue } - // Retrieve our group - req := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(rs.Primary.ID)}, - } - resp, err := conn.DescribeSecurityGroups(req) - if err == nil { - if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == rs.Primary.ID { - return fmt.Errorf("Security Group (%s) still exists.", rs.Primary.ID) - } - - return nil - } - - ec2err, ok := err.(awserr.Error) - if !ok { - return err + _, err := finder.SecurityGroupByID(conn, rs.Primary.ID) + if tfresource.NotFound(err) { + continue } - // Confirm error code is what we want - if ec2err.Code() != "InvalidGroup.NotFound" { + if err != nil { return err } + + return fmt.Errorf("Security Group (%s) still exists.", rs.Primary.ID) } return nil @@ -1226,20 +1209,15 @@ func testAccCheckAWSSecurityGroupRuleExists(n string, group *ec2.SecurityGroup) } conn := testAccProvider.Meta().(*AWSClient).ec2conn - req := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(rs.Primary.ID)}, - } - resp, err := conn.DescribeSecurityGroups(req) + + sg, err := finder.SecurityGroupByID(conn, rs.Primary.ID) if err != nil { return err } - if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == rs.Primary.ID { - *group = *resp.SecurityGroups[0] - return nil - } + *group = *sg - return fmt.Errorf("Security Group not found") + return nil } } diff --git a/aws/resource_aws_security_group_test.go b/aws/resource_aws_security_group_test.go index b0a97c8a0c49..e85547ba1daa 100644 --- a/aws/resource_aws_security_group_test.go +++ b/aws/resource_aws_security_group_test.go @@ -12,14 +12,14 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ec2" - "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/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) // add sweeper to delete known test sgs @@ -36,7 +36,7 @@ func init() { func testSweepSecurityGroups(region string) error { client, err := sharedClientForRegion(region) if err != nil { - return fmt.Errorf("error getting client: %s", err) + return fmt.Errorf("error getting client: %w", err) } conn := client.(*AWSClient).ec2conn @@ -82,7 +82,7 @@ func testSweepSecurityGroups(region string) error { } if err != nil { - return fmt.Errorf("Error retrieving EC2 Security Groups: %s", err) + return fmt.Errorf("Error retrieving EC2 Security Groups: %w", err) } err = conn.DescribeSecurityGroupsPages(input, func(page *ec2.DescribeSecurityGroupsOutput, lastPage bool) bool { @@ -118,7 +118,7 @@ func testSweepSecurityGroups(region string) error { }) if err != nil { - return fmt.Errorf("Error retrieving EC2 Security Groups: %s", err) + return fmt.Errorf("Error retrieving EC2 Security Groups: %w", err) } return nil @@ -2098,15 +2098,11 @@ func testAddRuleCycle(primary, secondary *ec2.SecurityGroup) resource.TestCheckF var err error _, err = conn.AuthorizeSecurityGroupEgress(req1) if err != nil { - return fmt.Errorf( - "Error authorizing primary security group %s rules: %s", *primary.GroupId, - err) + return fmt.Errorf("Error authorizing primary security group %s rules: %w", aws.StringValue(primary.GroupId), err) } _, err = conn.AuthorizeSecurityGroupEgress(req2) if err != nil { - return fmt.Errorf( - "Error authorizing secondary security group %s rules: %s", *secondary.GroupId, - err) + return fmt.Errorf("Error authorizing secondary security group %s rules: %w", aws.StringValue(secondary.GroupId), err) } return nil } @@ -2133,9 +2129,7 @@ func testRemoveRuleCycle(primary, secondary *ec2.SecurityGroup) resource.TestChe } if _, err = conn.RevokeSecurityGroupIngress(req); err != nil { - return fmt.Errorf( - "Error revoking default ingress rule for Security Group in testRemoveCycle (%s): %s", - *primary.GroupId, err) + return fmt.Errorf("Error revoking default ingress rule for Security Group in testRemoveCycle (%s): %w", aws.StringValue(primary.GroupId), err) } } @@ -2146,9 +2140,7 @@ func testRemoveRuleCycle(primary, secondary *ec2.SecurityGroup) resource.TestChe } if _, err = conn.RevokeSecurityGroupEgress(req); err != nil { - return fmt.Errorf( - "Error revoking default egress rule for Security Group in testRemoveCycle (%s): %s", - *sg.GroupId, err) + return fmt.Errorf("Error revoking default egress rule for Security Group in testRemoveCycle (%s): %w", aws.StringValue(sg.GroupId), err) } } } @@ -2164,27 +2156,15 @@ func testAccCheckAWSSecurityGroupDestroy(s *terraform.State) error { continue } - // Retrieve our group - req := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(rs.Primary.ID)}, - } - resp, err := conn.DescribeSecurityGroups(req) - if err == nil { - if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == rs.Primary.ID { - return fmt.Errorf("Security Group (%s) still exists.", rs.Primary.ID) - } - - return nil - } - - ec2err, ok := err.(awserr.Error) - if !ok { - return err + _, err := finder.SecurityGroupByID(conn, rs.Primary.ID) + if tfresource.NotFound(err) { + continue } - // Confirm error code is what we want - if ec2err.Code() != "InvalidGroup.NotFound" { + if err != nil { return err } + + return fmt.Errorf("Security Group (%s) still exists.", rs.Primary.ID) } return nil @@ -2198,25 +2178,15 @@ func testAccCheckAWSSecurityGroupEc2ClassicDestroy(s *terraform.State) error { continue } - input := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(rs.Primary.ID)}, - } - - output, err := conn.DescribeSecurityGroups(input) - - if tfawserr.ErrCodeEquals(err, "InvalidGroup.NotFound") { + _, err := finder.SecurityGroupByID(conn, rs.Primary.ID) + if tfresource.NotFound(err) { continue } - if err != nil { - return fmt.Errorf("error describing EC2 Security Group (%s): %w", rs.Primary.ID, err) + return err } - for _, sg := range output.SecurityGroups { - if aws.StringValue(sg.GroupId) == rs.Primary.ID { - return fmt.Errorf("EC2 Security Group (%s) still exists", rs.Primary.ID) - } - } + return fmt.Errorf("Security Group (%s) still exists.", rs.Primary.ID) } return nil @@ -2234,20 +2204,18 @@ func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroup) reso } conn := testAccProvider.Meta().(*AWSClient).ec2conn - req := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(rs.Primary.ID)}, + + sg, err := finder.SecurityGroupByID(conn, rs.Primary.ID) + if tfresource.NotFound(err) { + return fmt.Errorf("Security Group (%s) not found: %w", rs.Primary.ID, err) } - resp, err := conn.DescribeSecurityGroups(req) if err != nil { return err } - if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == rs.Primary.ID { - *group = *resp.SecurityGroups[0] - return nil - } + *group = *sg - return fmt.Errorf("Security Group not found") + return nil } } @@ -2264,24 +2232,17 @@ func testAccCheckAWSSecurityGroupEc2ClassicExists(n string, group *ec2.SecurityG conn := testAccProviderEc2Classic.Meta().(*AWSClient).ec2conn - input := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(rs.Primary.ID)}, + sg, err := finder.SecurityGroupByID(conn, rs.Primary.ID) + if tfresource.NotFound(err) { + return fmt.Errorf("Security Group (%s) not found: %w", rs.Primary.ID, err) } - - output, err := conn.DescribeSecurityGroups(input) - if err != nil { - return fmt.Errorf("error describing EC2 Security Group (%s): %w", rs.Primary.ID, err) + return err } - for _, sg := range output.SecurityGroups { - if aws.StringValue(sg.GroupId) == rs.Primary.ID { - *group = *sg - return nil - } - } + *group = *sg - return fmt.Errorf("EC2 Security Group (%s) not found", rs.Primary.ID) + return nil } } @@ -2533,20 +2494,17 @@ func testAccCheckAWSSecurityGroupExistsWithoutDefault(n string) resource.TestChe } conn := testAccProvider.Meta().(*AWSClient).ec2conn - req := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(rs.Primary.ID)}, + + group, err := finder.SecurityGroupByID(conn, rs.Primary.ID) + if tfresource.NotFound(err) { + return fmt.Errorf("Security Group (%s) not found: %w", rs.Primary.ID, err) } - resp, err := conn.DescribeSecurityGroups(req) if err != nil { return err } - if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == rs.Primary.ID { - group := *resp.SecurityGroups[0] - - if len(group.IpPermissionsEgress) != 1 { - return fmt.Errorf("Security Group should have only 1 egress rule, got %d", len(group.IpPermissionsEgress)) - } + if len(group.IpPermissionsEgress) != 1 { + return fmt.Errorf("Security Group should have only 1 egress rule, got %d", len(group.IpPermissionsEgress)) } return nil @@ -2657,26 +2615,18 @@ func TestAccAWSSecurityGroup_ruleLimitCidrBlockExceededAppend(t *testing.T) { t.Fatalf("PreConfig check failed: %s", err) } - id := *group.GroupId + id := aws.StringValue(group.GroupId) conn := testAccProvider.Meta().(*AWSClient).ec2conn - req := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(id)}, + + match, err := finder.SecurityGroupByID(conn, id) + if tfresource.NotFound(err) { + t.Fatalf("PreConfig check failed: Security Group (%s) not found: %s", id, err) } - resp, err := conn.DescribeSecurityGroups(req) if err != nil { t.Fatalf("PreConfig check failed: %s", err) } - var match *ec2.SecurityGroup - if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == id { - match = resp.SecurityGroups[0] - } - - if match == nil { - t.Fatalf("PreConfig check failed: security group %s not found", id) - } - if cidrCount := len(match.IpPermissionsEgress[0].IpRanges); cidrCount != ruleLimit { t.Fatalf("PreConfig check failed: rule does not have previous IP ranges, has %d", cidrCount) } @@ -2823,23 +2773,15 @@ func testAccCheckAWSSecurityGroupRuleCount(group *ec2.SecurityGroup, expectedIng func testSecurityGroupRuleCount(id string, expectedIngressCount, expectedEgressCount int) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn - req := &ec2.DescribeSecurityGroupsInput{ - GroupIds: []*string{aws.String(id)}, + + group, err := finder.SecurityGroupByID(conn, id) + if tfresource.NotFound(err) { + return fmt.Errorf("Security Group (%s) not found: %w", id, err) } - resp, err := conn.DescribeSecurityGroups(req) if err != nil { return err } - var group *ec2.SecurityGroup - if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupId == id { - group = resp.SecurityGroups[0] - } - - if group == nil { - return fmt.Errorf("Security group %s not found", id) - } - if actual := len(group.IpPermissions); actual != expectedIngressCount { return fmt.Errorf("Security group ingress rule count %d does not match %d", actual, expectedIngressCount) } From 715821ab517d068f7b9f6a0dda242d2b314c3c03 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Tue, 27 Apr 2021 16:51:09 -0700 Subject: [PATCH 1156/1208] Updates function comments --- aws/internal/service/ec2/finder/finder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/internal/service/ec2/finder/finder.go b/aws/internal/service/ec2/finder/finder.go index cbf273af1447..ec9f498a232c 100644 --- a/aws/internal/service/ec2/finder/finder.go +++ b/aws/internal/service/ec2/finder/finder.go @@ -407,7 +407,6 @@ func RouteByPrefixListIDDestination(conn *ec2.EC2, routeTableID, prefixListID st return nil, &resource.NotFoundError{} } -// SecurityGroupByID looks up a security group by ID. When not found, returns nil and potentially an API error. // SecurityGroupByID looks up a security group by ID. Returns a resource.NotFoundError if not found. func SecurityGroupByID(conn *ec2.EC2, id string) (*ec2.SecurityGroup, error) { input := &ec2.DescribeSecurityGroupsInput{ @@ -429,6 +428,7 @@ func SecurityGroupByNameAndVpcID(conn *ec2.EC2, name, vpcID string) (*ec2.Securi return SecurityGroup(conn, input) } +// SecurityGroup looks up a security group using an ec2.DescribeSecurityGroupsInput. Returns a resource.NotFoundError if not found. func SecurityGroup(conn *ec2.EC2, input *ec2.DescribeSecurityGroupsInput) (*ec2.SecurityGroup, error) { result, err := conn.DescribeSecurityGroups(input) if tfawserr.ErrCodeEquals(err, tfec2.InvalidSecurityGroupIDNotFound) || From b698e692963bde8b7c01ef827899ab6b6695b75c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 12 Jul 2021 14:20:44 -0400 Subject: [PATCH 1157/1208] Correct error message for 'TestAccAWSSecurityGroup_rulesDropOnError'. --- aws/resource_aws_security_group_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_security_group_test.go b/aws/resource_aws_security_group_test.go index e85547ba1daa..f3f97df22264 100644 --- a/aws/resource_aws_security_group_test.go +++ b/aws/resource_aws_security_group_test.go @@ -2753,7 +2753,7 @@ func TestAccAWSSecurityGroup_rulesDropOnError(t *testing.T) { // Add a bad rule to trigger API error { Config: testAccAWSSecurityGroupConfig_rulesDropOnError_AddBadRule, - ExpectError: regexp.MustCompile("InvalidGroupId.Malformed"), + ExpectError: regexp.MustCompile("InvalidGroup.NotFound"), }, // All originally added rules must survive. This will return non-empty plan if anything changed. { From 88d36d052269e6cfa71e36e83222630ae28b7192 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 20:56:32 -0400 Subject: [PATCH 1158/1208] docs/r/wafv2_web_acl: Add to docs --- website/docs/r/wafv2_web_acl.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/wafv2_web_acl.html.markdown b/website/docs/r/wafv2_web_acl.html.markdown index d7917c0c7d38..e7ea1dc91775 100644 --- a/website/docs/r/wafv2_web_acl.html.markdown +++ b/website/docs/r/wafv2_web_acl.html.markdown @@ -416,6 +416,7 @@ The `managed_rule_group_statement` block supports the following arguments: * `excluded_rule` - (Optional) The `rules` whose actions are set to `COUNT` by the web ACL, regardless of the action that is set on the rule. See [Excluded Rule](#excluded-rule) below for details. * `name` - (Required) The name of the managed rule group. +* `scope_down_statement` - Narrows the scope of the statement to matching web requests. This can be any nestable statement, and you can nest statements at any level below this scope-down statement. See [Statement](#statement) above for details. * `vendor_name` - (Required) The name of the managed rule group vendor. ### NOT Statement From 3516ed7aaecbc91439446e27201a36036a372514 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 20:57:05 -0400 Subject: [PATCH 1159/1208] tests/r/wafv2_web_acl: Clean up tests --- aws/resource_aws_wafv2_web_acl_test.go | 206 ++++++++++++------------- 1 file changed, 103 insertions(+), 103 deletions(-) diff --git a/aws/resource_aws_wafv2_web_acl_test.go b/aws/resource_aws_wafv2_web_acl_test.go index 84ba41615475..dff17df08fbd 100644 --- a/aws/resource_aws_wafv2_web_acl_test.go +++ b/aws/resource_aws_wafv2_web_acl_test.go @@ -129,7 +129,7 @@ func TestAccAwsWafv2WebACL_basic(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_updateRule(t *testing.T) { +func TestAccAwsWafv2WebACL_Update_rule(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -260,7 +260,7 @@ func TestAccAwsWafv2WebACL_updateRule(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_UpdateRuleProperties(t *testing.T) { +func TestAccAwsWafv2WebACL_Update_ruleProperties(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -466,7 +466,7 @@ func TestAccAwsWafv2WebACL_UpdateRuleProperties(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_ChangeNameForceNew(t *testing.T) { +func TestAccAwsWafv2WebACL_Update_nameForceNew(t *testing.T) { var before, after wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") ruleGroupNewName := acctest.RandomWithPrefix("tf-acc-test") @@ -518,7 +518,7 @@ func TestAccAwsWafv2WebACL_ChangeNameForceNew(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_Disappears(t *testing.T) { +func TestAccAwsWafv2WebACL_disappears(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -541,7 +541,7 @@ func TestAccAwsWafv2WebACL_Disappears(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_ManagedRuleGroupStatement(t *testing.T) { +func TestAccAwsWafv2WebACL_managedRuleGroup(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -575,7 +575,7 @@ func TestAccAwsWafv2WebACL_ManagedRuleGroupStatement(t *testing.T) { ), }, { - Config: testAccAwsWafv2WebACLConfig_ManagedRuleGroupStatement_Update(webACLName), + Config: testAccAwsWafv2WebACLConfig_ManagedRuleGroupStatement_update(webACLName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -612,7 +612,7 @@ func TestAccAwsWafv2WebACL_ManagedRuleGroupStatement(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_Minimal(t *testing.T) { +func TestAccAwsWafv2WebACL_minimal(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -645,7 +645,7 @@ func TestAccAwsWafv2WebACL_Minimal(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_RateBasedStatement(t *testing.T) { +func TestAccAwsWafv2WebACL_RateBased_basic(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -679,7 +679,7 @@ func TestAccAwsWafv2WebACL_RateBasedStatement(t *testing.T) { ), }, { - Config: testAccAwsWafv2WebACLConfig_RateBasedStatement_Update(webACLName), + Config: testAccAwsWafv2WebACLConfig_RateBasedStatement_update(webACLName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -714,7 +714,7 @@ func TestAccAwsWafv2WebACL_RateBasedStatement(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_GeoMatchStatement(t *testing.T) { +func TestAccAwsWafv2WebACL_GeoMatch_basic(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -806,7 +806,7 @@ func TestAccAwsWafv2WebACL_GeoMatchStatement(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_GeoMatchStatement_ForwardedIPConfig(t *testing.T) { +func TestAccAwsWafv2WebACL_GeoMatch_forwardedIPConfig(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -818,7 +818,7 @@ func TestAccAwsWafv2WebACL_GeoMatchStatement_ForwardedIPConfig(t *testing.T) { CheckDestroy: testAccCheckAwsWafv2WebACLDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsWafv2WebACLConfig_GeoMatchStatement_ForwardedIPConfig(webACLName, "MATCH", "X-Forwarded-For"), + Config: testAccAwsWafv2WebACLConfig_GeoMatchStatement_forwardedIPConfig(webACLName, "MATCH", "X-Forwarded-For"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -840,7 +840,7 @@ func TestAccAwsWafv2WebACL_GeoMatchStatement_ForwardedIPConfig(t *testing.T) { ), }, { - Config: testAccAwsWafv2WebACLConfig_GeoMatchStatement_ForwardedIPConfig(webACLName, "NO_MATCH", "Updated"), + Config: testAccAwsWafv2WebACLConfig_GeoMatchStatement_forwardedIPConfig(webACLName, "NO_MATCH", "Updated"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -871,7 +871,7 @@ func TestAccAwsWafv2WebACL_GeoMatchStatement_ForwardedIPConfig(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_IPSetReferenceStatement(t *testing.T) { +func TestAccAwsWafv2WebACL_IPSetReference_basic(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -883,7 +883,7 @@ func TestAccAwsWafv2WebACL_IPSetReferenceStatement(t *testing.T) { CheckDestroy: testAccCheckAwsWafv2WebACLDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsWafv2WebACLConfig_IPSetReferenceStatement(webACLName), + Config: testAccAwsWafv2WebACLConfig_IPSetReference(webACLName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -917,7 +917,7 @@ func TestAccAwsWafv2WebACL_IPSetReferenceStatement(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_IPSetReferenceStatement_IPSetForwardedIPConfig(t *testing.T) { +func TestAccAwsWafv2WebACL_IPSetReference_forwardedIPConfig(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -929,7 +929,7 @@ func TestAccAwsWafv2WebACL_IPSetReferenceStatement_IPSetForwardedIPConfig(t *tes CheckDestroy: testAccCheckAwsWafv2WebACLDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsWafv2WebACLConfig_IPSetReferenceStatement_IPSetForwardedIPConfig(webACLName, "MATCH", "X-Forwarded-For", "FIRST"), + Config: testAccAwsWafv2WebACLConfig_IPSetReference_forwardedIPConfig(webACLName, "MATCH", "X-Forwarded-For", "FIRST"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -951,7 +951,7 @@ func TestAccAwsWafv2WebACL_IPSetReferenceStatement_IPSetForwardedIPConfig(t *tes ), }, { - Config: testAccAwsWafv2WebACLConfig_IPSetReferenceStatement_IPSetForwardedIPConfig(webACLName, "NO_MATCH", "X-Forwarded-For", "LAST"), + Config: testAccAwsWafv2WebACLConfig_IPSetReference_forwardedIPConfig(webACLName, "NO_MATCH", "X-Forwarded-For", "LAST"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -973,7 +973,7 @@ func TestAccAwsWafv2WebACL_IPSetReferenceStatement_IPSetForwardedIPConfig(t *tes ), }, { - Config: testAccAwsWafv2WebACLConfig_IPSetReferenceStatement_IPSetForwardedIPConfig(webACLName, "MATCH", "Updated", "ANY"), + Config: testAccAwsWafv2WebACLConfig_IPSetReference_forwardedIPConfig(webACLName, "MATCH", "Updated", "ANY"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -995,7 +995,7 @@ func TestAccAwsWafv2WebACL_IPSetReferenceStatement_IPSetForwardedIPConfig(t *tes ), }, { - Config: testAccAwsWafv2WebACLConfig_IPSetReferenceStatement(webACLName), + Config: testAccAwsWafv2WebACLConfig_IPSetReference(webACLName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -1021,7 +1021,7 @@ func TestAccAwsWafv2WebACL_IPSetReferenceStatement_IPSetForwardedIPConfig(t *tes }) } -func TestAccAwsWafv2WebACL_RateBasedStatement_ForwardedIPConfig(t *testing.T) { +func TestAccAwsWafv2WebACL_RateBased_forwardedIPConfig(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -1033,7 +1033,7 @@ func TestAccAwsWafv2WebACL_RateBasedStatement_ForwardedIPConfig(t *testing.T) { CheckDestroy: testAccCheckAwsWafv2WebACLDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsWafv2WebACLConfig_RateBasedStatement_ForwardedIPConfig(webACLName, "MATCH", "X-Forwarded-For"), + Config: testAccAwsWafv2WebACLConfig_RateBasedStatement_forwardedIPConfig(webACLName, "MATCH", "X-Forwarded-For"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -1057,7 +1057,7 @@ func TestAccAwsWafv2WebACL_RateBasedStatement_ForwardedIPConfig(t *testing.T) { ), }, { - Config: testAccAwsWafv2WebACLConfig_RateBasedStatement_ForwardedIPConfig(webACLName, "NO_MATCH", "Updated"), + Config: testAccAwsWafv2WebACLConfig_RateBasedStatement_forwardedIPConfig(webACLName, "NO_MATCH", "Updated"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -1090,7 +1090,7 @@ func TestAccAwsWafv2WebACL_RateBasedStatement_ForwardedIPConfig(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_RuleGroupReferenceStatement(t *testing.T) { +func TestAccAwsWafv2WebACL_RuleGroupReference_basic(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -1123,7 +1123,7 @@ func TestAccAwsWafv2WebACL_RuleGroupReferenceStatement(t *testing.T) { ), }, { - Config: testAccAwsWafv2WebACLConfig_RuleGroupReferenceStatement_Update(webACLName), + Config: testAccAwsWafv2WebACLConfig_RuleGroupReferenceStatement_update(webACLName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -1155,7 +1155,7 @@ func TestAccAwsWafv2WebACL_RuleGroupReferenceStatement(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_CustomRequestHandling(t *testing.T) { +func TestAccAwsWafv2WebACL_Custom_requestHandling(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -1167,7 +1167,7 @@ func TestAccAwsWafv2WebACL_CustomRequestHandling(t *testing.T) { CheckDestroy: testAccCheckAwsWafv2WebACLDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsWafv2WebACLConfig_CustomRequestHandling_Allow(webACLName, "x-hdr1", "x-hdr2"), + Config: testAccAwsWafv2WebACLConfig_CustomRequestHandling_allow(webACLName, "x-hdr1", "x-hdr2"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -1198,7 +1198,7 @@ func TestAccAwsWafv2WebACL_CustomRequestHandling(t *testing.T) { ), }, { - Config: testAccAwsWafv2WebACLConfig_CustomRequestHandling_Count(webACLName, "x-hdr1", "x-hdr2"), + Config: testAccAwsWafv2WebACLConfig_CustomRequestHandling_count(webACLName, "x-hdr1", "x-hdr2"), Check: resource.ComposeTestCheckFunc( testAccCheckAwsWafv2WebACLExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/webacl/.+$`)), @@ -1238,7 +1238,7 @@ func TestAccAwsWafv2WebACL_CustomRequestHandling(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_CustomResponse(t *testing.T) { +func TestAccAwsWafv2WebACL_Custom_response(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -1323,7 +1323,7 @@ func TestAccAwsWafv2WebACL_CustomResponse(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_Tags(t *testing.T) { +func TestAccAwsWafv2WebACL_tags(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -1373,7 +1373,7 @@ func TestAccAwsWafv2WebACL_Tags(t *testing.T) { } // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/13862 -func TestAccAwsWafv2WebACL_MaxNestedRateBasedStatements(t *testing.T) { +func TestAccAwsWafv2WebACL_RateBased_maxNested(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -1416,7 +1416,7 @@ func TestAccAwsWafv2WebACL_MaxNestedRateBasedStatements(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_MaxNestedOperatorStatements(t *testing.T) { +func TestAccAwsWafv2WebACL_Operators_maxNested(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" @@ -1531,8 +1531,8 @@ func testAccCheckAwsWafv2WebACLExists(n string, v *wafv2.WebACL) resource.TestCh func testAccAwsWafv2WebACLConfig_Basic(name string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -1551,7 +1551,7 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_BasicRule(name string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" + name = %[1]q description = "Updated" scope = "REGIONAL" @@ -1607,7 +1607,7 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_UpdateRuleNamePriorityMetric(name, ruleName1, ruleName2 string, priority1, priority2 int) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" + name = %[1]q description = "Updated" scope = "REGIONAL" @@ -1616,7 +1616,7 @@ resource "aws_wafv2_web_acl" "test" { } rule { - name = "%[2]s" + name = %[2]q priority = %[3]d action { @@ -1646,13 +1646,13 @@ resource "aws_wafv2_web_acl" "test" { visibility_config { cloudwatch_metrics_enabled = false - metric_name = "%[2]s" + metric_name = %[2]q sampled_requests_enabled = false } } rule { - name = "%[4]s" + name = %[4]q priority = %[5]d action { @@ -1667,7 +1667,7 @@ resource "aws_wafv2_web_acl" "test" { visibility_config { cloudwatch_metrics_enabled = false - metric_name = "%[4]s" + metric_name = %[4]q sampled_requests_enabled = false } } @@ -1684,8 +1684,8 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_GeoMatchStatement(name, countryCodes string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -1727,11 +1727,11 @@ resource "aws_wafv2_web_acl" "test" { `, name, countryCodes) } -func testAccAwsWafv2WebACLConfig_CustomRequestHandling_Count(name, firstHeader string, secondHeader string) string { +func testAccAwsWafv2WebACLConfig_CustomRequestHandling_count(name, firstHeader string, secondHeader string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -1746,12 +1746,12 @@ resource "aws_wafv2_web_acl" "test" { count { custom_request_handling { insert_header { - name = "%[2]s" + name = %[2]q value = "test-value-1" } insert_header { - name = "%[3]s" + name = %[3]q value = "test-value-2" } } @@ -1780,11 +1780,11 @@ resource "aws_wafv2_web_acl" "test" { `, name, firstHeader, secondHeader) } -func testAccAwsWafv2WebACLConfig_CustomRequestHandling_Allow(name, firstHeader string, secondHeader string) string { +func testAccAwsWafv2WebACLConfig_CustomRequestHandling_allow(name, firstHeader string, secondHeader string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -1799,12 +1799,12 @@ resource "aws_wafv2_web_acl" "test" { allow { custom_request_handling { insert_header { - name = "%[2]s" + name = %[2]q value = "test-value-1" } insert_header { - name = "%[3]s" + name = %[3]q value = "test-value-2" } } @@ -1836,8 +1836,8 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_CustomResponse(name string, defaultStatusCode int, countryBlockStatusCode int, countryHeaderName string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -1858,7 +1858,7 @@ resource "aws_wafv2_web_acl" "test" { response_code = %[3]d response_header { - name = "%[4]s" + name = %[4]q value = "custom-response-header-value" } } @@ -1887,11 +1887,11 @@ resource "aws_wafv2_web_acl" "test" { `, name, defaultStatusCode, countryBlockStatusCode, countryHeaderName) } -func testAccAwsWafv2WebACLConfig_GeoMatchStatement_ForwardedIPConfig(name, fallbackBehavior, headerName string) string { +func testAccAwsWafv2WebACLConfig_GeoMatchStatement_forwardedIPConfig(name, fallbackBehavior, headerName string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -1918,8 +1918,8 @@ resource "aws_wafv2_web_acl" "test" { geo_match_statement { country_codes = ["CA"] forwarded_ip_config { - fallback_behavior = "%s" - header_name = "%s" + fallback_behavior = %[2]q + header_name = %[3]q } } } @@ -1942,7 +1942,7 @@ resource "aws_wafv2_web_acl" "test" { `, name, fallbackBehavior, headerName) } -func testAccAwsWafv2WebACLConfig_IPSetReferenceStatement(name string) string { +func testAccAwsWafv2WebACLConfig_IPSetReference(name string) string { return fmt.Sprintf(` resource "aws_wafv2_ip_set" "test" { name = "ip-set-%[1]s" @@ -1952,8 +1952,8 @@ resource "aws_wafv2_ip_set" "test" { } resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -1990,7 +1990,7 @@ resource "aws_wafv2_web_acl" "test" { `, name) } -func testAccAwsWafv2WebACLConfig_IPSetReferenceStatement_IPSetForwardedIPConfig(name, fallbackBehavior, headerName, position string) string { +func testAccAwsWafv2WebACLConfig_IPSetReference_forwardedIPConfig(name, fallbackBehavior, headerName, position string) string { return fmt.Sprintf(` resource "aws_wafv2_ip_set" "test" { name = "ip-set-%[1]s" @@ -2000,8 +2000,8 @@ resource "aws_wafv2_ip_set" "test" { } resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -2020,9 +2020,9 @@ resource "aws_wafv2_web_acl" "test" { ip_set_reference_statement { arn = aws_wafv2_ip_set.test.arn ip_set_forwarded_ip_config { - fallback_behavior = "%[2]s" - header_name = "%[3]s" - position = "%[4]s" + fallback_behavior = %[2]q + header_name = %[3]q + position = %[4]q } } } @@ -2046,8 +2046,8 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_ManagedRuleGroupStatement(name string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -2090,11 +2090,11 @@ resource "aws_wafv2_web_acl" "test" { `, name) } -func testAccAwsWafv2WebACLConfig_ManagedRuleGroupStatement_Update(name string) string { +func testAccAwsWafv2WebACLConfig_ManagedRuleGroupStatement_update(name string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -2154,8 +2154,8 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_RateBasedStatement(name string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -2197,11 +2197,11 @@ resource "aws_wafv2_web_acl" "test" { `, name) } -func testAccAwsWafv2WebACLConfig_RateBasedStatement_ForwardedIPConfig(name, fallbackBehavior, headerName string) string { +func testAccAwsWafv2WebACLConfig_RateBasedStatement_forwardedIPConfig(name, fallbackBehavior, headerName string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -2220,8 +2220,8 @@ resource "aws_wafv2_web_acl" "test" { rate_based_statement { aggregate_key_type = "FORWARDED_IP" forwarded_ip_config { - fallback_behavior = "%s" - header_name = "%s" + fallback_behavior = %[2]q + header_name = %[3]q } limit = 50000 } @@ -2248,11 +2248,11 @@ resource "aws_wafv2_web_acl" "test" { `, name, fallbackBehavior, headerName) } -func testAccAwsWafv2WebACLConfig_RateBasedStatement_Update(name string) string { +func testAccAwsWafv2WebACLConfig_RateBasedStatement_update(name string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -2316,7 +2316,7 @@ resource "aws_wafv2_rule_group" "test" { } resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" + name = %[1]q scope = "REGIONAL" default_action { @@ -2358,7 +2358,7 @@ resource "aws_wafv2_web_acl" "test" { `, name) } -func testAccAwsWafv2WebACLConfig_RuleGroupReferenceStatement_Update(name string) string { +func testAccAwsWafv2WebACLConfig_RuleGroupReferenceStatement_update(name string) string { return fmt.Sprintf(` resource "aws_wafv2_rule_group" "test" { capacity = 10 @@ -2436,7 +2436,7 @@ resource "aws_wafv2_rule_group" "test" { } resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" + name = %[1]q scope = "REGIONAL" default_action { @@ -2489,7 +2489,7 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_Minimal(name string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%s" + name = %[1]q scope = "REGIONAL" default_action { @@ -2508,8 +2508,8 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_OneTag(name, tagKey, tagValue string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -2523,7 +2523,7 @@ resource "aws_wafv2_web_acl" "test" { } tags = { - "%s" = "%s" + %[2]q = %[3]q } } `, name, tagKey, tagValue) @@ -2532,8 +2532,8 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_TwoTags(name, tag1Key, tag1Value, tag2Key, tag2Value string) string { return fmt.Sprintf(` resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -2547,8 +2547,8 @@ resource "aws_wafv2_web_acl" "test" { } tags = { - "%s" = "%s" - "%s" = "%s" + %[2]q = %[3]q + %[4]q = %[5]q } } `, name, tag1Key, tag1Value, tag2Key, tag2Value) @@ -2557,7 +2557,7 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_multipleNestedRateBasedStatements(name string) string { return fmt.Sprintf(` resource "aws_wafv2_regex_pattern_set" "test" { - name = "%[1]s" + name = %[1]q scope = "REGIONAL" regular_expression { @@ -2566,15 +2566,15 @@ resource "aws_wafv2_regex_pattern_set" "test" { } resource "aws_wafv2_ip_set" "test" { - name = "%[1]s" + name = %[1]q scope = "REGIONAL" ip_address_version = "IPV4" addresses = ["1.2.3.4/32", "5.6.7.8/32"] } resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { @@ -2644,7 +2644,7 @@ resource "aws_wafv2_web_acl" "test" { func testAccAwsWafv2WebACLConfig_multipleNestedOperatorStatements(name string) string { return fmt.Sprintf(` resource "aws_wafv2_regex_pattern_set" "test" { - name = "%[1]s" + name = %[1]q scope = "REGIONAL" regular_expression { @@ -2653,15 +2653,15 @@ resource "aws_wafv2_regex_pattern_set" "test" { } resource "aws_wafv2_ip_set" "test" { - name = "%[1]s" + name = %[1]q scope = "REGIONAL" ip_address_version = "IPV4" addresses = ["1.2.3.4/32", "5.6.7.8/32"] } resource "aws_wafv2_web_acl" "test" { - name = "%[1]s" - description = "%[1]s" + name = %[1]q + description = %[1]q scope = "REGIONAL" default_action { From e771d9d61926def0054db3d7099f052db01b56f5 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 20:57:27 -0400 Subject: [PATCH 1160/1208] r/wafv2_web_acl: Standardize some --- aws/resource_aws_wafv2_web_acl.go | 62 +++++++++++++++++++------------ 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/aws/resource_aws_wafv2_web_acl.go b/aws/resource_aws_wafv2_web_acl.go index 18c71038b574..bb9e69c896bc 100644 --- a/aws/resource_aws_wafv2_web_acl.go +++ b/aws/resource_aws_wafv2_web_acl.go @@ -386,12 +386,12 @@ func wafv2ManagedRuleGroupStatementSchema(level int) *schema.Schema { Required: true, ValidateFunc: validation.StringLenBetween(1, 128), }, + "scope_down_statement": wafv2ScopeDownStatementSchema(level - 1), "vendor_name": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringLenBetween(1, 128), }, - "scope_down_statement": wafv2ScopeDownStatementSchema(level - 1), }, }, } @@ -633,8 +633,7 @@ func expandWafv2ManagedRuleGroupStatement(l []interface{}) *wafv2.ManagedRuleGro VendorName: aws.String(m["vendor_name"].(string)), } - s := m["scope_down_statement"].([]interface{}) - if len(s) > 0 && s[0] != nil { + if s, ok := m["scope_down_statement"].([]interface{}); ok && len(s) > 0 && s[0] != nil { r.ScopeDownStatement = expandWafv2Statement(s[0].(map[string]interface{})) } @@ -826,41 +825,56 @@ func flattenWafv2DefaultAction(a *wafv2.DefaultAction) interface{} { return []interface{}{m} } -func flattenWafv2ManagedRuleGroupStatement(r *wafv2.ManagedRuleGroupStatement) interface{} { - if r == nil { +func flattenWafv2ManagedRuleGroupStatement(apiObject *wafv2.ManagedRuleGroupStatement) interface{} { + if apiObject == nil { return []interface{}{} } - m := map[string]interface{}{ - "excluded_rule": flattenWafv2ExcludedRules(r.ExcludedRules), - "name": aws.StringValue(r.Name), - "vendor_name": aws.StringValue(r.VendorName), - "scope_down_statement": nil, + tfMap := map[string]interface{}{} + + if apiObject.ExcludedRules != nil { + tfMap["excluded_rule"] = flattenWafv2ExcludedRules(apiObject.ExcludedRules) } -if r.ScopeDownStatement != nil { - m["scope_down_statement"] = []interface{}{flattenWafv2Statement(r.ScopeDownStatement)} -} - return []interface{}{m} + if apiObject.Name != nil { + tfMap["name"] = aws.StringValue(apiObject.Name) + } + + if apiObject.ScopeDownStatement != nil { + tfMap["scope_down_statement"] = []interface{}{flattenWafv2Statement(apiObject.ScopeDownStatement)} + } + + if apiObject.VendorName != nil { + tfMap["vendor_name"] = aws.StringValue(apiObject.VendorName) + } + + return []interface{}{tfMap} } -func flattenWafv2RateBasedStatement(r *wafv2.RateBasedStatement) interface{} { - if r == nil { +func flattenWafv2RateBasedStatement(apiObject *wafv2.RateBasedStatement) interface{} { + if apiObject == nil { return []interface{}{} } - m := map[string]interface{}{ - "limit": int(aws.Int64Value(r.Limit)), - "aggregate_key_type": aws.StringValue(r.AggregateKeyType), - "forwarded_ip_config": flattenWafv2ForwardedIPConfig(r.ForwardedIPConfig), - "scope_down_statement": nil, + tfMap := map[string]interface{}{} + + if apiObject.AggregateKeyType != nil { + tfMap["aggregate_key_type"] = aws.StringValue(apiObject.AggregateKeyType) } - if r.ScopeDownStatement != nil { - m["scope_down_statement"] = []interface{}{flattenWafv2Statement(r.ScopeDownStatement)} + if apiObject.ForwardedIPConfig != nil { + tfMap["forwarded_ip_config"] = flattenWafv2ForwardedIPConfig(apiObject.ForwardedIPConfig) } - return []interface{}{m} + if apiObject.Limit != nil { + tfMap["limit"] = int(aws.Int64Value(apiObject.Limit)) + } + + if apiObject.ScopeDownStatement != nil { + tfMap["scope_down_statement"] = []interface{}{flattenWafv2Statement(apiObject.ScopeDownStatement)} + } + + return []interface{}{tfMap} } func flattenWafv2RuleGroupReferenceStatement(r *wafv2.RuleGroupReferenceStatement) interface{} { From fa5e588c11115e4ca55bad637f520cccdf95087d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 21:04:03 -0400 Subject: [PATCH 1161/1208] tests/r/wafv2_web_acl: Update test name --- aws/resource_aws_wafv2_web_acl_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_wafv2_web_acl_test.go b/aws/resource_aws_wafv2_web_acl_test.go index dff17df08fbd..f0f6adadc28b 100644 --- a/aws/resource_aws_wafv2_web_acl_test.go +++ b/aws/resource_aws_wafv2_web_acl_test.go @@ -541,7 +541,7 @@ func TestAccAwsWafv2WebACL_disappears(t *testing.T) { }) } -func TestAccAwsWafv2WebACL_managedRuleGroup(t *testing.T) { +func TestAccAwsWafv2WebACL_ManagedRuleGroup_basic(t *testing.T) { var v wafv2.WebACL webACLName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_wafv2_web_acl.test" From e31904d703d5d10b7376269652ef09e546549536 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 13 Jul 2021 01:21:30 +0000 Subject: [PATCH 1162/1208] Update CHANGELOG.md for #20140 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b53ab33ee1f..b5069ee03df0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,9 @@ FEATURES: * **New Resource:** `aws_appconfig_application` ([#19307](https://github.com/hashicorp/terraform-provider-aws/issues/19307)) * **New Resource:** `aws_appconfig_configuration_profile` ([#19320](https://github.com/hashicorp/terraform-provider-aws/issues/19320)) +* **New Resource:** `aws_appconfig_deployment_strategy` ([#19359](https://github.com/hashicorp/terraform-provider-aws/issues/19359)) * **New Resource:** `aws_appconfig_environment` ([#19307](https://github.com/hashicorp/terraform-provider-aws/issues/19307)) +* **New Resource:** `aws_appconfig_hosted_configuration_version` ([#19324](https://github.com/hashicorp/terraform-provider-aws/issues/19324)) * **New Resource:** `aws_config_organization_conformance_pack` ([#17298](https://github.com/hashicorp/terraform-provider-aws/issues/17298)) ENHANCEMENTS: @@ -18,6 +20,8 @@ ENHANCEMENTS: * resource/aws_fsx_windows_file_system: Add `aliases` argument ([#20054](https://github.com/hashicorp/terraform-provider-aws/issues/20054)) * resource/aws_guardduty_detector: Add `datasources` argument ([#19954](https://github.com/hashicorp/terraform-provider-aws/issues/19954)) * resource/aws_guardduty_organization_configuration: Add `datasources` argument ([#15241](https://github.com/hashicorp/terraform-provider-aws/issues/15241)) +* resource/aws_iam_access_key: Add encrypted SES SMTP password ([#19579](https://github.com/hashicorp/terraform-provider-aws/issues/19579)) +* resource/aws_s3_bucket: Add the delete_marker_replication_status argument for V2 replication configurations ([#19323](https://github.com/hashicorp/terraform-provider-aws/issues/19323)) BUG FIXES: From 26271f3121bdcadee84437f3064b5d3be88ea776 Mon Sep 17 00:00:00 2001 From: Theophile Chevalier Date: Tue, 7 Jan 2020 20:26:09 +0100 Subject: [PATCH 1163/1208] Add source_hash to aws_s3_bucket_object Allows one to store a hash in state to trigger resource update. --- aws/resource_aws_s3_bucket_object.go | 12 ++++ aws/resource_aws_s3_bucket_object_test.go | 57 +++++++++++++++++++ website/docs/r/s3_bucket_object.html.markdown | 1 + 3 files changed, 70 insertions(+) diff --git a/aws/resource_aws_s3_bucket_object.go b/aws/resource_aws_s3_bucket_object.go index 4f90ae35c8c3..cc95b3a50605 100644 --- a/aws/resource_aws_s3_bucket_object.go +++ b/aws/resource_aws_s3_bucket_object.go @@ -191,6 +191,11 @@ func resourceAwsS3BucketObject() *schema.Resource { Optional: true, ValidateFunc: validation.IsRFC3339Time, }, + + "source_hash": { + Type: schema.TypeString, + Optional: true, + }, }, } } @@ -564,6 +569,12 @@ func resourceAwsS3BucketObjectCustomizeDiff(_ context.Context, d *schema.Resourc if hasS3BucketObjectContentChanges(d) { return d.SetNewComputed("version_id") } + + if d.HasChange("source_hash") { + d.SetNewComputed("version_id") + d.SetNewComputed("etag") + } + return nil } @@ -582,6 +593,7 @@ func hasS3BucketObjectContentChanges(d resourceDiffer) bool { "metadata", "server_side_encryption", "source", + "source_hash", "storage_class", "website_redirect", } { diff --git a/aws/resource_aws_s3_bucket_object_test.go b/aws/resource_aws_s3_bucket_object_test.go index f88b4283918b..dde4681eb301 100644 --- a/aws/resource_aws_s3_bucket_object_test.go +++ b/aws/resource_aws_s3_bucket_object_test.go @@ -247,6 +247,48 @@ func TestAccAWSS3BucketObject_contentBase64(t *testing.T) { }) } +func TestAccAWSS3BucketObject_SourceHashTrigger(t *testing.T) { + var obj, updated_obj s3.GetObjectOutput + resourceName := "aws_s3_bucket_object.object" + source := testAccAWSS3BucketObjectCreateTempFile(t, "{anything will do }") + rewrite_source := func(*terraform.State) error { + if err := ioutil.WriteFile(source, []byte("{any other thing will do }"), 0644); err != nil { + os.Remove(source) + t.Fatal(err) + } + return nil + } + rInt := acctest.RandInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, + Steps: []resource.TestStep{ + { + PreConfig: func() {}, + Config: testAccAWSS3BucketObjectConfig_SourceHashTrigger(rInt, source), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSS3BucketObjectExists(resourceName, &obj), + testAccCheckAWSS3BucketObjectBody(&obj, "{anything will do }"), + resource.TestCheckResourceAttr(resourceName, "source_hash", "7b006ff4d70f68cc65061acf2f802e6f"), + rewrite_source, + ), + ExpectNonEmptyPlan: true, + }, + { + PreConfig: func() {}, + Config: testAccAWSS3BucketObjectConfig_SourceHashTrigger(rInt, source), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSS3BucketObjectExists(resourceName, &updated_obj), + testAccCheckAWSS3BucketObjectBody(&updated_obj, "{any other thing will do }"), + resource.TestCheckResourceAttr(resourceName, "source_hash", "77a736aa9e04d0dc96b9b30894963983"), + ), + }, + }, + }) +} + func TestAccAWSS3BucketObject_withContentCharacteristics(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" @@ -1582,6 +1624,21 @@ resource "aws_s3_bucket_object" "object" { `, randInt, contentBase64) } +func testAccAWSS3BucketObjectConfig_SourceHashTrigger(randInt int, source string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "object_bucket" { + bucket = "tf-object-test-bucket-%d" +} + +resource "aws_s3_bucket_object" "object" { + bucket = "${aws_s3_bucket.object_bucket.bucket}" + key = "test-key" + source = "%s" + source_hash = "${filemd5("%s")}" +} +`, randInt, source, source) +} + func testAccAWSS3BucketObjectConfig_updateable(randInt int, bucketVersioning bool, source string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "object_bucket_3" { diff --git a/website/docs/r/s3_bucket_object.html.markdown b/website/docs/r/s3_bucket_object.html.markdown index 6bbd9dfa11c8..f9934409c5aa 100644 --- a/website/docs/r/s3_bucket_object.html.markdown +++ b/website/docs/r/s3_bucket_object.html.markdown @@ -131,6 +131,7 @@ The following arguments are supported: for the object. Can be either "`STANDARD`", "`REDUCED_REDUNDANCY`", "`ONEZONE_IA`", "`INTELLIGENT_TIERING`", "`GLACIER`", "`DEEP_ARCHIVE`", or "`STANDARD_IA`". Defaults to "`STANDARD`". * `etag` - (Optional) Used to trigger updates. The only meaningful value is `${filemd5("path/to/file")}` (Terraform 0.11.12 or later) or `${md5(file("path/to/file"))}` (Terraform 0.11.11 or earlier). This attribute is not compatible with KMS encryption, `kms_key_id` or `server_side_encryption = "aws:kms"`. +* `source_hash` - (Optional) Used to trigger updates based on source local changes. If used, must be set to `${filemd5("path/to/source")}` (Terraform 0.11.12 or later). This differs from `etag` since the value is stored in the state and does not come from AWS. Especially useful to address `etag` KMS encryption limitations. * `server_side_encryption` - (Optional) Specifies server-side encryption of the object in S3. Valid values are "`AES256`" and "`aws:kms`". * `kms_key_id` - (Optional) Amazon Resource Name (ARN) of the KMS Key to use for object encryption. If the S3 Bucket has server-side encryption enabled, that value will automatically be used. If referencing the `aws_kms_key` resource, use the `arn` attribute. If referencing the `aws_kms_alias` data source or resource, use the `target_key_arn` attribute. Terraform will only perform drift detection if a configuration value From bef29fe79c6eb9dcf39ee9b8f481d6260cc79f44 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 21:59:06 -0400 Subject: [PATCH 1164/1208] tests/r/s3_bucket_object: Clean up tests --- aws/resource_aws_s3_bucket_object_test.go | 369 +++++++++++----------- 1 file changed, 185 insertions(+), 184 deletions(-) diff --git a/aws/resource_aws_s3_bucket_object_test.go b/aws/resource_aws_s3_bucket_object_test.go index dde4681eb301..561aa388a3fd 100644 --- a/aws/resource_aws_s3_bucket_object_test.go +++ b/aws/resource_aws_s3_bucket_object_test.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "fmt" "io" + "io/ioutil" "log" "os" "reflect" @@ -130,7 +131,7 @@ func TestAccAWSS3BucketObject_noNameNoKey(t *testing.T) { func TestAccAWSS3BucketObject_empty(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -140,7 +141,7 @@ func TestAccAWSS3BucketObject_empty(t *testing.T) { Steps: []resource.TestStep{ { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectConfigEmpty(rInt), + Config: testAccAWSS3BucketObjectConfigEmpty(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectBody(&obj, ""), @@ -153,7 +154,7 @@ func TestAccAWSS3BucketObject_empty(t *testing.T) { func TestAccAWSS3BucketObject_source(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") source := testAccAWSS3BucketObjectCreateTempFile(t, "{anything will do }") defer os.Remove(source) @@ -165,7 +166,7 @@ func TestAccAWSS3BucketObject_source(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfigSource(rInt, source), + Config: testAccAWSS3BucketObjectConfigSource(rName, source), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectBody(&obj, "{anything will do }"), @@ -178,7 +179,7 @@ func TestAccAWSS3BucketObject_source(t *testing.T) { func TestAccAWSS3BucketObject_content(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -188,7 +189,7 @@ func TestAccAWSS3BucketObject_content(t *testing.T) { Steps: []resource.TestStep{ { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectConfigContent(rInt, "some_bucket_content"), + Config: testAccAWSS3BucketObjectConfigContent(rName, "some_bucket_content"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectBody(&obj, "some_bucket_content"), @@ -201,7 +202,7 @@ func TestAccAWSS3BucketObject_content(t *testing.T) { func TestAccAWSS3BucketObject_etagEncryption(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") source := testAccAWSS3BucketObjectCreateTempFile(t, "{anything will do }") defer os.Remove(source) @@ -213,7 +214,7 @@ func TestAccAWSS3BucketObject_etagEncryption(t *testing.T) { Steps: []resource.TestStep{ { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectEtagEncryption(rInt, source), + Config: testAccAWSS3BucketObjectEtagEncryption(rName, source), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectBody(&obj, "{anything will do }"), @@ -227,7 +228,7 @@ func TestAccAWSS3BucketObject_etagEncryption(t *testing.T) { func TestAccAWSS3BucketObject_contentBase64(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -237,7 +238,7 @@ func TestAccAWSS3BucketObject_contentBase64(t *testing.T) { Steps: []resource.TestStep{ { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectConfigContentBase64(rInt, base64.StdEncoding.EncodeToString([]byte("some_bucket_content"))), + Config: testAccAWSS3BucketObjectConfigContentBase64(rName, base64.StdEncoding.EncodeToString([]byte("some_bucket_content"))), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectBody(&obj, "some_bucket_content"), @@ -247,18 +248,18 @@ func TestAccAWSS3BucketObject_contentBase64(t *testing.T) { }) } -func TestAccAWSS3BucketObject_SourceHashTrigger(t *testing.T) { +func TestAccAWSS3BucketObject_sourceHashTrigger(t *testing.T) { var obj, updated_obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" source := testAccAWSS3BucketObjectCreateTempFile(t, "{anything will do }") - rewrite_source := func(*terraform.State) error { + rewriteSourceF := func(*terraform.State) error { if err := ioutil.WriteFile(source, []byte("{any other thing will do }"), 0644); err != nil { os.Remove(source) t.Fatal(err) } return nil } - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -267,18 +268,18 @@ func TestAccAWSS3BucketObject_SourceHashTrigger(t *testing.T) { Steps: []resource.TestStep{ { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectConfig_SourceHashTrigger(rInt, source), + Config: testAccAWSS3BucketObjectConfig_sourceHashTrigger(rName, source), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectBody(&obj, "{anything will do }"), resource.TestCheckResourceAttr(resourceName, "source_hash", "7b006ff4d70f68cc65061acf2f802e6f"), - rewrite_source, + rewriteSourceF, ), ExpectNonEmptyPlan: true, }, { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectConfig_SourceHashTrigger(rInt, source), + Config: testAccAWSS3BucketObjectConfig_sourceHashTrigger(rName, source), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &updated_obj), testAccCheckAWSS3BucketObjectBody(&updated_obj, "{any other thing will do }"), @@ -292,7 +293,7 @@ func TestAccAWSS3BucketObject_SourceHashTrigger(t *testing.T) { func TestAccAWSS3BucketObject_withContentCharacteristics(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") source := testAccAWSS3BucketObjectCreateTempFile(t, "{anything will do }") defer os.Remove(source) @@ -304,7 +305,7 @@ func TestAccAWSS3BucketObject_withContentCharacteristics(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_withContentCharacteristics(rInt, source), + Config: testAccAWSS3BucketObjectConfig_withContentCharacteristics(rName, source), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectBody(&obj, "{anything will do }"), @@ -316,10 +317,10 @@ func TestAccAWSS3BucketObject_withContentCharacteristics(t *testing.T) { }) } -func TestAccAWSS3BucketObject_NonVersioned(t *testing.T) { +func TestAccAWSS3BucketObject_nonVersioned(t *testing.T) { sourceInitial := testAccAWSS3BucketObjectCreateTempFile(t, "initial object state") defer os.Remove(sourceInitial) - + rName := acctest.RandomWithPrefix("tf-acc-test") var originalObj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" @@ -330,7 +331,7 @@ func TestAccAWSS3BucketObject_NonVersioned(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_NonVersioned(acctest.RandInt(), sourceInitial), + Config: testAccAWSS3BucketObjectConfig_nonVersioned(rName, sourceInitial), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &originalObj), testAccCheckAWSS3BucketObjectBody(&originalObj, "initial object state"), @@ -344,7 +345,7 @@ func TestAccAWSS3BucketObject_NonVersioned(t *testing.T) { func TestAccAWSS3BucketObject_updates(t *testing.T) { var originalObj, modifiedObj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") sourceInitial := testAccAWSS3BucketObjectCreateTempFile(t, "initial object state") defer os.Remove(sourceInitial) @@ -358,7 +359,7 @@ func TestAccAWSS3BucketObject_updates(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_updateable(rInt, false, sourceInitial), + Config: testAccAWSS3BucketObjectConfig_updateable(rName, false, sourceInitial), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &originalObj), testAccCheckAWSS3BucketObjectBody(&originalObj, "initial object state"), @@ -369,7 +370,7 @@ func TestAccAWSS3BucketObject_updates(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_updateable(rInt, false, sourceModified), + Config: testAccAWSS3BucketObjectConfig_updateable(rName, false, sourceModified), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &modifiedObj), testAccCheckAWSS3BucketObjectBody(&modifiedObj, "modified object"), @@ -386,7 +387,7 @@ func TestAccAWSS3BucketObject_updates(t *testing.T) { func TestAccAWSS3BucketObject_updateSameFile(t *testing.T) { var originalObj, modifiedObj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") startingData := "lane 8" changingData := "chicane" @@ -409,7 +410,7 @@ func TestAccAWSS3BucketObject_updateSameFile(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_updateable(rInt, false, filename), + Config: testAccAWSS3BucketObjectConfig_updateable(rName, false, filename), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &originalObj), testAccCheckAWSS3BucketObjectBody(&originalObj, startingData), @@ -419,7 +420,7 @@ func TestAccAWSS3BucketObject_updateSameFile(t *testing.T) { ExpectNonEmptyPlan: true, }, { - Config: testAccAWSS3BucketObjectConfig_updateable(rInt, false, filename), + Config: testAccAWSS3BucketObjectConfig_updateable(rName, false, filename), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &modifiedObj), testAccCheckAWSS3BucketObjectBody(&modifiedObj, changingData), @@ -433,7 +434,7 @@ func TestAccAWSS3BucketObject_updateSameFile(t *testing.T) { func TestAccAWSS3BucketObject_updatesWithVersioning(t *testing.T) { var originalObj, modifiedObj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") sourceInitial := testAccAWSS3BucketObjectCreateTempFile(t, "initial versioned object state") defer os.Remove(sourceInitial) @@ -447,7 +448,7 @@ func TestAccAWSS3BucketObject_updatesWithVersioning(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_updateable(rInt, true, sourceInitial), + Config: testAccAWSS3BucketObjectConfig_updateable(rName, true, sourceInitial), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &originalObj), testAccCheckAWSS3BucketObjectBody(&originalObj, "initial versioned object state"), @@ -455,7 +456,7 @@ func TestAccAWSS3BucketObject_updatesWithVersioning(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_updateable(rInt, true, sourceModified), + Config: testAccAWSS3BucketObjectConfig_updateable(rName, true, sourceModified), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &modifiedObj), testAccCheckAWSS3BucketObjectBody(&modifiedObj, "modified versioned object"), @@ -509,7 +510,7 @@ func TestAccAWSS3BucketObject_updatesWithVersioningViaAccessPoint(t *testing.T) func TestAccAWSS3BucketObject_kms(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") source := testAccAWSS3BucketObjectCreateTempFile(t, "{anything will do }") defer os.Remove(source) @@ -522,7 +523,7 @@ func TestAccAWSS3BucketObject_kms(t *testing.T) { Steps: []resource.TestStep{ { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectConfig_withKMSId(rInt, source), + Config: testAccAWSS3BucketObjectConfig_withKMSId(rName, source), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectSSE(resourceName, "aws:kms"), @@ -536,7 +537,7 @@ func TestAccAWSS3BucketObject_kms(t *testing.T) { func TestAccAWSS3BucketObject_sse(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") source := testAccAWSS3BucketObjectCreateTempFile(t, "{anything will do }") defer os.Remove(source) @@ -549,7 +550,7 @@ func TestAccAWSS3BucketObject_sse(t *testing.T) { Steps: []resource.TestStep{ { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectConfig_withSSE(rInt, source), + Config: testAccAWSS3BucketObjectConfig_withSSE(rName, source), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectSSE(resourceName, "AES256"), @@ -563,7 +564,7 @@ func TestAccAWSS3BucketObject_sse(t *testing.T) { func TestAccAWSS3BucketObject_acl(t *testing.T) { var obj1, obj2, obj3 s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -572,7 +573,7 @@ func TestAccAWSS3BucketObject_acl(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_acl(rInt, "some_bucket_content", "private"), + Config: testAccAWSS3BucketObjectConfig_acl(rName, "some_bucket_content", "private"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj1), testAccCheckAWSS3BucketObjectBody(&obj1, "some_bucket_content"), @@ -581,7 +582,7 @@ func TestAccAWSS3BucketObject_acl(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_acl(rInt, "some_bucket_content", "public-read"), + Config: testAccAWSS3BucketObjectConfig_acl(rName, "some_bucket_content", "public-read"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj2), testAccCheckAWSS3BucketObjectVersionIdEquals(&obj2, &obj1), @@ -591,7 +592,7 @@ func TestAccAWSS3BucketObject_acl(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_acl(rInt, "changed_some_bucket_content", "private"), + Config: testAccAWSS3BucketObjectConfig_acl(rName, "changed_some_bucket_content", "private"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj3), testAccCheckAWSS3BucketObjectVersionIdDiffers(&obj3, &obj2), @@ -605,7 +606,7 @@ func TestAccAWSS3BucketObject_acl(t *testing.T) { } func TestAccAWSS3BucketObject_metadata(t *testing.T) { - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" @@ -616,7 +617,7 @@ func TestAccAWSS3BucketObject_metadata(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_withMetadata(rInt, "key1", "value1", "key2", "value2"), + Config: testAccAWSS3BucketObjectConfig_withMetadata(rName, "key1", "value1", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), resource.TestCheckResourceAttr(resourceName, "metadata.%", "2"), @@ -625,7 +626,7 @@ func TestAccAWSS3BucketObject_metadata(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_withMetadata(rInt, "key1", "value1updated", "key3", "value3"), + Config: testAccAWSS3BucketObjectConfig_withMetadata(rName, "key1", "value1updated", "key3", "value3"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), resource.TestCheckResourceAttr(resourceName, "metadata.%", "2"), @@ -634,7 +635,7 @@ func TestAccAWSS3BucketObject_metadata(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfigEmpty(rInt), + Config: testAccAWSS3BucketObjectConfigEmpty(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), resource.TestCheckResourceAttr(resourceName, "metadata.%", "0"), @@ -647,7 +648,7 @@ func TestAccAWSS3BucketObject_metadata(t *testing.T) { func TestAccAWSS3BucketObject_storageClass(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -657,7 +658,7 @@ func TestAccAWSS3BucketObject_storageClass(t *testing.T) { Steps: []resource.TestStep{ { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectConfigContent(rInt, "some_bucket_content"), + Config: testAccAWSS3BucketObjectConfigContent(rName, "some_bucket_content"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), resource.TestCheckResourceAttr(resourceName, "storage_class", "STANDARD"), @@ -665,7 +666,7 @@ func TestAccAWSS3BucketObject_storageClass(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_storageClass(rInt, "REDUCED_REDUNDANCY"), + Config: testAccAWSS3BucketObjectConfig_storageClass(rName, "REDUCED_REDUNDANCY"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), resource.TestCheckResourceAttr(resourceName, "storage_class", "REDUCED_REDUNDANCY"), @@ -673,7 +674,7 @@ func TestAccAWSS3BucketObject_storageClass(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_storageClass(rInt, "GLACIER"), + Config: testAccAWSS3BucketObjectConfig_storageClass(rName, "GLACIER"), Check: resource.ComposeTestCheckFunc( // Can't GetObject on an object in Glacier without restoring it. resource.TestCheckResourceAttr(resourceName, "storage_class", "GLACIER"), @@ -681,7 +682,7 @@ func TestAccAWSS3BucketObject_storageClass(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_storageClass(rInt, "INTELLIGENT_TIERING"), + Config: testAccAWSS3BucketObjectConfig_storageClass(rName, "INTELLIGENT_TIERING"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), resource.TestCheckResourceAttr(resourceName, "storage_class", "INTELLIGENT_TIERING"), @@ -689,7 +690,7 @@ func TestAccAWSS3BucketObject_storageClass(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_storageClass(rInt, "DEEP_ARCHIVE"), + Config: testAccAWSS3BucketObjectConfig_storageClass(rName, "DEEP_ARCHIVE"), Check: resource.ComposeTestCheckFunc( // Can't GetObject on an object in DEEP_ARCHIVE without restoring it. resource.TestCheckResourceAttr(resourceName, "storage_class", "DEEP_ARCHIVE"), @@ -960,10 +961,10 @@ func TestAccAWSS3BucketObject_tagsMultipleSlashes(t *testing.T) { }) } -func TestAccAWSS3BucketObject_ObjectLockLegalHoldStartWithNone(t *testing.T) { +func TestAccAWSS3BucketObject_objectLockLegalHoldStartWithNone(t *testing.T) { var obj1, obj2, obj3 s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -972,7 +973,7 @@ func TestAccAWSS3BucketObject_ObjectLockLegalHoldStartWithNone(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_noObjectLockLegalHold(rInt, "stuff"), + Config: testAccAWSS3BucketObjectConfig_noObjectLockLegalHold(rName, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj1), testAccCheckAWSS3BucketObjectBody(&obj1, "stuff"), @@ -982,7 +983,7 @@ func TestAccAWSS3BucketObject_ObjectLockLegalHoldStartWithNone(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_withObjectLockLegalHold(rInt, "stuff", "ON"), + Config: testAccAWSS3BucketObjectConfig_withObjectLockLegalHold(rName, "stuff", "ON"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj2), testAccCheckAWSS3BucketObjectVersionIdEquals(&obj2, &obj1), @@ -994,7 +995,7 @@ func TestAccAWSS3BucketObject_ObjectLockLegalHoldStartWithNone(t *testing.T) { }, // Remove legal hold but create a new object version to test force_destroy { - Config: testAccAWSS3BucketObjectConfig_withObjectLockLegalHold(rInt, "changed stuff", "OFF"), + Config: testAccAWSS3BucketObjectConfig_withObjectLockLegalHold(rName, "changed stuff", "OFF"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj3), testAccCheckAWSS3BucketObjectVersionIdDiffers(&obj3, &obj2), @@ -1008,10 +1009,10 @@ func TestAccAWSS3BucketObject_ObjectLockLegalHoldStartWithNone(t *testing.T) { }) } -func TestAccAWSS3BucketObject_ObjectLockLegalHoldStartWithOn(t *testing.T) { +func TestAccAWSS3BucketObject_objectLockLegalHoldStartWithOn(t *testing.T) { var obj1, obj2 s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -1020,7 +1021,7 @@ func TestAccAWSS3BucketObject_ObjectLockLegalHoldStartWithOn(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_withObjectLockLegalHold(rInt, "stuff", "ON"), + Config: testAccAWSS3BucketObjectConfig_withObjectLockLegalHold(rName, "stuff", "ON"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj1), testAccCheckAWSS3BucketObjectBody(&obj1, "stuff"), @@ -1030,7 +1031,7 @@ func TestAccAWSS3BucketObject_ObjectLockLegalHoldStartWithOn(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_withObjectLockLegalHold(rInt, "stuff", "OFF"), + Config: testAccAWSS3BucketObjectConfig_withObjectLockLegalHold(rName, "stuff", "OFF"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj2), testAccCheckAWSS3BucketObjectVersionIdEquals(&obj2, &obj1), @@ -1044,10 +1045,10 @@ func TestAccAWSS3BucketObject_ObjectLockLegalHoldStartWithOn(t *testing.T) { }) } -func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithNone(t *testing.T) { +func TestAccAWSS3BucketObject_objectLockRetentionStartWithNone(t *testing.T) { var obj1, obj2, obj3 s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") retainUntilDate := time.Now().UTC().AddDate(0, 0, 10).Format(time.RFC3339) resource.ParallelTest(t, resource.TestCase{ @@ -1057,7 +1058,7 @@ func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithNone(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_noObjectLockRetention(rInt, "stuff"), + Config: testAccAWSS3BucketObjectConfig_noObjectLockRetention(rName, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj1), testAccCheckAWSS3BucketObjectBody(&obj1, "stuff"), @@ -1067,7 +1068,7 @@ func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithNone(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_withObjectLockRetention(rInt, "stuff", retainUntilDate), + Config: testAccAWSS3BucketObjectConfig_withObjectLockRetention(rName, "stuff", retainUntilDate), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj2), testAccCheckAWSS3BucketObjectVersionIdEquals(&obj2, &obj1), @@ -1079,7 +1080,7 @@ func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithNone(t *testing.T) { }, // Remove retention period but create a new object version to test force_destroy { - Config: testAccAWSS3BucketObjectConfig_noObjectLockRetention(rInt, "changed stuff"), + Config: testAccAWSS3BucketObjectConfig_noObjectLockRetention(rName, "changed stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj3), testAccCheckAWSS3BucketObjectVersionIdDiffers(&obj3, &obj2), @@ -1093,10 +1094,10 @@ func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithNone(t *testing.T) { }) } -func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithSet(t *testing.T) { +func TestAccAWSS3BucketObject_objectLockRetentionStartWithSet(t *testing.T) { var obj1, obj2, obj3, obj4 s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") retainUntilDate1 := time.Now().UTC().AddDate(0, 0, 20).Format(time.RFC3339) retainUntilDate2 := time.Now().UTC().AddDate(0, 0, 30).Format(time.RFC3339) retainUntilDate3 := time.Now().UTC().AddDate(0, 0, 10).Format(time.RFC3339) @@ -1108,7 +1109,7 @@ func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithSet(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_withObjectLockRetention(rInt, "stuff", retainUntilDate1), + Config: testAccAWSS3BucketObjectConfig_withObjectLockRetention(rName, "stuff", retainUntilDate1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj1), testAccCheckAWSS3BucketObjectBody(&obj1, "stuff"), @@ -1118,7 +1119,7 @@ func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithSet(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_withObjectLockRetention(rInt, "stuff", retainUntilDate2), + Config: testAccAWSS3BucketObjectConfig_withObjectLockRetention(rName, "stuff", retainUntilDate2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj2), testAccCheckAWSS3BucketObjectVersionIdEquals(&obj2, &obj1), @@ -1129,7 +1130,7 @@ func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithSet(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_withObjectLockRetention(rInt, "stuff", retainUntilDate3), + Config: testAccAWSS3BucketObjectConfig_withObjectLockRetention(rName, "stuff", retainUntilDate3), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj3), testAccCheckAWSS3BucketObjectVersionIdEquals(&obj3, &obj2), @@ -1140,7 +1141,7 @@ func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithSet(t *testing.T) { ), }, { - Config: testAccAWSS3BucketObjectConfig_noObjectLockRetention(rInt, "stuff"), + Config: testAccAWSS3BucketObjectConfig_noObjectLockRetention(rName, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj4), testAccCheckAWSS3BucketObjectVersionIdEquals(&obj4, &obj3), @@ -1157,7 +1158,7 @@ func TestAccAWSS3BucketObject_ObjectLockRetentionStartWithSet(t *testing.T) { func TestAccAWSS3BucketObject_objectBucketKeyEnabled(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -1166,7 +1167,7 @@ func TestAccAWSS3BucketObject_objectBucketKeyEnabled(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_objectBucketKeyEnabled(rInt, "stuff"), + Config: testAccAWSS3BucketObjectConfig_objectBucketKeyEnabled(rName, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectBody(&obj, "stuff"), @@ -1180,7 +1181,7 @@ func TestAccAWSS3BucketObject_objectBucketKeyEnabled(t *testing.T) { func TestAccAWSS3BucketObject_bucketBucketKeyEnabled(t *testing.T) { var obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -1189,7 +1190,7 @@ func TestAccAWSS3BucketObject_bucketBucketKeyEnabled(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_bucketBucketKeyEnabled(rInt, "stuff"), + Config: testAccAWSS3BucketObjectConfig_bucketBucketKeyEnabled(rName, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectBody(&obj, "stuff"), @@ -1203,7 +1204,7 @@ func TestAccAWSS3BucketObject_bucketBucketKeyEnabled(t *testing.T) { func TestAccAWSS3BucketObject_defaultBucketSSE(t *testing.T) { var obj1 s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - rInt := acctest.RandInt() + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -1212,7 +1213,7 @@ func TestAccAWSS3BucketObject_defaultBucketSSE(t *testing.T) { CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSS3BucketObjectConfig_defaultBucketSSE(rInt, "stuff"), + Config: testAccAWSS3BucketObjectConfig_defaultBucketSSE(rName, "stuff"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj1), testAccCheckAWSS3BucketObjectBody(&obj1, "stuff"), @@ -1535,114 +1536,114 @@ resource "aws_s3_bucket_object" "object" { `, bucket, key) } -func testAccAWSS3BucketObjectConfigEmpty(randInt int) string { +func testAccAWSS3BucketObjectConfigEmpty(rName string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" } -`, randInt) +`, rName) } -func testAccAWSS3BucketObjectConfigSource(randInt int, source string) string { +func testAccAWSS3BucketObjectConfigSource(rName string, source string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" source = %[2]q content_type = "binary/octet-stream" } -`, randInt, source) +`, rName, source) } -func testAccAWSS3BucketObjectConfig_withContentCharacteristics(randInt int, source string) string { +func testAccAWSS3BucketObjectConfig_withContentCharacteristics(rName string, source string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" source = %[2]q content_language = "en" content_type = "binary/octet-stream" website_redirect = "http://google.com" } -`, randInt, source) +`, rName, source) } -func testAccAWSS3BucketObjectConfigContent(randInt int, content string) string { +func testAccAWSS3BucketObjectConfigContent(rName string, content string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" content = %[2]q } -`, randInt, content) +`, rName, content) } -func testAccAWSS3BucketObjectEtagEncryption(randInt int, source string) string { +func testAccAWSS3BucketObjectEtagEncryption(rName string, source string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" server_side_encryption = "AES256" source = %[2]q etag = filemd5(%[2]q) } -`, randInt, source) +`, rName, source) } -func testAccAWSS3BucketObjectConfigContentBase64(randInt int, contentBase64 string) string { +func testAccAWSS3BucketObjectConfigContentBase64(rName string, contentBase64 string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" content_base64 = %[2]q } -`, randInt, contentBase64) +`, rName, contentBase64) } -func testAccAWSS3BucketObjectConfig_SourceHashTrigger(randInt int, source string) string { +func testAccAWSS3BucketObjectConfig_sourceHashTrigger(rName string, source string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = "${aws_s3_bucket.object_bucket.bucket}" + bucket = aws_s3_bucket.test.bucket key = "test-key" - source = "%s" - source_hash = "${filemd5("%s")}" + source = %[2]q + source_hash = filemd5(%[2]q) } -`, randInt, source, source) +`, rName, source) } -func testAccAWSS3BucketObjectConfig_updateable(randInt int, bucketVersioning bool, source string) string { +func testAccAWSS3BucketObjectConfig_updateable(rName string, bucketVersioning bool, source string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "object_bucket_3" { - bucket = "tf-object-test-bucket-%[1]d" + bucket = %[1]q versioning { enabled = %[2]t @@ -1655,7 +1656,7 @@ resource "aws_s3_bucket_object" "object" { source = %[3]q etag = filemd5(%[3]q) } -`, randInt, bucketVersioning, source) +`, rName, bucketVersioning, source) } func testAccAWSS3BucketObjectConfig_updateableViaAccessPoint(rName string, bucketVersioning bool, source string) string { @@ -1682,42 +1683,42 @@ resource "aws_s3_bucket_object" "test" { `, rName, bucketVersioning, source) } -func testAccAWSS3BucketObjectConfig_withKMSId(randInt int, source string) string { +func testAccAWSS3BucketObjectConfig_withKMSId(rName string, source string) string { return fmt.Sprintf(` resource "aws_kms_key" "kms_key_1" {} -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" source = %[2]q kms_key_id = aws_kms_key.kms_key_1.arn } -`, randInt, source) +`, rName, source) } -func testAccAWSS3BucketObjectConfig_withSSE(randInt int, source string) string { +func testAccAWSS3BucketObjectConfig_withSSE(rName string, source string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" source = %[2]q server_side_encryption = "AES256" } -`, randInt, source) +`, rName, source) } -func testAccAWSS3BucketObjectConfig_acl(randInt int, content, acl string) string { +func testAccAWSS3BucketObjectConfig_acl(rName string, content, acl string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q versioning { enabled = true @@ -1725,32 +1726,32 @@ resource "aws_s3_bucket" "object_bucket" { } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" content = %[2]q acl = %[3]q } -`, randInt, content, acl) +`, rName, content, acl) } -func testAccAWSS3BucketObjectConfig_storageClass(randInt int, storage_class string) string { +func testAccAWSS3BucketObjectConfig_storageClass(rName string, storage_class string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" content = "some_bucket_content" storage_class = %[2]q } -`, randInt, storage_class) +`, rName, storage_class) } func testAccAWSS3BucketObjectConfig_withTags(rName, key, content string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { +resource "aws_s3_bucket" "test" { bucket = %[1]q versioning { @@ -1759,7 +1760,7 @@ resource "aws_s3_bucket" "object_bucket" { } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = %[2]q content = %[3]q @@ -1774,7 +1775,7 @@ resource "aws_s3_bucket_object" "object" { func testAccAWSS3BucketObjectConfig_withUpdatedTags(rName, key, content string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { +resource "aws_s3_bucket" "test" { bucket = %[1]q versioning { @@ -1783,7 +1784,7 @@ resource "aws_s3_bucket" "object_bucket" { } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = %[2]q content = %[3]q @@ -1799,7 +1800,7 @@ resource "aws_s3_bucket_object" "object" { func testAccAWSS3BucketObjectConfig_withNoTags(rName, key, content string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { +resource "aws_s3_bucket" "test" { bucket = %[1]q versioning { @@ -1808,21 +1809,21 @@ resource "aws_s3_bucket" "object_bucket" { } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = %[2]q content = %[3]q } `, rName, key, content) } -func testAccAWSS3BucketObjectConfig_withMetadata(randInt int, metadataKey1, metadataValue1, metadataKey2, metadataValue2 string) string { +func testAccAWSS3BucketObjectConfig_withMetadata(rName string, metadataKey1, metadataValue1, metadataKey2, metadataValue2 string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" metadata = { @@ -1830,13 +1831,13 @@ resource "aws_s3_bucket_object" "object" { %[4]s = %[5]q } } -`, randInt, metadataKey1, metadataValue1, metadataKey2, metadataValue2) +`, rName, metadataKey1, metadataValue1, metadataKey2, metadataValue2) } -func testAccAWSS3BucketObjectConfig_noObjectLockLegalHold(randInt int, content string) string { +func testAccAWSS3BucketObjectConfig_noObjectLockLegalHold(rName string, content string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q versioning { enabled = true @@ -1848,18 +1849,18 @@ resource "aws_s3_bucket" "object_bucket" { } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" content = %[2]q force_destroy = true } -`, randInt, content) +`, rName, content) } -func testAccAWSS3BucketObjectConfig_withObjectLockLegalHold(randInt int, content, legalHoldStatus string) string { +func testAccAWSS3BucketObjectConfig_withObjectLockLegalHold(rName string, content, legalHoldStatus string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q versioning { enabled = true @@ -1871,19 +1872,19 @@ resource "aws_s3_bucket" "object_bucket" { } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" content = %[2]q object_lock_legal_hold_status = %[3]q force_destroy = true } -`, randInt, content, legalHoldStatus) +`, rName, content, legalHoldStatus) } -func testAccAWSS3BucketObjectConfig_noObjectLockRetention(randInt int, content string) string { +func testAccAWSS3BucketObjectConfig_noObjectLockRetention(rName string, content string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q versioning { enabled = true @@ -1895,18 +1896,18 @@ resource "aws_s3_bucket" "object_bucket" { } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" content = %[2]q force_destroy = true } -`, randInt, content) +`, rName, content) } -func testAccAWSS3BucketObjectConfig_withObjectLockRetention(randInt int, content, retainUntilDate string) string { +func testAccAWSS3BucketObjectConfig_withObjectLockRetention(rName string, content, retainUntilDate string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q versioning { enabled = true @@ -1918,17 +1919,17 @@ resource "aws_s3_bucket" "object_bucket" { } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" content = %[2]q force_destroy = true object_lock_mode = "GOVERNANCE" object_lock_retain_until_date = %[3]q } -`, randInt, content, retainUntilDate) +`, rName, content, retainUntilDate) } -func testAccAWSS3BucketObjectConfig_NonVersioned(randInt int, source string) string { +func testAccAWSS3BucketObjectConfig_nonVersioned(rName string, source string) string { policy := `{ "Version": "2012-10-17", "Statement": [ @@ -1952,7 +1953,7 @@ func testAccAWSS3BucketObjectConfig_NonVersioned(randInt int, source string) str return testAccProviderConfigAssumeRolePolicy(policy) + fmt.Sprintf(` resource "aws_s3_bucket" "object_bucket_3" { - bucket = "tf-object-test-bucket-%[1]d" + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { @@ -1961,39 +1962,39 @@ resource "aws_s3_bucket_object" "object" { source = %[2]q etag = filemd5(%[2]q) } -`, randInt, source) +`, rName, source) } -func testAccAWSS3BucketObjectConfig_objectBucketKeyEnabled(randInt int, content string) string { +func testAccAWSS3BucketObjectConfig_objectBucketKeyEnabled(rName string, content string) string { return fmt.Sprintf(` resource "aws_kms_key" "test" { description = "Encrypts test bucket objects" deletion_window_in_days = 7 } -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" content = %q kms_key_id = aws_kms_key.test.arn bucket_key_enabled = true } -`, randInt, content) +`, rName, content) } -func testAccAWSS3BucketObjectConfig_bucketBucketKeyEnabled(randInt int, content string) string { +func testAccAWSS3BucketObjectConfig_bucketBucketKeyEnabled(rName string, content string) string { return fmt.Sprintf(` resource "aws_kms_key" "test" { description = "Encrypts test bucket objects" deletion_window_in_days = 7 } -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%[1]d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q server_side_encryption_configuration { rule { @@ -2007,22 +2008,22 @@ resource "aws_s3_bucket" "object_bucket" { } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" content = %q } -`, randInt, content) +`, rName, content) } -func testAccAWSS3BucketObjectConfig_defaultBucketSSE(randInt int, content string) string { +func testAccAWSS3BucketObjectConfig_defaultBucketSSE(rName string, content string) string { return fmt.Sprintf(` resource "aws_kms_key" "test" { description = "Encrypts test bucket objects" deletion_window_in_days = 7 } -resource "aws_s3_bucket" "object_bucket" { - bucket = "tf-object-test-bucket-%d" +resource "aws_s3_bucket" "test" { + bucket = %[1]q server_side_encryption_configuration { rule { apply_server_side_encryption_by_default { @@ -2034,9 +2035,9 @@ resource "aws_s3_bucket" "object_bucket" { } resource "aws_s3_bucket_object" "object" { - bucket = aws_s3_bucket.object_bucket.bucket + bucket = aws_s3_bucket.test.bucket key = "test-key" - content = %q + content = %[2]q } -`, randInt, content) +`, rName, content) } From 2ee18a55fb851c8592d4394996b2e87a20825d7f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 22:40:21 -0400 Subject: [PATCH 1165/1208] tests/r/s3_bucket_object: Fix tests --- aws/resource_aws_s3_bucket_object_test.go | 35 +++++++++++++---------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/aws/resource_aws_s3_bucket_object_test.go b/aws/resource_aws_s3_bucket_object_test.go index 561aa388a3fd..33fc74424fce 100644 --- a/aws/resource_aws_s3_bucket_object_test.go +++ b/aws/resource_aws_s3_bucket_object_test.go @@ -4,7 +4,6 @@ import ( "encoding/base64" "fmt" "io" - "io/ioutil" "log" "os" "reflect" @@ -251,15 +250,21 @@ func TestAccAWSS3BucketObject_contentBase64(t *testing.T) { func TestAccAWSS3BucketObject_sourceHashTrigger(t *testing.T) { var obj, updated_obj s3.GetObjectOutput resourceName := "aws_s3_bucket_object.object" - source := testAccAWSS3BucketObjectCreateTempFile(t, "{anything will do }") - rewriteSourceF := func(*terraform.State) error { - if err := ioutil.WriteFile(source, []byte("{any other thing will do }"), 0644); err != nil { - os.Remove(source) + rName := acctest.RandomWithPrefix("tf-acc-test") + + startingData := "Ebben!" + changingData := "Ne andrò lontana" + + filename := testAccAWSS3BucketObjectCreateTempFile(t, startingData) + defer os.Remove(filename) + + rewriteFile := func(*terraform.State) error { + if err := os.WriteFile(filename, []byte(changingData), 0644); err != nil { + os.Remove(filename) t.Fatal(err) } return nil } - rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -268,22 +273,22 @@ func TestAccAWSS3BucketObject_sourceHashTrigger(t *testing.T) { Steps: []resource.TestStep{ { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectConfig_sourceHashTrigger(rName, source), + Config: testAccAWSS3BucketObjectConfig_sourceHashTrigger(rName, filename), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &obj), - testAccCheckAWSS3BucketObjectBody(&obj, "{anything will do }"), - resource.TestCheckResourceAttr(resourceName, "source_hash", "7b006ff4d70f68cc65061acf2f802e6f"), - rewriteSourceF, + testAccCheckAWSS3BucketObjectBody(&obj, "Ebben!"), + resource.TestCheckResourceAttr(resourceName, "source_hash", "7c7e02a79f28968882bb1426c8f8bfc6"), + rewriteFile, ), ExpectNonEmptyPlan: true, }, { PreConfig: func() {}, - Config: testAccAWSS3BucketObjectConfig_sourceHashTrigger(rName, source), + Config: testAccAWSS3BucketObjectConfig_sourceHashTrigger(rName, filename), Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketObjectExists(resourceName, &updated_obj), - testAccCheckAWSS3BucketObjectBody(&updated_obj, "{any other thing will do }"), - resource.TestCheckResourceAttr(resourceName, "source_hash", "77a736aa9e04d0dc96b9b30894963983"), + testAccCheckAWSS3BucketObjectBody(&updated_obj, "Ne andrò lontana"), + resource.TestCheckResourceAttr(resourceName, "source_hash", "cffc5e20de2d21764145b1124c9b337b"), ), }, }, @@ -1260,12 +1265,12 @@ func TestAccAWSS3BucketObject_ignoreTags(t *testing.T) { testAccCheckAWSS3BucketObjectExists(resourceName, &obj), testAccCheckAWSS3BucketObjectBody(&obj, "stuff"), resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"), + resource.TestCheckResourceAttr(resourceName, "tags.Key1", "A@AA"), resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"), resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"), testAccCheckAWSS3BucketObjectCheckTags(resourceName, map[string]string{ "ignorekey1": "ignorevalue1", - "Key1": "AAA", + "Key1": "A@AA", "Key2": "BBB", "Key3": "CCC", }), From 73fad554a32a50a6937d0ba12de30709655d36c0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 22:40:43 -0400 Subject: [PATCH 1166/1208] docs/r/s3_bucket_object: Clean up documentation --- website/docs/r/s3_bucket_object.html.markdown | 65 +++++++++---------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/website/docs/r/s3_bucket_object.html.markdown b/website/docs/r/s3_bucket_object.html.markdown index f9934409c5aa..9d53f2509986 100644 --- a/website/docs/r/s3_bucket_object.html.markdown +++ b/website/docs/r/s3_bucket_object.html.markdown @@ -113,37 +113,35 @@ resource "aws_s3_bucket_object" "examplebucket_object" { -> **Note:** If you specify `content_encoding` you are responsible for encoding the body appropriately. `source`, `content`, and `content_base64` all expect already encoded/compressed bytes. -The following arguments are supported: +The following arguments are required: -* `bucket` - (Required) The name of the bucket to put the file in. Alternatively, an [S3 access point](https://docs.aws.amazon.com/AmazonS3/latest/dev/using-access-points.html) ARN can be specified. -* `key` - (Required) The name of the object once it is in the bucket. -* `source` - (Optional, conflicts with `content` and `content_base64`) The path to a file that will be read and uploaded as raw bytes for the object content. -* `content` - (Optional, conflicts with `source` and `content_base64`) Literal string value to use as the object content, which will be uploaded as UTF-8-encoded text. -* `content_base64` - (Optional, conflicts with `source` and `content`) Base64-encoded data that will be decoded and uploaded as raw bytes for the object content. This allows safely uploading non-UTF8 binary data, but is recommended only for small content such as the result of the `gzipbase64` function with small text strings. For larger objects, use `source` to stream the content from a disk file. -* `acl` - (Optional) The [canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) to apply. Valid values are `private`, `public-read`, `public-read-write`, `aws-exec-read`, `authenticated-read`, `bucket-owner-read`, and `bucket-owner-full-control`. Defaults to `private`. -* `cache_control` - (Optional) Specifies caching behavior along the request/reply chain Read [w3c cache_control](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9) for further details. -* `content_disposition` - (Optional) Specifies presentational information for the object. Read [w3c content_disposition](http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1) for further information. -* `content_encoding` - (Optional) Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field. Read [w3c content encoding](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11) for further information. -* `content_language` - (Optional) The language the content is in e.g. en-US or en-GB. -* `content_type` - (Optional) A standard MIME type describing the format of the object data, e.g. application/octet-stream. All Valid MIME Types are valid for this input. -* `website_redirect` - (Optional) Specifies a target URL for [website redirect](http://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-page-redirect.html). -* `storage_class` - (Optional) Specifies the desired [Storage Class](http://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html) -for the object. Can be either "`STANDARD`", "`REDUCED_REDUNDANCY`", "`ONEZONE_IA`", "`INTELLIGENT_TIERING`", "`GLACIER`", "`DEEP_ARCHIVE`", or "`STANDARD_IA`". Defaults to "`STANDARD`". -* `etag` - (Optional) Used to trigger updates. The only meaningful value is `${filemd5("path/to/file")}` (Terraform 0.11.12 or later) or `${md5(file("path/to/file"))}` (Terraform 0.11.11 or earlier). -This attribute is not compatible with KMS encryption, `kms_key_id` or `server_side_encryption = "aws:kms"`. -* `source_hash` - (Optional) Used to trigger updates based on source local changes. If used, must be set to `${filemd5("path/to/source")}` (Terraform 0.11.12 or later). This differs from `etag` since the value is stored in the state and does not come from AWS. Especially useful to address `etag` KMS encryption limitations. -* `server_side_encryption` - (Optional) Specifies server-side encryption of the object in S3. Valid values are "`AES256`" and "`aws:kms`". -* `kms_key_id` - (Optional) Amazon Resource Name (ARN) of the KMS Key to use for object encryption. If the S3 Bucket has server-side encryption enabled, that value will automatically be used. If referencing the -`aws_kms_key` resource, use the `arn` attribute. If referencing the `aws_kms_alias` data source or resource, use the `target_key_arn` attribute. Terraform will only perform drift detection if a configuration value -is provided. +* `bucket` - (Required) Name of the bucket to put the file in. Alternatively, an [S3 access point](https://docs.aws.amazon.com/AmazonS3/latest/dev/using-access-points.html) ARN can be specified. +* `key` - (Required) Name of the object once it is in the bucket. + +The following arguments are optional: + +* `acl` - (Optional) [Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) to apply. Valid values are `private`, `public-read`, `public-read-write`, `aws-exec-read`, `authenticated-read`, `bucket-owner-read`, and `bucket-owner-full-control`. Defaults to `private`. * `bucket_key_enabled` - (Optional) Whether or not to use [Amazon S3 Bucket Keys](https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html) for SSE-KMS. -* `metadata` - (Optional) A map of keys/values to provision metadata (will be automatically prefixed by `x-amz-meta-`, note that only lowercase label are currently supported by the AWS Go API). -* `tags` - (Optional) A map of tags to assign to the object. 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. -* `force_destroy` - (Optional) Allow the object to be deleted by removing any legal hold on any object version. -Default is `false`. This value should be set to `true` only if the bucket has S3 object lock enabled. -* `object_lock_legal_hold_status` - (Optional) The [legal hold](https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html#object-lock-legal-holds) status that you want to apply to the specified object. Valid values are `ON` and `OFF`. -* `object_lock_mode` - (Optional) The object lock [retention mode](https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html#object-lock-retention-modes) that you want to apply to this object. Valid values are `GOVERNANCE` and `COMPLIANCE`. -* `object_lock_retain_until_date` - (Optional) The date and time, in [RFC3339 format](https://tools.ietf.org/html/rfc3339#section-5.8), when this object's object lock will [expire](https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html#object-lock-retention-periods). +* `cache_control` - (Optional) Caching behavior along the request/reply chain Read [w3c cache_control](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9) for further details. +* `content_base64` - (Optional, conflicts with `source` and `content`) Base64-encoded data that will be decoded and uploaded as raw bytes for the object content. This allows safely uploading non-UTF8 binary data, but is recommended only for small content such as the result of the `gzipbase64` function with small text strings. For larger objects, use `source` to stream the content from a disk file. +* `content_disposition` - (Optional) Presentational information for the object. Read [w3c content_disposition](http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1) for further information. +* `content_encoding` - (Optional) Content encodings that have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field. Read [w3c content encoding](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11) for further information. +* `content_language` - (Optional) Language the content is in e.g. en-US or en-GB. +* `content_type` - (Optional) Standard MIME type describing the format of the object data, e.g. application/octet-stream. All Valid MIME Types are valid for this input. +* `content` - (Optional, conflicts with `source` and `content_base64`) Literal string value to use as the object content, which will be uploaded as UTF-8-encoded text. +* `etag` - (Optional) Triggers updates when the value changes. The only meaningful value is `filemd5("path/to/file")` (Terraform 0.11.12 or later) or `${md5(file("path/to/file"))}` (Terraform 0.11.11 or earlier). This attribute is not compatible with KMS encryption, `kms_key_id` or `server_side_encryption = "aws:kms"` (see `source_hash` instead). +* `force_destroy` - (Optional) Whether to allow the object to be deleted by removing any legal hold on any object version. Default is `false`. This value should be set to `true` only if the bucket has S3 object lock enabled. +* `kms_key_id` - (Optional) ARN of the KMS Key to use for object encryption. If the S3 Bucket has server-side encryption enabled, that value will automatically be used. If referencing the `aws_kms_key` resource, use the `arn` attribute. If referencing the `aws_kms_alias` data source or resource, use the `target_key_arn` attribute. Terraform will only perform drift detection if a configuration value is provided. +* `metadata` - (Optional) Map of keys/values to provision metadata (will be automatically prefixed by `x-amz-meta-`, note that only lowercase label are currently supported by the AWS Go API). +* `object_lock_legal_hold_status` - (Optional) [Legal hold](https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html#object-lock-legal-holds) status that you want to apply to the specified object. Valid values are `ON` and `OFF`. +* `object_lock_mode` - (Optional) Object lock [retention mode](https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html#object-lock-retention-modes) that you want to apply to this object. Valid values are `GOVERNANCE` and `COMPLIANCE`. +* `object_lock_retain_until_date` - (Optional) Date and time, in [RFC3339 format](https://tools.ietf.org/html/rfc3339#section-5.8), when this object's object lock will [expire](https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html#object-lock-retention-periods). +* `server_side_encryption` - (Optional) Server-side encryption of the object in S3. Valid values are "`AES256`" and "`aws:kms`". +* `source_hash` - (Optional) Triggers updates like `etag` but useful to address `etag` encryption limitations. Set using `filemd5("path/to/source")` (Terraform 0.11.12 or later). (The value is only stored in state and not saved by AWS.) +* `source` - (Optional, conflicts with `content` and `content_base64`) Path to a file that will be read and uploaded as raw bytes for the object content. +* `storage_class` - (Optional) [Storage Class](http://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html) for the object. Can be either "`STANDARD`", "`REDUCED_REDUNDANCY`", "`ONEZONE_IA`", "`INTELLIGENT_TIERING`", "`GLACIER`", "`DEEP_ARCHIVE`", or "`STANDARD_IA`". Defaults to "`STANDARD`". +* `tags` - (Optional) Map of tags to assign to the object. 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. +* `website_redirect` - (Optional) Target URL for [website redirect](http://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-page-redirect.html). If no content is provided through `source`, `content` or `content_base64`, then the object will be empty. @@ -153,8 +151,7 @@ If no content is provided through `source`, `content` or `content_base64`, then In addition to all arguments above, the following attributes are exported: -* `id` - the `key` of the resource supplied above -* `etag` - the ETag generated for the object (an MD5 sum of the object content). For plaintext objects or objects encrypted with an AWS-managed key, the hash is an MD5 digest of the object data. For objects encrypted with a KMS key or objects created by either the Multipart Upload or Part Copy operation, the hash is not an MD5 digest, regardless of the method of encryption. More information on possible values can be found on [Common Response Headers](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html). -* `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). -* `version_id` - A unique version ID value for the object, if bucket versioning -is enabled. +* `etag` - ETag generated for the object (an MD5 sum of the object content). For plaintext objects or objects encrypted with an AWS-managed key, the hash is an MD5 digest of the object data. For objects encrypted with a KMS key or objects created by either the Multipart Upload or Part Copy operation, the hash is not an MD5 digest, regardless of the method of encryption. More information on possible values can be found on [Common Response Headers](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html). +* `id` - `key` of the resource supplied above +* `tags_all` - 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). +* `version_id` - Unique version ID value for the object, if bucket versioning is enabled. \ No newline at end of file From 76e6415a0d6ce2a247b236e8eb131a0fc7667d27 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 22:44:14 -0400 Subject: [PATCH 1167/1208] r/s3_bucket_object: Add changelog --- .changelog/11522.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/11522.txt diff --git a/.changelog/11522.txt b/.changelog/11522.txt new file mode 100644 index 000000000000..1eaade7f178a --- /dev/null +++ b/.changelog/11522.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_s3_bucket_object: Add `source_hash` argument to compliment `etag`'s encryption limitations +``` \ No newline at end of file From efc078e6fe0302b9df2a52fdd07e0a030fb6f012 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 12 Jul 2021 22:47:18 -0400 Subject: [PATCH 1168/1208] tests/r/s3_bucket_object: Add errorcheck --- aws/resource_aws_s3_bucket_object_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_s3_bucket_object_test.go b/aws/resource_aws_s3_bucket_object_test.go index 33fc74424fce..e7d2c0d6dae9 100644 --- a/aws/resource_aws_s3_bucket_object_test.go +++ b/aws/resource_aws_s3_bucket_object_test.go @@ -268,6 +268,7 @@ func TestAccAWSS3BucketObject_sourceHashTrigger(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, s3.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, Steps: []resource.TestStep{ From 35560820a22d7cb9f90b31d635afec2de97b943a Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 12 Jul 2021 22:36:52 -0700 Subject: [PATCH 1169/1208] Corrects Semgrep rule for `!d.IsNewResource()` check --- .semgrep.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.semgrep.yml b/.semgrep.yml index 575fc5949d21..45f0978901f4 100644 --- a/.semgrep.yml +++ b/.semgrep.yml @@ -348,7 +348,7 @@ rules: return nil } - pattern-not-inside: | - if <... d.IsNewResource() ...> { ... } + if <... !d.IsNewResource() ...> { ... } severity: WARNING - id: helper-schema-resource-Retry-without-TimeoutError-check From 4283c8a4c9f5e7589b422ec761c36eca25dd823b Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 12 Jul 2021 22:38:16 -0700 Subject: [PATCH 1170/1208] Addresses PR feedback --- .semgrep.yml | 12 +++++++++--- aws/internal/service/ec2/errors.go | 6 ++++++ aws/resource_aws_default_security_group.go | 15 +++++---------- ...e_aws_globalaccelerator_endpoint_group_test.go | 4 +--- aws/resource_aws_security_group.go | 11 ++++++----- aws/resource_aws_security_group_rule.go | 15 +++++++-------- 6 files changed, 34 insertions(+), 29 deletions(-) diff --git a/.semgrep.yml b/.semgrep.yml index 45f0978901f4..718408630adb 100644 --- a/.semgrep.yml +++ b/.semgrep.yml @@ -327,10 +327,16 @@ rules: - aws/resource_aws_athena_*.go - aws/resource_aws_autoscaling_*.go - aws/resource_aws_autoscalingplans_scaling_plan.go - - aws/resource_aws_[b-g]*.go + - aws/resource_aws_[b-ce-g]*.go + - aws/resource_aws_d[a-df-z]*.go + - aws/resource_aws_devicefarm*.go - aws/resource_aws_i*.go - - aws/resource_aws_[k-t]*.go - - aws/resource_aws_[v-x]*.go + - aws/resource_aws_[k-r]*.go + - aws/resource_aws_s[a-df-z3]*.go + - aws/resource_aws_se[d-z]*.go + - aws/resource_aws_sec[a-t]*.go + - aws/resource_aws_securityhub*.go + - aws/resource_aws_[t-x]*.go include: - aws/resource*.go patterns: diff --git a/aws/internal/service/ec2/errors.go b/aws/internal/service/ec2/errors.go index e4c94a554084..d7f9a9a110da 100644 --- a/aws/internal/service/ec2/errors.go +++ b/aws/internal/service/ec2/errors.go @@ -83,6 +83,12 @@ const ( InvalidVpnGatewayIDNotFound = "InvalidVpnGatewayID.NotFound" ) +const ( + ErrCodeInvalidPermissionDuplicate = "InvalidPermission.Duplicate" + ErrCodeInvalidPermissionMalformed = "InvalidPermission.Malformed" + ErrCodeInvalidPermissionNotFound = "InvalidPermission.NotFound" +) + func UnsuccessfulItemError(apiObject *ec2.UnsuccessfulItemError) error { if apiObject == nil { return nil diff --git a/aws/resource_aws_default_security_group.go b/aws/resource_aws_default_security_group.go index 97be5dc68d39..d08c0b858ba9 100644 --- a/aws/resource_aws_default_security_group.go +++ b/aws/resource_aws_default_security_group.go @@ -268,7 +268,7 @@ func resourceAwsDefaultSecurityGroupRead(d *schema.ResourceData, meta interface{ ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig group, err := finder.SecurityGroupByID(conn, d.Id()) - if tfresource.NotFound(err) { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] Security group (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -328,24 +328,19 @@ func resourceAwsDefaultSecurityGroupUpdate(d *schema.ResourceData, meta interfac conn := meta.(*AWSClient).ec2conn group, err := finder.SecurityGroupByID(conn, d.Id()) - if tfresource.NotFound(err) { - log.Printf("[WARN] Security group (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } if err != nil { - return err + return fmt.Errorf("error updating Default Security Group (%s): %w", d.Id(), err) } err = resourceAwsSecurityGroupUpdateRules(d, "ingress", meta, group) if err != nil { - return err + return fmt.Errorf("error updating Default Security Group (%s): %w", d.Id(), err) } if d.Get("vpc_id") != nil { err = resourceAwsSecurityGroupUpdateRules(d, "egress", meta, group) if err != nil { - return err + return fmt.Errorf("error updating Default Security Group (%s): %w", d.Id(), err) } } @@ -353,7 +348,7 @@ func resourceAwsDefaultSecurityGroupUpdate(d *schema.ResourceData, meta interfac o, n := d.GetChange("tags_all") if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating EC2 Security Group (%s) tags: %w", d.Id(), err) + return fmt.Errorf("error updating Default Security Group (%s) tags: %w", d.Id(), err) } } diff --git a/aws/resource_aws_globalaccelerator_endpoint_group_test.go b/aws/resource_aws_globalaccelerator_endpoint_group_test.go index aac2d49854bd..0c12f6646051 100644 --- a/aws/resource_aws_globalaccelerator_endpoint_group_test.go +++ b/aws/resource_aws_globalaccelerator_endpoint_group_test.go @@ -1,7 +1,6 @@ package aws import ( - "errors" "fmt" "regexp" "testing" @@ -472,8 +471,7 @@ func testAccCheckGlobalAcceleratorEndpointGroupDeleteGlobalAcceleratorSecurityGr conn := testAccProvider.Meta().(*AWSClient).ec2conn sg, err := ec2finder.SecurityGroupByNameAndVpcID(conn, "GlobalAccelerator", aws.StringValue(vpc.VpcId)) - var nfe *resource.NotFoundError - if errors.As(err, &nfe) { + if tfresource.NotFound(err) { // Already gone. return nil } diff --git a/aws/resource_aws_security_group.go b/aws/resource_aws_security_group.go index ffb90175518d..784f43dbf936 100644 --- a/aws/resource_aws_security_group.go +++ b/aws/resource_aws_security_group.go @@ -20,6 +20,7 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" + tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter" ) @@ -328,7 +329,7 @@ func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er if err != nil { //If we have a NotFound or InvalidParameterValue, then we are trying to remove the default IPv6 egress of a non-IPv6 //enabled SG - if !tfawserr.ErrCodeEquals(err, "InvalidPermission.NotFound") && !tfawserr.ErrMessageContains(err, "InvalidParameterValue", "remote-ipv6-range") { + if !tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidPermissionNotFound) && !tfawserr.ErrMessageContains(err, tfec2.ErrCodeInvalidParameterValue, "remote-ipv6-range") { return fmt.Errorf("Error revoking default IPv6 egress rule for Security Group (%s): %w", d.Id(), err) } } @@ -345,7 +346,7 @@ func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro sg, err := finder.SecurityGroupByID(conn, d.Id()) var nfe *resource.NotFoundError - if errors.As(err, &nfe) { + if !d.IsNewResource() && errors.As(err, &nfe) { log.Printf("[WARN] Security group (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -412,13 +413,13 @@ func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er err = resourceAwsSecurityGroupUpdateRules(d, "ingress", meta, group) if err != nil { - return err + return fmt.Errorf("error updating Security Group (%s): %w", d.Id(), err) } if d.Get("vpc_id") != nil { err = resourceAwsSecurityGroupUpdateRules(d, "egress", meta, group) if err != nil { - return err + return fmt.Errorf("error updating Security Group (%s): %w", d.Id(), err) } } @@ -426,7 +427,7 @@ func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er o, n := d.GetChange("tags_all") if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating EC2 Security Group (%s) tags: %w", d.Id(), err) + return fmt.Errorf("error updating Security Group (%s) tags: %w", d.Id(), err) } } diff --git a/aws/resource_aws_security_group_rule.go b/aws/resource_aws_security_group_rule.go index 7f3bfdf8c4d5..e6844c405bcd 100644 --- a/aws/resource_aws_security_group_rule.go +++ b/aws/resource_aws_security_group_rule.go @@ -16,6 +16,7 @@ import ( "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/hashcode" + tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -211,7 +212,7 @@ func resourceAwsSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{} return fmt.Errorf("Security Group Rule must be type 'ingress' or type 'egress'") } - if tfawserr.ErrCodeEquals(autherr, "InvalidPermission.Duplicate") { + if tfawserr.ErrCodeEquals(autherr, tfec2.ErrCodeInvalidPermissionDuplicate) { return fmt.Errorf(`[WARN] A duplicate Security Group rule was found on (%s). This may be a side effect of a now-fixed Terraform issue causing two security groups with identical attributes but different source_security_group_ids to overwrite each @@ -281,7 +282,7 @@ func resourceAwsSecurityGroupRuleRead(d *schema.ResourceData, meta interface{}) conn := meta.(*AWSClient).ec2conn sg_id := d.Get("security_group_id").(string) sg, err := finder.SecurityGroupByID(conn, sg_id) - if tfresource.NotFound(err) { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] Security Group (%s) not found, removing Rule (%s) from state", sg_id, d.Id()) d.SetId("") return nil @@ -308,18 +309,16 @@ func resourceAwsSecurityGroupRuleRead(d *schema.ResourceData, meta interface{}) return err } - if len(rules) == 0 { - log.Printf("[WARN] No %s rules were found for Security Group (%s) looking for Security Group Rule (%s)", - ruleType, *sg.GroupName, d.Id()) + if !d.IsNewResource() && len(rules) == 0 { + log.Printf("[WARN] No %s rules were found for Security Group (%s) looking for Security Group Rule (%s)", ruleType, aws.StringValue(sg.GroupName), d.Id()) d.SetId("") return nil } rule = findRuleMatch(p, rules, isVPC) - if rule == nil { - log.Printf("[DEBUG] Unable to find matching %s Security Group Rule (%s) for Group %s", - ruleType, d.Id(), sg_id) + if !d.IsNewResource() && rule == nil { + log.Printf("[DEBUG] Unable to find matching %s Security Group Rule (%s) for Group %s", ruleType, d.Id(), sg_id) d.SetId("") return nil } From e40cebfc75c8c82560d172ae1c2dade8036541fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 06:06:03 +0000 Subject: [PATCH 1171/1208] build(deps): bump integrations/github in /infrastructure/repository Bumps [integrations/github](https://github.com/integrations/terraform-provider-github) from 4.12.1 to 4.12.2. - [Release notes](https://github.com/integrations/terraform-provider-github/releases) - [Changelog](https://github.com/integrations/terraform-provider-github/blob/main/CHANGELOG.md) - [Commits](https://github.com/integrations/terraform-provider-github/compare/v4.12.1...v4.12.2) --- updated-dependencies: - dependency-name: integrations/github dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- infrastructure/repository/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/repository/main.tf b/infrastructure/repository/main.tf index d10b66d74711..f56369482785 100644 --- a/infrastructure/repository/main.tf +++ b/infrastructure/repository/main.tf @@ -10,7 +10,7 @@ terraform { required_providers { github = { source = "integrations/github" - version = "4.12.1" + version = "4.12.2" } } From 832a220ae144d4ae7077356cb173c4cefed3dc14 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 06:09:53 +0000 Subject: [PATCH 1172/1208] build(deps): bump github.com/aws/aws-sdk-go from 1.39.4 to 1.39.5 Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.39.4 to 1.39.5. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.39.4...v1.39.5) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 13234f81e5e3..b5a2ef936f56 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect - github.com/aws/aws-sdk-go v1.39.4 + github.com/aws/aws-sdk-go v1.39.5 github.com/beevik/etree v1.1.0 github.com/fatih/color v1.9.0 // indirect github.com/hashicorp/aws-sdk-go-base v0.7.1 diff --git a/go.sum b/go.sum index fc92a009e9de..4ae44b94f009 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.39.4 h1:nXBChUaG5cinrl3yg4/rUyssOOLH/ohk4S9K03kJirE= -github.com/aws/aws-sdk-go v1.39.4/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go v1.39.5 h1:yoJEE1NJxbpZ3CtPxvOSFJ9ByxiXmBTKk8J+XU5ldtg= +github.com/aws/aws-sdk-go v1.39.5/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= From 922b885e0aa65d45ff4ef96866eedbe880b7b8b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 06:10:38 +0000 Subject: [PATCH 1173/1208] build(deps): bump github.com/aws/aws-sdk-go in /awsproviderlint Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.39.4 to 1.39.5. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.39.4...v1.39.5) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- awsproviderlint/go.mod | 2 +- awsproviderlint/go.sum | 4 ++-- .../github.com/aws/aws-sdk-go/aws/endpoints/defaults.go | 2 ++ .../vendor/github.com/aws/aws-sdk-go/aws/version.go | 2 +- awsproviderlint/vendor/modules.txt | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/awsproviderlint/go.mod b/awsproviderlint/go.mod index 1a77c9b93d8e..060ecbee7f50 100644 --- a/awsproviderlint/go.mod +++ b/awsproviderlint/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-aws/awsproviderlint go 1.16 require ( - github.com/aws/aws-sdk-go v1.39.4 + github.com/aws/aws-sdk-go v1.39.5 github.com/bflad/tfproviderlint v0.27.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb diff --git a/awsproviderlint/go.sum b/awsproviderlint/go.sum index b9de0de284d7..58a3527e6860 100644 --- a/awsproviderlint/go.sum +++ b/awsproviderlint/go.sum @@ -70,8 +70,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.39.4 h1:nXBChUaG5cinrl3yg4/rUyssOOLH/ohk4S9K03kJirE= -github.com/aws/aws-sdk-go v1.39.4/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go v1.39.5 h1:yoJEE1NJxbpZ3CtPxvOSFJ9ByxiXmBTKk8J+XU5ldtg= +github.com/aws/aws-sdk-go v1.39.5/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= github.com/bflad/gopaniccheck v0.1.0/go.mod h1:ZCj2vSr7EqVeDaqVsWN4n2MwdROx1YL+LFo47TSWtsA= github.com/bflad/tfproviderlint v0.27.0 h1:KXF+dYaWJ/OSVyWIrk2NIYgQBMDDSOC4VQB/P+P5nhI= diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go index 60ff236dfd52..2dcc49e7fda0 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go @@ -3582,6 +3582,8 @@ var awsPartition = partition{ }, Endpoints: endpoints{ "us-east-1": endpoint{}, + "us-east-2": endpoint{}, + "us-west-2": endpoint{}, }, }, "honeycode": service{ diff --git a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go index 8b253ba02b18..f148c09d942d 100644 --- a/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go +++ b/awsproviderlint/vendor/github.com/aws/aws-sdk-go/aws/version.go @@ -5,4 +5,4 @@ package aws const SDKName = "aws-sdk-go" // SDKVersion is the version of this SDK -const SDKVersion = "1.39.4" +const SDKVersion = "1.39.5" diff --git a/awsproviderlint/vendor/modules.txt b/awsproviderlint/vendor/modules.txt index a9d77a9d5ef9..ec3c23fb3779 100644 --- a/awsproviderlint/vendor/modules.txt +++ b/awsproviderlint/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/agext/levenshtein github.com/apparentlymart/go-textseg/v12/textseg # github.com/apparentlymart/go-textseg/v13 v13.0.0 github.com/apparentlymart/go-textseg/v13/textseg -# github.com/aws/aws-sdk-go v1.39.4 +# github.com/aws/aws-sdk-go v1.39.5 ## explicit github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn From 4f9b9cb397158cf0a7e377d406cde56414985c8d Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 13 Jul 2021 12:55:57 +0000 Subject: [PATCH 1174/1208] Update CHANGELOG.md for #20159 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5069ee03df0..bc5478f213a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ ENHANCEMENTS: * resource/aws_guardduty_organization_configuration: Add `datasources` argument ([#15241](https://github.com/hashicorp/terraform-provider-aws/issues/15241)) * resource/aws_iam_access_key: Add encrypted SES SMTP password ([#19579](https://github.com/hashicorp/terraform-provider-aws/issues/19579)) * resource/aws_s3_bucket: Add the delete_marker_replication_status argument for V2 replication configurations ([#19323](https://github.com/hashicorp/terraform-provider-aws/issues/19323)) +* resource/aws_s3_bucket_object: Add `source_hash` argument to compliment `etag`'s encryption limitations ([#11522](https://github.com/hashicorp/terraform-provider-aws/issues/11522)) +* resource/aws_wafv2_web_acl: Support `scope_down_statement` on `managed_rule_group_statement` ([#19407](https://github.com/hashicorp/terraform-provider-aws/issues/19407)) BUG FIXES: From 48d2e61e1c6f2f876f4ad3fa17953e144f960bc9 Mon Sep 17 00:00:00 2001 From: Andrew Babichev Date: Tue, 29 Sep 2020 21:36:01 +0300 Subject: [PATCH 1175/1208] New resource: aws_securityhub_standards_control --- aws/provider.go | 1 + ...ource_aws_securityhub_standards_control.go | 139 ++++++++++++++++ ..._aws_securityhub_standards_control_test.go | 154 ++++++++++++++++++ ...securityhub_standards_subscription_test.go | 14 +- .../r/securityhub_standards_control.markdown | 54 ++++++ 5 files changed, 356 insertions(+), 6 deletions(-) create mode 100644 aws/resource_aws_securityhub_standards_control.go create mode 100644 aws/resource_aws_securityhub_standards_control_test.go create mode 100644 website/docs/r/securityhub_standards_control.markdown diff --git a/aws/provider.go b/aws/provider.go index bd2642be4db3..60169a08e5b3 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1056,6 +1056,7 @@ func Provider() *schema.Provider { "aws_securityhub_member": resourceAwsSecurityHubMember(), "aws_securityhub_organization_admin_account": resourceAwsSecurityHubOrganizationAdminAccount(), "aws_securityhub_product_subscription": resourceAwsSecurityHubProductSubscription(), + "aws_securityhub_standards_control": resourceAwsSecurityHubStandardsControl(), "aws_securityhub_standards_subscription": resourceAwsSecurityHubStandardsSubscription(), "aws_servicecatalog_budget_resource_association": resourceAwsServiceCatalogBudgetResourceAssociation(), "aws_servicecatalog_constraint": resourceAwsServiceCatalogConstraint(), diff --git a/aws/resource_aws_securityhub_standards_control.go b/aws/resource_aws_securityhub_standards_control.go new file mode 100644 index 000000000000..c49bbfd49ff9 --- /dev/null +++ b/aws/resource_aws_securityhub_standards_control.go @@ -0,0 +1,139 @@ +package aws + +import ( + "context" + "log" + "path" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/securityhub" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceAwsSecurityHubStandardsControl() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceAwsSecurityHubStandardsControlPut, + ReadContext: resourceAwsSecurityHubStandardsControlRead, + UpdateContext: resourceAwsSecurityHubStandardsControlPut, + DeleteContext: resourceAwsSecurityHubStandardsControlDelete, + + Schema: map[string]*schema.Schema{ + "standards_control_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateArn, + }, + "control_status": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(securityhub.ControlStatus_Values(), false), + }, + "disabled_reason": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "control_id": { + Type: schema.TypeString, + Computed: true, + }, + "control_status_updated_at": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "related_requirements": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "remediation_url": { + Type: schema.TypeString, + Computed: true, + }, + "severity_rating": { + Type: schema.TypeString, + Computed: true, + }, + "title": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsSecurityHubStandardsControlRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).securityhubconn + + a := d.Get("standards_control_arn").(string) + controlArn, err := arn.Parse(a) + if err != nil { + return diag.Errorf("error parsing standards control ARN %q", controlArn) + } + + subscriptionArn := path.Dir(strings.ReplaceAll(controlArn.String(), "control", "subscription")) + + log.Printf("[DEBUG] Read Security Hub standard control %s", controlArn) + + resp, err := conn.DescribeStandardsControls(&securityhub.DescribeStandardsControlsInput{ + StandardsSubscriptionArn: aws.String(subscriptionArn), + }) + if err != nil { + return diag.Errorf("error reading Security Hub standard controls within %q subscription: %s", subscriptionArn, err) + } + + for _, c := range resp.Controls { + if aws.StringValue(c.StandardsControlArn) != controlArn.String() { + continue + } + + d.Set("control_status", c.ControlStatus) + d.Set("control_status_updated_at", c.ControlStatusUpdatedAt.Format(time.RFC3339)) + d.Set("description", c.Description) + d.Set("disabled_reason", c.DisabledReason) + d.Set("severity_rating", c.SeverityRating) + d.Set("title", c.Title) + + if err := d.Set("related_requirements", flattenStringList(c.RelatedRequirements)); err != nil { + return diag.Errorf("error setting related_requirements: %s", err) + } + } + + return nil +} + +func resourceAwsSecurityHubStandardsControlPut(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).securityhubconn + + d.SetId(d.Get("standards_control_arn").(string)) + + log.Printf("[DEBUG] Update Security Hub standard control %s", d.Id()) + + _, err := conn.UpdateStandardsControl(&securityhub.UpdateStandardsControlInput{ + StandardsControlArn: aws.String(d.Get("standards_control_arn").(string)), + ControlStatus: aws.String(d.Get("control_status").(string)), + DisabledReason: aws.String(d.Get("disabled_reason").(string)), + }) + if err != nil { + d.SetId("") + return diag.Errorf("error updating Security Hub standard control %q: %s", d.Id(), err) + } + + return resourceAwsSecurityHubStandardsControlRead(ctx, d, meta) +} + +func resourceAwsSecurityHubStandardsControlDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + log.Printf("[WARN] Cannot delete Security Hub standard control. Terraform will remove this resource from the state.") + return nil +} diff --git a/aws/resource_aws_securityhub_standards_control_test.go b/aws/resource_aws_securityhub_standards_control_test.go new file mode 100644 index 000000000000..4f943abc9931 --- /dev/null +++ b/aws/resource_aws_securityhub_standards_control_test.go @@ -0,0 +1,154 @@ +package aws + +import ( + "fmt" + "path" + "regexp" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/securityhub" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccAWSSecurityHubStandardsControl_basic(t *testing.T) { + var standardsControl *securityhub.StandardsControl + + resourceName := "aws_securityhub_standards_control.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), + Steps: []resource.TestStep{ + { + Config: testAccAWSSecurityHubStandardsControlConfig_basic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), + resource.TestCheckResourceAttr(resourceName, "control_status", "ENABLED"), + resource.TestMatchResourceAttr(resourceName, "control_status_updated_at", regexp.MustCompile(`\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)), + resource.TestCheckResourceAttr(resourceName, "description", "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords."), + resource.TestCheckResourceAttr(resourceName, "disabled_reason", ""), + resource.TestCheckResourceAttr(resourceName, "related_requirements.0", "CIS AWS Foundations 1.10"), + resource.TestCheckResourceAttr(resourceName, "severity_rating", "LOW"), + resource.TestCheckResourceAttr(resourceName, "title", "Ensure IAM password policy prevents password reuse"), + ), + }, + }, + }) +} + +func TestAccAWSSecurityHubStandardsControl_disabledControlStatus(t *testing.T) { + var standardsControl *securityhub.StandardsControl + + resourceName := "aws_securityhub_standards_control.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), + Steps: []resource.TestStep{ + { + Config: testAccAWSSecurityHubStandardsControlConfig_disabledControlStatus(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), + resource.TestCheckResourceAttr(resourceName, "control_status", "DISABLED"), + resource.TestCheckResourceAttr(resourceName, "disabled_reason", "We handle password policies within Okta"), + ), + }, + }, + }) +} + +func TestAccAWSSecurityHubStandardsControl_enabledControlStatusAndDisabledReason(t *testing.T) { + var standardsControl *securityhub.StandardsControl + + resourceName := "aws_securityhub_standards_control.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), + Steps: []resource.TestStep{ + { + Config: testAccAWSSecurityHubStandardsControlConfig_enabledControlStatus(), + ExpectError: regexp.MustCompile("InvalidInputException: DisabledReason should not be given for action other than disabling control"), + }, + }, + }) +} + +func testAccCheckAWSSecurityHubStandardsControlExists(n string, control *securityhub.StandardsControl) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := testAccProvider.Meta().(*AWSClient).securityhubconn + + arn := rs.Primary.ID + subscription_arn := path.Dir(strings.ReplaceAll(arn, "control", "subscription")) + + resp, err := conn.DescribeStandardsControls(&securityhub.DescribeStandardsControlsInput{ + StandardsSubscriptionArn: aws.String(subscription_arn), + }) + if err != nil { + return fmt.Errorf("error reading Security Hub %s standard controls: %s", subscription_arn, err) + } + + controlNotFound := true + + for _, c := range resp.Controls { + if aws.StringValue(c.StandardsControlArn) != arn { + continue + } + + controlNotFound = false + control = c + } + + if controlNotFound { + return fmt.Errorf("Security Hub %s standard control %s not found", subscription_arn, arn) + } + + return nil + } +} + +func testAccAWSSecurityHubStandardsControlConfig_basic() string { + return composeConfig( + testAccAWSSecurityHubStandardsSubscriptionConfig_basic, + ` +resource aws_securityhub_standards_control test { + standards_control_arn = format("%s/1.10", replace(aws_securityhub_standards_subscription.test.id, "subscription", "control")) + control_status = "ENABLED" +} +`) +} + +func testAccAWSSecurityHubStandardsControlConfig_disabledControlStatus() string { + return composeConfig( + testAccAWSSecurityHubStandardsSubscriptionConfig_basic, + ` +resource aws_securityhub_standards_control test { + standards_control_arn = format("%s/1.11", replace(aws_securityhub_standards_subscription.test.id, "subscription", "control")) + control_status = "DISABLED" + disabled_reason = "We handle password policies within Okta" +} +`) +} + +func testAccAWSSecurityHubStandardsControlConfig_enabledControlStatus() string { + return composeConfig( + testAccAWSSecurityHubStandardsSubscriptionConfig_basic, + ` +resource aws_securityhub_standards_control test { + standards_control_arn = format("%s/1.12", replace(aws_securityhub_standards_subscription.test.id, "subscription", "control")) + control_status = "ENABLED" + disabled_reason = "We handle password policies within Okta" +} +`) +} diff --git a/aws/resource_aws_securityhub_standards_subscription_test.go b/aws/resource_aws_securityhub_standards_subscription_test.go index f05b8f5a6791..0e3bb4b56688 100644 --- a/aws/resource_aws_securityhub_standards_subscription_test.go +++ b/aws/resource_aws_securityhub_standards_subscription_test.go @@ -13,6 +13,8 @@ import ( func testAccAWSSecurityHubStandardsSubscription_basic(t *testing.T) { var standardsSubscription *securityhub.StandardsSubscription + resourceName := "aws_securityhub_standards_subscription.test" + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), @@ -22,11 +24,11 @@ func testAccAWSSecurityHubStandardsSubscription_basic(t *testing.T) { { Config: testAccAWSSecurityHubStandardsSubscriptionConfig_basic, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSecurityHubStandardsSubscriptionExists("aws_securityhub_standards_subscription.example", standardsSubscription), + testAccCheckAWSSecurityHubStandardsSubscriptionExists(resourceName, standardsSubscription), ), }, { - ResourceName: "aws_securityhub_standards_subscription.example", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -95,16 +97,16 @@ func testAccCheckAWSSecurityHubStandardsSubscriptionDestroy(s *terraform.State) } const testAccAWSSecurityHubStandardsSubscriptionConfig_empty = ` -resource "aws_securityhub_account" "example" {} +resource "aws_securityhub_account" "test" {} ` const testAccAWSSecurityHubStandardsSubscriptionConfig_basic = ` -resource "aws_securityhub_account" "example" {} +resource "aws_securityhub_account" "test" {} data "aws_partition" "current" {} -resource "aws_securityhub_standards_subscription" "example" { - depends_on = [aws_securityhub_account.example] +resource "aws_securityhub_standards_subscription" "test" { standards_arn = "arn:${data.aws_partition.current.partition}:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0" + depends_on = [aws_securityhub_account.test] } ` diff --git a/website/docs/r/securityhub_standards_control.markdown b/website/docs/r/securityhub_standards_control.markdown new file mode 100644 index 000000000000..e5b90dc78602 --- /dev/null +++ b/website/docs/r/securityhub_standards_control.markdown @@ -0,0 +1,54 @@ +--- +subcategory: "Security Hub" +layout: "aws" +page_title: "AWS: aws_securityhub_standards_control" +description: |- + Enable/disable Security Hub standards controls. +--- + +# Resource: aws_securityhub_standards_control + +Disable/enable Security Hub standards control in the current region. + +The `aws_securityhub_standards_control` behaves differently from normal resources, in that +Terraform does not _create_ this resource, but instead "adopts" it +into management. When you _delete_ this resource configuration, Terraform "abandons" resource as is and just removes it from the state. + +## Example Usage + +```hcl +resource aws_securityhub_account example {} + +resource aws_securityhub_standards_subscription cis_aws_foundations_benchmark { + standards_arn = "arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0" + depends_on = [aws_securityhub_account.example] +} + +resource aws_securityhub_standards_control ensure_iam_password_policy_prevents_password_reuse { + arn = "arn:aws:securityhub:us-east-1:111111111111:control/cis-aws-foundations-benchmark/v/1.2.0/1.10" + control_status = "DISABLED" + disabled_reason = "We handle password policies within Okta" + depends_on = [aws_securityhub_standards_subscription.cis_aws_foundations_benchmark] +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `standards_control_arn` - (Required) The standards control ARN. +* `control_status` – (Required) The control status could be `ENABLED` or `DISABLED`. You have to specify `disabled_reason` argument for `DISABLED` control status. +* `disabled_reason` – (Optional) A description of the reason why you are disabling a security standard control. If you specify this attribute, `control_status` will be set to `DISABLED` automatically. + +## Attributes Reference + +The following attributes are exported in addition to the arguments listed above: + +* `id` - The standard control ARN. +* `control_id` – The identifier of the security standard control. +* `control_status_updated_at` – The date and time that the status of the security standard control was most recently updated. +* `description` – The standard control longer description. Provides information about what the control is checking for. +* `related_requirements` – The list of requirements that are related to this control. +* `remediation_url` – A link to remediation information for the control in the Security Hub user documentation. +* `severity_rating` – The severity of findings generated from this security standard control. +* `title` – The standard control title. From 5899f97e78cc92cf2875bf82aa4985bb0e0ee0da Mon Sep 17 00:00:00 2001 From: Andrew Babichev Date: Mon, 9 Nov 2020 23:15:26 +0200 Subject: [PATCH 1176/1208] Gratify impi --- aws/resource_aws_securityhub_standards_control.go | 1 - 1 file changed, 1 deletion(-) diff --git a/aws/resource_aws_securityhub_standards_control.go b/aws/resource_aws_securityhub_standards_control.go index c49bbfd49ff9..be5d817eb11d 100644 --- a/aws/resource_aws_securityhub_standards_control.go +++ b/aws/resource_aws_securityhub_standards_control.go @@ -10,7 +10,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/securityhub" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" From bd64f13fd3924263bee1391fc1c04b59f4fbdd25 Mon Sep 17 00:00:00 2001 From: Andrew Babichev Date: Wed, 19 May 2021 17:24:15 +0300 Subject: [PATCH 1177/1208] Add ErrorCheck --- aws/resource_aws_securityhub_standards_control_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aws/resource_aws_securityhub_standards_control_test.go b/aws/resource_aws_securityhub_standards_control_test.go index 4f943abc9931..24535392f62a 100644 --- a/aws/resource_aws_securityhub_standards_control_test.go +++ b/aws/resource_aws_securityhub_standards_control_test.go @@ -20,6 +20,7 @@ func TestAccAWSSecurityHubStandardsControl_basic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), Steps: []resource.TestStep{ @@ -47,6 +48,7 @@ func TestAccAWSSecurityHubStandardsControl_disabledControlStatus(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), Steps: []resource.TestStep{ @@ -69,6 +71,7 @@ func TestAccAWSSecurityHubStandardsControl_enabledControlStatusAndDisabledReason resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), Steps: []resource.TestStep{ From f8c8a95c47decd23ff4a8181064c66129da10230 Mon Sep 17 00:00:00 2001 From: Andrew Babichev Date: Wed, 19 May 2021 17:24:24 +0300 Subject: [PATCH 1178/1208] Fix doc with ```terraform --- website/docs/r/securityhub_standards_control.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/securityhub_standards_control.markdown b/website/docs/r/securityhub_standards_control.markdown index e5b90dc78602..f0065775336b 100644 --- a/website/docs/r/securityhub_standards_control.markdown +++ b/website/docs/r/securityhub_standards_control.markdown @@ -16,7 +16,7 @@ into management. When you _delete_ this resource configuration, Terraform "aband ## Example Usage -```hcl +```terraform resource aws_securityhub_account example {} resource aws_securityhub_standards_subscription cis_aws_foundations_benchmark { From 246c64b408ada50d8118ea6c4c5529d1eebd9d55 Mon Sep 17 00:00:00 2001 From: Andrew Babichev Date: Wed, 19 May 2021 17:42:37 +0300 Subject: [PATCH 1179/1208] Fix to "Argument Reference" --- website/docs/r/securityhub_standards_control.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/securityhub_standards_control.markdown b/website/docs/r/securityhub_standards_control.markdown index f0065775336b..4af7879e56c0 100644 --- a/website/docs/r/securityhub_standards_control.markdown +++ b/website/docs/r/securityhub_standards_control.markdown @@ -32,7 +32,7 @@ resource aws_securityhub_standards_control ensure_iam_password_policy_prevents_p } ``` -## Arguments Reference +## Argument Reference The following arguments are supported: From 7c28583dd3154bda0fe0ee01382accb9349d1ada Mon Sep 17 00:00:00 2001 From: Andrew Babichev Date: Wed, 19 May 2021 17:56:42 +0300 Subject: [PATCH 1180/1208] Fix to "In addition to all arguments above, the following attributes are exported" --- website/docs/r/securityhub_standards_control.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/securityhub_standards_control.markdown b/website/docs/r/securityhub_standards_control.markdown index 4af7879e56c0..54effa683361 100644 --- a/website/docs/r/securityhub_standards_control.markdown +++ b/website/docs/r/securityhub_standards_control.markdown @@ -42,7 +42,7 @@ The following arguments are supported: ## Attributes Reference -The following attributes are exported in addition to the arguments listed above: +In addition to all arguments above, the following attributes are exported: * `id` - The standard control ARN. * `control_id` – The identifier of the security standard control. From c578a7978176bb9004059ba424de565a0915cc43 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 13 Jul 2021 09:28:04 -0400 Subject: [PATCH 1181/1208] Add CHANGELOG entry. --- .changelog/14714.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/14714.txt diff --git a/.changelog/14714.txt b/.changelog/14714.txt new file mode 100644 index 000000000000..bf5967390590 --- /dev/null +++ b/.changelog/14714.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_securityhub_standards_control +``` \ No newline at end of file From b7f2d94c00a7745ba62f94946e93429ff0f23ffb Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 13 Jul 2021 09:39:48 -0400 Subject: [PATCH 1182/1208] Correct argument name in example. --- website/docs/r/securityhub_standards_control.markdown | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/website/docs/r/securityhub_standards_control.markdown b/website/docs/r/securityhub_standards_control.markdown index 54effa683361..38388c87a698 100644 --- a/website/docs/r/securityhub_standards_control.markdown +++ b/website/docs/r/securityhub_standards_control.markdown @@ -25,10 +25,11 @@ resource aws_securityhub_standards_subscription cis_aws_foundations_benchmark { } resource aws_securityhub_standards_control ensure_iam_password_policy_prevents_password_reuse { - arn = "arn:aws:securityhub:us-east-1:111111111111:control/cis-aws-foundations-benchmark/v/1.2.0/1.10" - control_status = "DISABLED" - disabled_reason = "We handle password policies within Okta" - depends_on = [aws_securityhub_standards_subscription.cis_aws_foundations_benchmark] + standards_control_arn = "arn:aws:securityhub:us-east-1:111111111111:control/cis-aws-foundations-benchmark/v/1.2.0/1.10" + control_status = "DISABLED" + disabled_reason = "We handle password policies within Okta" + + depends_on = [aws_securityhub_standards_subscription.cis_aws_foundations_benchmark] } ``` From 48cb7198f2ef0e4debe411673c970bbe6b34ad5c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 13 Jul 2021 12:17:02 -0400 Subject: [PATCH 1183/1208] aws_securityhub_standards_control: Use internal finder package and serialize tests. --- aws/internal/service/securityhub/arn.go | 44 ++++++++ aws/internal/service/securityhub/arn_test.go | 65 +++++++++++ .../service/securityhub/finder/finder.go | 81 ++++++++++++++ .../service/securityhub/waiter/status.go | 21 ++++ .../service/securityhub/waiter/waiter.go | 37 +++++++ ...ource_aws_securityhub_standards_control.go | 103 +++++++++--------- ..._aws_securityhub_standards_control_test.go | 78 ++++++------- ..._aws_securityhub_standards_subscription.go | 54 +++++---- ...securityhub_standards_subscription_test.go | 61 ++++++----- aws/resource_aws_securityhub_test.go | 8 +- 10 files changed, 408 insertions(+), 144 deletions(-) create mode 100644 aws/internal/service/securityhub/arn.go create mode 100644 aws/internal/service/securityhub/arn_test.go diff --git a/aws/internal/service/securityhub/arn.go b/aws/internal/service/securityhub/arn.go new file mode 100644 index 000000000000..105541e3021d --- /dev/null +++ b/aws/internal/service/securityhub/arn.go @@ -0,0 +1,44 @@ +package securityhub + +import ( + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/aws/arn" +) + +const ( + ARNSeparator = "/" + ARNService = "securityhub" +) + +// StandardsControlARNToStandardsSubscriptionARN converts a security standard control ARN to a subscription ARN. +func StandardsControlARNToStandardsSubscriptionARN(inputARN string) (string, error) { + parsedARN, err := arn.Parse(inputARN) + + if err != nil { + return "", fmt.Errorf("error parsing ARN (%s): %w", inputARN, err) + } + + if actual, expected := parsedARN.Service, ARNService; actual != expected { + return "", fmt.Errorf("expected service %s in ARN (%s), got: %s", expected, inputARN, actual) + } + + inputResourceParts := strings.Split(parsedARN.Resource, ARNSeparator) + + if actual, expected := len(inputResourceParts), 3; actual < expected { + return "", fmt.Errorf("expected at least %d resource parts in ARN (%s), got: %d", expected, inputARN, actual) + } + + outputResourceParts := append([]string{"subscription"}, inputResourceParts[1:len(inputResourceParts)-1]...) + + outputARN := arn.ARN{ + Partition: parsedARN.Partition, + Service: parsedARN.Service, + Region: parsedARN.Region, + AccountID: parsedARN.AccountID, + Resource: strings.Join(outputResourceParts, ARNSeparator), + }.String() + + return outputARN, nil +} diff --git a/aws/internal/service/securityhub/arn_test.go b/aws/internal/service/securityhub/arn_test.go new file mode 100644 index 000000000000..76a9e61994bc --- /dev/null +++ b/aws/internal/service/securityhub/arn_test.go @@ -0,0 +1,65 @@ +package securityhub_test + +import ( + "regexp" + "testing" + + tfsecurityhub "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/securityhub" +) + +func TestStandardsControlARNToStandardsSubscriptionARN(t *testing.T) { + testCases := []struct { + TestName string + InputARN string + ExpectedError *regexp.Regexp + ExpectedARN string + }{ + { + TestName: "empty ARN", + InputARN: "", + ExpectedError: regexp.MustCompile(`error parsing ARN`), + }, + { + TestName: "unparsable ARN", + InputARN: "test", + ExpectedError: regexp.MustCompile(`error parsing ARN`), + }, + { + TestName: "invalid ARN service", + InputARN: "arn:aws:ec2:us-west-2:1234567890:control/cis-aws-foundations-benchmark/v/1.2.0/1.1", + ExpectedError: regexp.MustCompile(`expected service securityhub`), + }, + { + TestName: "invalid ARN resource parts", + InputARN: "arn:aws:securityhub:us-west-2:1234567890:control/cis-aws-foundations-benchmark", + ExpectedError: regexp.MustCompile(`expected at least 3 resource parts`), + }, + { + TestName: "valid ARN", + InputARN: "arn:aws:securityhub:us-west-2:1234567890:control/cis-aws-foundations-benchmark/v/1.2.0/1.1", + ExpectedARN: "arn:aws:securityhub:us-west-2:1234567890:subscription/cis-aws-foundations-benchmark/v/1.2.0", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.TestName, func(t *testing.T) { + got, err := tfsecurityhub.StandardsControlARNToStandardsSubscriptionARN(testCase.InputARN) + + if err == nil && testCase.ExpectedError != nil { + t.Fatalf("expected error %s, got no error", testCase.ExpectedError.String()) + } + + if err != nil && testCase.ExpectedError == nil { + t.Fatalf("got unexpected error: %s", err) + } + + if err != nil && !testCase.ExpectedError.MatchString(err.Error()) { + t.Fatalf("expected error %s, got: %s", testCase.ExpectedError.String(), err) + } + + if got != testCase.ExpectedARN { + t.Errorf("got %s, expected %s", got, testCase.ExpectedARN) + } + }) + } +} diff --git a/aws/internal/service/securityhub/finder/finder.go b/aws/internal/service/securityhub/finder/finder.go index ecb245bb2ad3..4b99b707f1ca 100644 --- a/aws/internal/service/securityhub/finder/finder.go +++ b/aws/internal/service/securityhub/finder/finder.go @@ -5,6 +5,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/securityhub" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func AdminAccount(conn *securityhub.SecurityHub, adminAccountID string) (*securityhub.AdminAccount, error) { @@ -51,3 +53,82 @@ func Insight(ctx context.Context, conn *securityhub.SecurityHub, arn string) (*s return output.Insights[0], nil } + +func StandardsControlByStandardsSubscriptionARNAndStandardsControlARN(ctx context.Context, conn *securityhub.SecurityHub, standardsSubscriptionARN, standardsControlARN string) (*securityhub.StandardsControl, error) { + input := &securityhub.DescribeStandardsControlsInput{ + StandardsSubscriptionArn: aws.String(standardsSubscriptionARN), + } + var output *securityhub.StandardsControl + + err := conn.DescribeStandardsControlsPagesWithContext(ctx, input, func(page *securityhub.DescribeStandardsControlsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, control := range page.Controls { + if aws.StringValue(control.StandardsControlArn) == standardsControlARN { + output = control + + return false + } + } + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, securityhub.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output, nil +} + +func StandardsSubscriptionByARN(conn *securityhub.SecurityHub, arn string) (*securityhub.StandardsSubscription, error) { + input := &securityhub.GetEnabledStandardsInput{ + StandardsSubscriptionArns: aws.StringSlice([]string{arn}), + } + + output, err := conn.GetEnabledStandards(input) + + if tfawserr.ErrCodeEquals(err, securityhub.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if output == nil || len(output.StandardsSubscriptions) == 0 || output.StandardsSubscriptions[0] == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + // TODO Check for multiple results. + // TODO https://github.com/hashicorp/terraform-provider-aws/pull/17613. + + subscription := output.StandardsSubscriptions[0] + + if status := aws.StringValue(subscription.StandardsStatus); status == securityhub.StandardsStatusFailed { + return nil, &resource.NotFoundError{ + Message: status, + LastRequest: input, + } + } + + return subscription, nil +} diff --git a/aws/internal/service/securityhub/waiter/status.go b/aws/internal/service/securityhub/waiter/status.go index 6ab9c3360041..d377ec257b37 100644 --- a/aws/internal/service/securityhub/waiter/status.go +++ b/aws/internal/service/securityhub/waiter/status.go @@ -5,6 +5,7 @@ import ( "github.com/aws/aws-sdk-go/service/securityhub" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/securityhub/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( @@ -13,6 +14,8 @@ const ( // AdminStatus Unknown AdminStatusUnknown = "Unknown" + + StandardsStatusNotFound = "NotFound" ) // AdminAccountAdminStatus fetches the AdminAccount and its AdminStatus @@ -31,3 +34,21 @@ func AdminAccountAdminStatus(conn *securityhub.SecurityHub, adminAccountID strin return adminAccount, aws.StringValue(adminAccount.Status), nil } } + +func StandardsSubscriptionStatus(conn *securityhub.SecurityHub, arn string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.StandardsSubscriptionByARN(conn, arn) + + if tfresource.NotFound(err) { + // Return a fake result and status to deal with the INCOMPLETE subscription status + // being a target for both Create and Delete. + return "", StandardsStatusNotFound, nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.StandardsStatus), nil + } +} diff --git a/aws/internal/service/securityhub/waiter/waiter.go b/aws/internal/service/securityhub/waiter/waiter.go index deac42a90912..d91080fcfb03 100644 --- a/aws/internal/service/securityhub/waiter/waiter.go +++ b/aws/internal/service/securityhub/waiter/waiter.go @@ -13,6 +13,9 @@ const ( // Maximum amount of time to wait for an AdminAccount to return NotFound AdminAccountNotFoundTimeout = 5 * time.Minute + + StandardsSubscriptionCreateTimeout = 3 * time.Minute + StandardsSubscriptionDeleteTimeout = 3 * time.Minute ) // AdminAccountEnabled waits for an AdminAccount to return Enabled @@ -50,3 +53,37 @@ func AdminAccountNotFound(conn *securityhub.SecurityHub, adminAccountID string) return nil, err } + +func StandardsSubscriptionCreated(conn *securityhub.SecurityHub, arn string) (*securityhub.StandardsSubscription, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{securityhub.StandardsStatusPending}, + Target: []string{securityhub.StandardsStatusReady, securityhub.StandardsStatusIncomplete}, + Refresh: StandardsSubscriptionStatus(conn, arn), + Timeout: StandardsSubscriptionCreateTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*securityhub.StandardsSubscription); ok { + return output, err + } + + return nil, err +} + +func StandardsSubscriptionDeleted(conn *securityhub.SecurityHub, arn string) (*securityhub.StandardsSubscription, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{securityhub.StandardsStatusDeleting}, + Target: []string{StandardsStatusNotFound, securityhub.StandardsStatusIncomplete}, + Refresh: StandardsSubscriptionStatus(conn, arn), + Timeout: StandardsSubscriptionDeleteTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*securityhub.StandardsSubscription); ok { + return output, err + } + + return nil, err +} diff --git a/aws/resource_aws_securityhub_standards_control.go b/aws/resource_aws_securityhub_standards_control.go index be5d817eb11d..9ff8d4d7bc9c 100644 --- a/aws/resource_aws_securityhub_standards_control.go +++ b/aws/resource_aws_securityhub_standards_control.go @@ -3,16 +3,16 @@ package aws import ( "context" "log" - "path" - "strings" "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/securityhub" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + tfsecurityhub "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/securityhub" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/securityhub/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsSecurityHubStandardsControl() *schema.Resource { @@ -23,47 +23,56 @@ func resourceAwsSecurityHubStandardsControl() *schema.Resource { DeleteContext: resourceAwsSecurityHubStandardsControlDelete, Schema: map[string]*schema.Schema{ - "standards_control_arn": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validateArn, + "control_id": { + Type: schema.TypeString, + Computed: true, }, + "control_status": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice(securityhub.ControlStatus_Values(), false), }, - "disabled_reason": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "control_id": { + + "control_status_updated_at": { Type: schema.TypeString, Computed: true, }, - "control_status_updated_at": { + + "description": { Type: schema.TypeString, Computed: true, }, - "description": { + + "disabled_reason": { Type: schema.TypeString, + Optional: true, Computed: true, }, + "related_requirements": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "remediation_url": { Type: schema.TypeString, Computed: true, }, + "severity_rating": { Type: schema.TypeString, Computed: true, }, + + "standards_control_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateArn, + }, + "title": { Type: schema.TypeString, Computed: true, @@ -75,39 +84,34 @@ func resourceAwsSecurityHubStandardsControl() *schema.Resource { func resourceAwsSecurityHubStandardsControlRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*AWSClient).securityhubconn - a := d.Get("standards_control_arn").(string) - controlArn, err := arn.Parse(a) + standardsSubscriptionARN, err := tfsecurityhub.StandardsControlARNToStandardsSubscriptionARN(d.Id()) + if err != nil { - return diag.Errorf("error parsing standards control ARN %q", controlArn) + return diag.FromErr(err) } - subscriptionArn := path.Dir(strings.ReplaceAll(controlArn.String(), "control", "subscription")) + control, err := finder.StandardsControlByStandardsSubscriptionARNAndStandardsControlARN(ctx, conn, standardsSubscriptionARN, d.Id()) - log.Printf("[DEBUG] Read Security Hub standard control %s", controlArn) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Security Hub Standards Control (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } - resp, err := conn.DescribeStandardsControls(&securityhub.DescribeStandardsControlsInput{ - StandardsSubscriptionArn: aws.String(subscriptionArn), - }) if err != nil { - return diag.Errorf("error reading Security Hub standard controls within %q subscription: %s", subscriptionArn, err) + return diag.Errorf("error reading Security Hub Standards Control (%s): %s", d.Id(), err) } - for _, c := range resp.Controls { - if aws.StringValue(c.StandardsControlArn) != controlArn.String() { - continue - } - - d.Set("control_status", c.ControlStatus) - d.Set("control_status_updated_at", c.ControlStatusUpdatedAt.Format(time.RFC3339)) - d.Set("description", c.Description) - d.Set("disabled_reason", c.DisabledReason) - d.Set("severity_rating", c.SeverityRating) - d.Set("title", c.Title) - - if err := d.Set("related_requirements", flattenStringList(c.RelatedRequirements)); err != nil { - return diag.Errorf("error setting related_requirements: %s", err) - } - } + d.Set("control_id", control.ControlId) + d.Set("control_status", control.ControlStatus) + d.Set("control_status_updated_at", control.ControlStatusUpdatedAt.Format(time.RFC3339)) + d.Set("description", control.Description) + d.Set("disabled_reason", control.DisabledReason) + d.Set("related_requirements", aws.StringValueSlice(control.RelatedRequirements)) + d.Set("remediation_url", control.RemediationUrl) + d.Set("severity_rating", control.SeverityRating) + d.Set("standards_control_arn", control.StandardsControlArn) + d.Set("title", control.Title) return nil } @@ -117,22 +121,23 @@ func resourceAwsSecurityHubStandardsControlPut(ctx context.Context, d *schema.Re d.SetId(d.Get("standards_control_arn").(string)) - log.Printf("[DEBUG] Update Security Hub standard control %s", d.Id()) - - _, err := conn.UpdateStandardsControl(&securityhub.UpdateStandardsControlInput{ - StandardsControlArn: aws.String(d.Get("standards_control_arn").(string)), + input := &securityhub.UpdateStandardsControlInput{ ControlStatus: aws.String(d.Get("control_status").(string)), DisabledReason: aws.String(d.Get("disabled_reason").(string)), - }) + StandardsControlArn: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Updating Security Hub Standards Control: %s", input) + _, err := conn.UpdateStandardsControlWithContext(ctx, input) + if err != nil { - d.SetId("") - return diag.Errorf("error updating Security Hub standard control %q: %s", d.Id(), err) + return diag.Errorf("error updating Security Hub Standards Control (%s): %s", d.Id(), err) } return resourceAwsSecurityHubStandardsControlRead(ctx, d, meta) } func resourceAwsSecurityHubStandardsControlDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - log.Printf("[WARN] Cannot delete Security Hub standard control. Terraform will remove this resource from the state.") + log.Printf("[WARN] Cannot delete Security Hub Standards Control. Terraform will remove this resource from the state.") return nil } diff --git a/aws/resource_aws_securityhub_standards_control_test.go b/aws/resource_aws_securityhub_standards_control_test.go index 24535392f62a..0db41d357cfc 100644 --- a/aws/resource_aws_securityhub_standards_control_test.go +++ b/aws/resource_aws_securityhub_standards_control_test.go @@ -1,38 +1,38 @@ package aws import ( + "context" "fmt" - "path" "regexp" - "strings" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/securityhub" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + tfsecurityhub "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/securityhub" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/securityhub/finder" ) -func TestAccAWSSecurityHubStandardsControl_basic(t *testing.T) { - var standardsControl *securityhub.StandardsControl - +func testAccAWSSecurityHubStandardsControl_basic(t *testing.T) { + var standardsControl securityhub.StandardsControl resourceName := "aws_securityhub_standards_control.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), + Providers: testAccProviders, Steps: []resource.TestStep{ { Config: testAccAWSSecurityHubStandardsControlConfig_basic(), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), + testAccCheckAWSSecurityHubStandardsControlExists(resourceName, &standardsControl), + resource.TestCheckResourceAttr(resourceName, "control_id", "CIS.1.10"), resource.TestCheckResourceAttr(resourceName, "control_status", "ENABLED"), - resource.TestMatchResourceAttr(resourceName, "control_status_updated_at", regexp.MustCompile(`\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)), + resource.TestCheckResourceAttrSet(resourceName, "control_status_updated_at"), resource.TestCheckResourceAttr(resourceName, "description", "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords."), resource.TestCheckResourceAttr(resourceName, "disabled_reason", ""), resource.TestCheckResourceAttr(resourceName, "related_requirements.0", "CIS AWS Foundations 1.10"), + resource.TestCheckResourceAttrSet(resourceName, "remediation_url"), resource.TestCheckResourceAttr(resourceName, "severity_rating", "LOW"), resource.TestCheckResourceAttr(resourceName, "title", "Ensure IAM password policy prevents password reuse"), ), @@ -41,21 +41,19 @@ func TestAccAWSSecurityHubStandardsControl_basic(t *testing.T) { }) } -func TestAccAWSSecurityHubStandardsControl_disabledControlStatus(t *testing.T) { - var standardsControl *securityhub.StandardsControl - +func testAccAWSSecurityHubStandardsControl_disabledControlStatus(t *testing.T) { + var standardsControl securityhub.StandardsControl resourceName := "aws_securityhub_standards_control.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), + Providers: testAccProviders, Steps: []resource.TestStep{ { Config: testAccAWSSecurityHubStandardsControlConfig_disabledControlStatus(), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), + testAccCheckAWSSecurityHubStandardsControlExists(resourceName, &standardsControl), resource.TestCheckResourceAttr(resourceName, "control_status", "DISABLED"), resource.TestCheckResourceAttr(resourceName, "disabled_reason", "We handle password policies within Okta"), ), @@ -64,16 +62,11 @@ func TestAccAWSSecurityHubStandardsControl_disabledControlStatus(t *testing.T) { }) } -func TestAccAWSSecurityHubStandardsControl_enabledControlStatusAndDisabledReason(t *testing.T) { - var standardsControl *securityhub.StandardsControl - - resourceName := "aws_securityhub_standards_control.test" - +func testAccAWSSecurityHubStandardsControl_enabledControlStatusAndDisabledReason(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSSecurityHubStandardsControlExists(resourceName, standardsControl), + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), + Providers: testAccProviders, Steps: []resource.TestStep{ { Config: testAccAWSSecurityHubStandardsControlConfig_enabledControlStatus(), @@ -90,32 +83,25 @@ func testAccCheckAWSSecurityHubStandardsControlExists(n string, control *securit return fmt.Errorf("Not found: %s", n) } + if rs.Primary.ID == "" { + return fmt.Errorf("No Security Hub Standards Control ID is set") + } + conn := testAccProvider.Meta().(*AWSClient).securityhubconn - arn := rs.Primary.ID - subscription_arn := path.Dir(strings.ReplaceAll(arn, "control", "subscription")) + standardsSubscriptionARN, err := tfsecurityhub.StandardsControlARNToStandardsSubscriptionARN(rs.Primary.ID) - resp, err := conn.DescribeStandardsControls(&securityhub.DescribeStandardsControlsInput{ - StandardsSubscriptionArn: aws.String(subscription_arn), - }) if err != nil { - return fmt.Errorf("error reading Security Hub %s standard controls: %s", subscription_arn, err) + return err } - controlNotFound := true - - for _, c := range resp.Controls { - if aws.StringValue(c.StandardsControlArn) != arn { - continue - } + output, err := finder.StandardsControlByStandardsSubscriptionARNAndStandardsControlARN(context.TODO(), conn, standardsSubscriptionARN, rs.Primary.ID) - controlNotFound = false - control = c + if err != nil { + return err } - if controlNotFound { - return fmt.Errorf("Security Hub %s standard control %s not found", subscription_arn, arn) - } + *control = *output return nil } diff --git a/aws/resource_aws_securityhub_standards_subscription.go b/aws/resource_aws_securityhub_standards_subscription.go index ebf53ef11f74..1fc28e812a52 100644 --- a/aws/resource_aws_securityhub_standards_subscription.go +++ b/aws/resource_aws_securityhub_standards_subscription.go @@ -7,6 +7,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/securityhub" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/securityhub/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/securityhub/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsSecurityHubStandardsSubscription() *schema.Resource { @@ -14,6 +17,7 @@ func resourceAwsSecurityHubStandardsSubscription() *schema.Resource { Create: resourceAwsSecurityHubStandardsSubscriptionCreate, Read: resourceAwsSecurityHubStandardsSubscriptionRead, Delete: resourceAwsSecurityHubStandardsSubscriptionDelete, + Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, @@ -31,23 +35,30 @@ func resourceAwsSecurityHubStandardsSubscription() *schema.Resource { func resourceAwsSecurityHubStandardsSubscriptionCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).securityhubconn - log.Printf("[DEBUG] Enabling Security Hub standard %s", d.Get("standards_arn")) - resp, err := conn.BatchEnableStandards(&securityhub.BatchEnableStandardsInput{ + standardsARN := d.Get("standards_arn").(string) + input := &securityhub.BatchEnableStandardsInput{ StandardsSubscriptionRequests: []*securityhub.StandardsSubscriptionRequest{ { - StandardsArn: aws.String(d.Get("standards_arn").(string)), + StandardsArn: aws.String(standardsARN), }, }, - }) + } + + log.Printf("[DEBUG] Creating Security Hub Standards Subscription: %s", input) + output, err := conn.BatchEnableStandards(input) if err != nil { - return fmt.Errorf("Error enabling Security Hub standard: %s", err) + return fmt.Errorf("error enabling Security Hub Standard (%s): %w", standardsARN, err) } - standardsSubscription := resp.StandardsSubscriptions[0] + d.SetId(aws.StringValue(output.StandardsSubscriptions[0].StandardsSubscriptionArn)) - d.SetId(aws.StringValue(standardsSubscription.StandardsSubscriptionArn)) + _, err = waiter.StandardsSubscriptionCreated(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for Security Hub Standards Subscription (%s) to create: %w", d.Id(), err) + } return resourceAwsSecurityHubStandardsSubscriptionRead(d, meta) } @@ -55,38 +66,35 @@ func resourceAwsSecurityHubStandardsSubscriptionCreate(d *schema.ResourceData, m func resourceAwsSecurityHubStandardsSubscriptionRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).securityhubconn - log.Printf("[DEBUG] Reading Security Hub standard %s", d.Id()) - resp, err := conn.GetEnabledStandards(&securityhub.GetEnabledStandardsInput{ - StandardsSubscriptionArns: []*string{aws.String(d.Id())}, - }) - - if err != nil { - return fmt.Errorf("Error reading Security Hub standard %s: %s", d.Id(), err) - } + output, err := finder.StandardsSubscriptionByARN(conn, d.Id()) - if len(resp.StandardsSubscriptions) == 0 { - log.Printf("[WARN] Security Hub standard (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Security Hub Standards Subscription (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - standardsSubscription := resp.StandardsSubscriptions[0] - - d.Set("standards_arn", standardsSubscription.StandardsArn) + d.Set("standards_arn", output.StandardsArn) return nil } func resourceAwsSecurityHubStandardsSubscriptionDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).securityhubconn - log.Printf("[DEBUG] Disabling Security Hub standard %s", d.Id()) + log.Printf("[DEBUG] Deleting Security Hub Standards Subscription: %s", d.Id()) _, err := conn.BatchDisableStandards(&securityhub.BatchDisableStandardsInput{ - StandardsSubscriptionArns: []*string{aws.String(d.Id())}, + StandardsSubscriptionArns: aws.StringSlice([]string{d.Id()}), }) if err != nil { - return fmt.Errorf("Error disabling Security Hub standard %s: %s", d.Id(), err) + return fmt.Errorf("error disabling Security Hub Standard (%s): %w", d.Id(), err) + } + + _, err = waiter.StandardsSubscriptionDeleted(conn, d.Id()) + + if err != nil { + return fmt.Errorf("error waiting for Security Hub Standards Subscription (%s) to delete: %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_securityhub_standards_subscription_test.go b/aws/resource_aws_securityhub_standards_subscription_test.go index 0e3bb4b56688..25f2f9a85595 100644 --- a/aws/resource_aws_securityhub_standards_subscription_test.go +++ b/aws/resource_aws_securityhub_standards_subscription_test.go @@ -4,15 +4,15 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/securityhub" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/securityhub/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func testAccAWSSecurityHubStandardsSubscription_basic(t *testing.T) { - var standardsSubscription *securityhub.StandardsSubscription - + var standardsSubscription securityhub.StandardsSubscription resourceName := "aws_securityhub_standards_subscription.test" resource.Test(t, resource.TestCase{ @@ -24,7 +24,7 @@ func testAccAWSSecurityHubStandardsSubscription_basic(t *testing.T) { { Config: testAccAWSSecurityHubStandardsSubscriptionConfig_basic, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSSecurityHubStandardsSubscriptionExists(resourceName, standardsSubscription), + testAccCheckAWSSecurityHubStandardsSubscriptionExists(resourceName, &standardsSubscription), ), }, { @@ -32,11 +32,27 @@ func testAccAWSSecurityHubStandardsSubscription_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + }, + }) +} + +func testAccAWSSecurityHubStandardsSubscription_disappears(t *testing.T) { + var standardsSubscription securityhub.StandardsSubscription + resourceName := "aws_securityhub_standards_subscription.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSecurityHubAccountDestroy, + Steps: []resource.TestStep{ { - // Check Destroy - but only target the specific resource (otherwise Security Hub - // will be disabled and the destroy check will fail) - Config: testAccAWSSecurityHubStandardsSubscriptionConfig_empty, - Check: testAccCheckAWSSecurityHubStandardsSubscriptionDestroy, + Config: testAccAWSSecurityHubStandardsSubscriptionConfig_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSecurityHubStandardsSubscriptionExists(resourceName, &standardsSubscription), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSecurityHubStandardsSubscription(), resourceName), + ), + ExpectNonEmptyPlan: true, }, }, }) @@ -49,21 +65,19 @@ func testAccCheckAWSSecurityHubStandardsSubscriptionExists(n string, standardsSu return fmt.Errorf("Not found: %s", n) } + if rs.Primary.ID == "" { + return fmt.Errorf("No Security Hub Standards Subscription ID is set") + } + conn := testAccProvider.Meta().(*AWSClient).securityhubconn - resp, err := conn.GetEnabledStandards(&securityhub.GetEnabledStandardsInput{ - StandardsSubscriptionArns: []*string{aws.String(rs.Primary.ID)}, - }) + output, err := finder.StandardsSubscriptionByARN(conn, rs.Primary.ID) if err != nil { return err } - if len(resp.StandardsSubscriptions) == 0 { - return fmt.Errorf("Security Hub standard %s not found", rs.Primary.ID) - } - - standardsSubscription = resp.StandardsSubscriptions[0] + *standardsSubscription = *output return nil } @@ -77,20 +91,17 @@ func testAccCheckAWSSecurityHubStandardsSubscriptionDestroy(s *terraform.State) continue } - resp, err := conn.GetEnabledStandards(&securityhub.GetEnabledStandardsInput{ - StandardsSubscriptionArns: []*string{aws.String(rs.Primary.ID)}, - }) + _, err := finder.StandardsSubscriptionByARN(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } if err != nil { - if isAWSErr(err, securityhub.ErrCodeResourceNotFoundException, "") { - continue - } return err } - if len(resp.StandardsSubscriptions) != 0 { - return fmt.Errorf("Security Hub standard %s still exists", rs.Primary.ID) - } + return fmt.Errorf("Security Hub Standards Subscription %s still exists", rs.Primary.ID) } return nil diff --git a/aws/resource_aws_securityhub_test.go b/aws/resource_aws_securityhub_test.go index ee4601b8d31f..78ae1839dd42 100644 --- a/aws/resource_aws_securityhub_test.go +++ b/aws/resource_aws_securityhub_test.go @@ -43,8 +43,14 @@ func TestAccAWSSecurityHub_serial(t *testing.T) { "ProductSubscription": { "basic": testAccAWSSecurityHubProductSubscription_basic, }, + "StandardsControl": { + "basic": testAccAWSSecurityHubStandardsControl_basic, + "DisabledControlStatus": testAccAWSSecurityHubStandardsControl_disabledControlStatus, + "EnabledControlStatusAndDisabledReason": testAccAWSSecurityHubStandardsControl_enabledControlStatusAndDisabledReason, + }, "StandardsSubscription": { - "basic": testAccAWSSecurityHubStandardsSubscription_basic, + "basic": testAccAWSSecurityHubStandardsSubscription_basic, + "disappears": testAccAWSSecurityHubStandardsSubscription_disappears, }, } From 7495f70be54ab3819ab8c5ce31bc7314775e1025 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 13 Jul 2021 13:51:55 -0400 Subject: [PATCH 1184/1208] Fix awsprovidelint error 'AT001: missing CheckDestroy'. --- ..._aws_securityhub_standards_control_test.go | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/aws/resource_aws_securityhub_standards_control_test.go b/aws/resource_aws_securityhub_standards_control_test.go index 0db41d357cfc..d1f4629849e6 100644 --- a/aws/resource_aws_securityhub_standards_control_test.go +++ b/aws/resource_aws_securityhub_standards_control_test.go @@ -18,9 +18,10 @@ func testAccAWSSecurityHubStandardsControl_basic(t *testing.T) { resourceName := "aws_securityhub_standards_control.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), + Providers: testAccProviders, + CheckDestroy: nil, //lintignore:AT001 Steps: []resource.TestStep{ { Config: testAccAWSSecurityHubStandardsControlConfig_basic(), @@ -46,9 +47,10 @@ func testAccAWSSecurityHubStandardsControl_disabledControlStatus(t *testing.T) { resourceName := "aws_securityhub_standards_control.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), + Providers: testAccProviders, + CheckDestroy: nil, //lintignore:AT001 Steps: []resource.TestStep{ { Config: testAccAWSSecurityHubStandardsControlConfig_disabledControlStatus(), @@ -64,9 +66,10 @@ func testAccAWSSecurityHubStandardsControl_disabledControlStatus(t *testing.T) { func testAccAWSSecurityHubStandardsControl_enabledControlStatusAndDisabledReason(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), + Providers: testAccProviders, + CheckDestroy: nil, //lintignore:AT001 Steps: []resource.TestStep{ { Config: testAccAWSSecurityHubStandardsControlConfig_enabledControlStatus(), From f83cb8bbcb53c54d98f136e83ec7cb56ac694432 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 13 Jul 2021 13:52:46 -0400 Subject: [PATCH 1185/1208] Fix golangci-lint error 'deadcode'. --- ...esource_aws_securityhub_standards_subscription_test.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_securityhub_standards_subscription_test.go b/aws/resource_aws_securityhub_standards_subscription_test.go index 25f2f9a85595..d0b77d76edf9 100644 --- a/aws/resource_aws_securityhub_standards_subscription_test.go +++ b/aws/resource_aws_securityhub_standards_subscription_test.go @@ -19,7 +19,7 @@ func testAccAWSSecurityHubStandardsSubscription_basic(t *testing.T) { PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), Providers: testAccProviders, - CheckDestroy: testAccCheckAWSSecurityHubAccountDestroy, + CheckDestroy: testAccCheckAWSSecurityHubStandardsSubscriptionDestroy, Steps: []resource.TestStep{ { Config: testAccAWSSecurityHubStandardsSubscriptionConfig_basic, @@ -44,7 +44,7 @@ func testAccAWSSecurityHubStandardsSubscription_disappears(t *testing.T) { PreCheck: func() { testAccPreCheck(t) }, ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), Providers: testAccProviders, - CheckDestroy: testAccCheckAWSSecurityHubAccountDestroy, + CheckDestroy: testAccCheckAWSSecurityHubStandardsSubscriptionDestroy, Steps: []resource.TestStep{ { Config: testAccAWSSecurityHubStandardsSubscriptionConfig_basic, @@ -107,10 +107,6 @@ func testAccCheckAWSSecurityHubStandardsSubscriptionDestroy(s *terraform.State) return nil } -const testAccAWSSecurityHubStandardsSubscriptionConfig_empty = ` -resource "aws_securityhub_account" "test" {} -` - const testAccAWSSecurityHubStandardsSubscriptionConfig_basic = ` resource "aws_securityhub_account" "test" {} From f92c7af611ea7dcf95b79fcc2b2761368eb3061c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 13 Jul 2021 13:59:10 -0400 Subject: [PATCH 1186/1208] r/aws_securityhub_standards_subscription: Correctly handle INCOMPLETE status in 'testAccCheckAWSSecurityHubStandardsSubscriptionDestroy'. Acceptance test output: % make testacc TEST=./aws TESTARGS='-run=TestAccAWSSecurityHub_serial/StandardsSubscription' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSSecurityHub_serial/StandardsSubscription -timeout 180m === RUN TestAccAWSSecurityHub_serial === RUN TestAccAWSSecurityHub_serial/StandardsSubscription === RUN TestAccAWSSecurityHub_serial/StandardsSubscription/basic === RUN TestAccAWSSecurityHub_serial/StandardsSubscription/disappears --- PASS: TestAccAWSSecurityHub_serial (39.10s) --- PASS: TestAccAWSSecurityHub_serial/StandardsSubscription (39.10s) --- PASS: TestAccAWSSecurityHub_serial/StandardsSubscription/basic (22.59s) --- PASS: TestAccAWSSecurityHub_serial/StandardsSubscription/disappears (16.51s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 42.508s --- ...esource_aws_securityhub_standards_subscription_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_securityhub_standards_subscription_test.go b/aws/resource_aws_securityhub_standards_subscription_test.go index d0b77d76edf9..3988a43e5506 100644 --- a/aws/resource_aws_securityhub_standards_subscription_test.go +++ b/aws/resource_aws_securityhub_standards_subscription_test.go @@ -4,6 +4,7 @@ import ( "fmt" "testing" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/securityhub" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -91,7 +92,7 @@ func testAccCheckAWSSecurityHubStandardsSubscriptionDestroy(s *terraform.State) continue } - _, err := finder.StandardsSubscriptionByARN(conn, rs.Primary.ID) + output, err := finder.StandardsSubscriptionByARN(conn, rs.Primary.ID) if tfresource.NotFound(err) { continue @@ -101,6 +102,11 @@ func testAccCheckAWSSecurityHubStandardsSubscriptionDestroy(s *terraform.State) return err } + // INCOMPLETE subscription status => deleted. + if aws.StringValue(output.StandardsStatus) == securityhub.StandardsStatusIncomplete { + continue + } + return fmt.Errorf("Security Hub Standards Subscription %s still exists", rs.Primary.ID) } From a199a6be8618ec9ace2806dc9ba414890abab00a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 13 Jul 2021 15:07:06 -0400 Subject: [PATCH 1187/1208] Correct new argument name (retro v3.47.0) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc5478f213a9..837d38996d3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,7 +87,7 @@ ENHANCEMENTS: * resource/aws_eks_cluster: Allow updates to `encryption_config` ([#19144](https://github.com/hashicorp/terraform-provider-aws/issues/19144)) * resource/aws_lb_target_group: Add support for `app_cookie` stickiness type and `cookie_name` argument ([#18102](https://github.com/hashicorp/terraform-provider-aws/issues/18102)) * resource/aws_main_route_table_association: Wait for association to reach the required state ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) -* resource/aws_neptune_cluster: Add `copy_snapshot_to_tags` argument ([#19899](https://github.com/hashicorp/terraform-provider-aws/issues/19899)) +* resource/aws_neptune_cluster: Add `copy_tags_to_snapshot` argument ([#19899](https://github.com/hashicorp/terraform-provider-aws/issues/19899)) * resource/aws_route: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_route_table: Add retries when creating, deleting and replacing routes ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) * resource/aws_route_table_association: Wait for association to reach the required state ([#19426](https://github.com/hashicorp/terraform-provider-aws/issues/19426)) From 72e623415ce30dfa463aa0cac7d3ef433b262824 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Tue, 13 Jul 2021 19:10:04 +0000 Subject: [PATCH 1188/1208] Update CHANGELOG.md for #20168 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 837d38996d3c..b17d94a70581 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ FEATURES: * **New Resource:** `aws_appconfig_environment` ([#19307](https://github.com/hashicorp/terraform-provider-aws/issues/19307)) * **New Resource:** `aws_appconfig_hosted_configuration_version` ([#19324](https://github.com/hashicorp/terraform-provider-aws/issues/19324)) * **New Resource:** `aws_config_organization_conformance_pack` ([#17298](https://github.com/hashicorp/terraform-provider-aws/issues/17298)) +* **New Resource:** `aws_securityhub_standards_control` ([#14714](https://github.com/hashicorp/terraform-provider-aws/issues/14714)) ENHANCEMENTS: From b805c0ec7340f1a8ae57cea675d571b0eb20d489 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jul 2021 06:04:32 +0000 Subject: [PATCH 1189/1208] build(deps): bump alex-page/github-project-automation-plus Bumps [alex-page/github-project-automation-plus](https://github.com/alex-page/github-project-automation-plus) from 0.8.0 to 0.8.1. - [Release notes](https://github.com/alex-page/github-project-automation-plus/releases) - [Commits](https://github.com/alex-page/github-project-automation-plus/compare/v0.8.0...v0.8.1) --- updated-dependencies: - dependency-name: alex-page/github-project-automation-plus dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/project.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml index 7739fa63b75f..7c9f0d5852a1 100644 --- a/.github/workflows/project.yml +++ b/.github/workflows/project.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Move team PRs to Review column - uses: alex-page/github-project-automation-plus@v0.8.0 + uses: alex-page/github-project-automation-plus@v0.8.1 if: contains(fromJSON('["anGie44", "bill-rich", "breathingdust", "ewbankkit", "gdavison", "maryelizbeth", "YakDriver"]'), github.actor) && github.event.pull_request.draft == false with: project: AWS Provider Working Board From dc0ef30fce9ea93c382a443830a45917007583de Mon Sep 17 00:00:00 2001 From: Suzuki Shunsuke Date: Wed, 14 Jul 2021 20:34:20 +0900 Subject: [PATCH 1190/1208] fix: add the attribute "environment_id" to aws_appconfig_environment --- aws/resource_aws_appconfig_environment.go | 6 ++++++ website/docs/r/appconfig_environment.html.markdown | 1 + 2 files changed, 7 insertions(+) diff --git a/aws/resource_aws_appconfig_environment.go b/aws/resource_aws_appconfig_environment.go index 14f4d67513e9..9a6c15a55644 100644 --- a/aws/resource_aws_appconfig_environment.go +++ b/aws/resource_aws_appconfig_environment.go @@ -32,6 +32,10 @@ func resourceAwsAppconfigEnvironment() *schema.Resource { ForceNew: true, ValidateFunc: validation.StringMatch(regexp.MustCompile(`[a-z0-9]{4,7}`), ""), }, + "environment_id": { + Type: schema.TypeString, + Computed: true, + }, "arn": { Type: schema.TypeString, Computed: true, @@ -110,6 +114,7 @@ func resourceAwsAppconfigEnvironmentCreate(d *schema.ResourceData, meta interfac return fmt.Errorf("error creating AppConfig Environment for Application (%s): empty response", appId) } + d.Set("environment_id", environment.Id) d.SetId(fmt.Sprintf("%s:%s", aws.StringValue(environment.Id), aws.StringValue(environment.ApplicationId))) return resourceAwsAppconfigEnvironmentRead(d, meta) @@ -148,6 +153,7 @@ func resourceAwsAppconfigEnvironmentRead(d *schema.ResourceData, meta interface{ } d.Set("application_id", output.ApplicationId) + d.Set("environment_id", output.Id) d.Set("description", output.Description) d.Set("name", output.Name) d.Set("state", output.State) diff --git a/website/docs/r/appconfig_environment.html.markdown b/website/docs/r/appconfig_environment.html.markdown index 506e3b1266b8..ee06988b27aa 100644 --- a/website/docs/r/appconfig_environment.html.markdown +++ b/website/docs/r/appconfig_environment.html.markdown @@ -61,6 +61,7 @@ In addition to all arguments above, the following attributes are exported: * `arn` - The Amazon Resource Name (ARN) of the AppConfig Environment. * `id` - The AppConfig environment ID and application ID separated by a colon (`:`). +* `environment_id` - The AppConfig environment ID. * `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 From 64522c13505e2473f5451920fd90363328db1c05 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 14 Jul 2021 16:19:52 +0000 Subject: [PATCH 1191/1208] Update CHANGELOG.md for #20111 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b17d94a70581..8485296a35ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ BUG FIXES: * resource/aws_cognito_user_pool_client: Retry on `ConcurrentModificationException` ([#20031](https://github.com/hashicorp/terraform-provider-aws/issues/20031)) * resource/aws_datasync_location_s3: Correctly parse S3 on Outposts location URI ([#19859](https://github.com/hashicorp/terraform-provider-aws/issues/19859)) * resource/aws_db_instance: Ignore allocated_storage for replica at creation time ([#12548](https://github.com/hashicorp/terraform-provider-aws/issues/12548)) +* resource/aws_elasticache_replication_group: Cannot set `cluster_mode.replicas_per_node_group` when member of Global Replication Group ([#20111](https://github.com/hashicorp/terraform-provider-aws/issues/20111)) ## 3.49.0 (July 08, 2021) From dc5410c8966b43416e1a1dc3dd9764418b20b0c7 Mon Sep 17 00:00:00 2001 From: Mikael Allison Date: Mon, 26 Apr 2021 02:00:10 +0100 Subject: [PATCH 1192/1208] Add SecurityHub Organization Configuration Resource Resource to enable security hub's auto-enroll feature when apart of an organization and a security hub admin account has been configured. By default the **Auto-Enable** feature is disabled. See: [Automatically enabling new organization accounts](https://docs.aws.amazon.com/securityhub/latest/userguide/accounts-orgs-auto-enable.html) [method]: https://docs.aws.amazon.com/sdk-for-go/api/service/securityhub/#SecurityHub.UpdateOrganizationConfiguration [input]: https://docs.aws.amazon.com/sdk-for-go/api/service/securityhub/#UpdateOrganizationConfigurationInput Refactored with amendments suggested by @ewbankkit --- .changelog/19108.txt | 3 + aws/provider.go | 1 + ..._securityhub_organization_configuration.go | 60 +++++++++++++ ...rityhub_organization_configuration_test.go | 84 +++++++++++++++++++ aws/resource_aws_securityhub_test.go | 3 + ...b_organization_admin_account.html.markdown | 3 + ...ityhub_organization_configuration.markdown | 54 ++++++++++++ 7 files changed, 208 insertions(+) create mode 100644 .changelog/19108.txt create mode 100644 aws/resource_aws_securityhub_organization_configuration.go create mode 100644 aws/resource_aws_securityhub_organization_configuration_test.go create mode 100644 website/docs/r/securityhub_organization_configuration.markdown diff --git a/.changelog/19108.txt b/.changelog/19108.txt new file mode 100644 index 000000000000..f6266443b273 --- /dev/null +++ b/.changelog/19108.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_securityhub_organization_configuration +``` diff --git a/aws/provider.go b/aws/provider.go index 745c64e4937f..2a2671a4b72a 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -992,6 +992,7 @@ func Provider() *schema.Provider { "aws_securityhub_invite_accepter": resourceAwsSecurityHubInviteAccepter(), "aws_securityhub_member": resourceAwsSecurityHubMember(), "aws_securityhub_organization_admin_account": resourceAwsSecurityHubOrganizationAdminAccount(), + "aws_securityhub_organization_configuration": resourceAwsSecurityHubOrganizationConfiguration(), "aws_securityhub_product_subscription": resourceAwsSecurityHubProductSubscription(), "aws_securityhub_standards_subscription": resourceAwsSecurityHubStandardsSubscription(), "aws_servicecatalog_portfolio": resourceAwsServiceCatalogPortfolio(), diff --git a/aws/resource_aws_securityhub_organization_configuration.go b/aws/resource_aws_securityhub_organization_configuration.go new file mode 100644 index 000000000000..cba3fd99539d --- /dev/null +++ b/aws/resource_aws_securityhub_organization_configuration.go @@ -0,0 +1,60 @@ +package aws + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/securityhub" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceAwsSecurityHubOrganizationConfiguration() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSecurityHubOrganizationConfigurationUpdate, + Read: resourceAwsSecurityHubOrganizationConfigurationRead, + Update: resourceAwsSecurityHubOrganizationConfigurationUpdate, + Delete: schema.Noop, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "auto_enable": { + Type: schema.TypeBool, + Required: true, + }, + }, + } +} + +func resourceAwsSecurityHubOrganizationConfigurationUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + + input := &securityhub.UpdateOrganizationConfigurationInput{ + AutoEnable: aws.Bool(d.Get("auto_enable").(bool)), + } + + _, err := conn.UpdateOrganizationConfiguration(input) + + if err != nil { + return fmt.Errorf("error updating Security Hub Organization Configuration (%s): %w", d.Id(), err) + } + + d.SetId(meta.(*AWSClient).accountid) + + return resourceAwsSecurityHubOrganizationConfigurationRead(d, meta) +} + +func resourceAwsSecurityHubOrganizationConfigurationRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).securityhubconn + + output, err := conn.DescribeOrganizationConfiguration(&securityhub.DescribeOrganizationConfigurationInput{}) + + if err != nil { + return fmt.Errorf("error reading Security Hub Organization Configuration: %w", err) + } + + d.Set("auto_enable", output.AutoEnable) + + return nil +} diff --git a/aws/resource_aws_securityhub_organization_configuration_test.go b/aws/resource_aws_securityhub_organization_configuration_test.go new file mode 100644 index 000000000000..1c202fab97d2 --- /dev/null +++ b/aws/resource_aws_securityhub_organization_configuration_test.go @@ -0,0 +1,84 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/securityhub" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func testAccAwsSecurityHubOrganizationConfiguration_basic(t *testing.T) { + resourceName := "aws_securityhub_organization_configuration.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccOrganizationsAccountPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, securityhub.EndpointsID), + Providers: testAccProviders, + CheckDestroy: nil, //lintignore:AT001 + Steps: []resource.TestStep{ + { + Config: testAccAwsSecurityHubOrganizationConfigurationConfig(true), + Check: resource.ComposeTestCheckFunc( + testAccAwsSecurityHubOrganizationConfigurationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "auto_enable", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAwsSecurityHubOrganizationConfigurationConfig(false), + Check: resource.ComposeTestCheckFunc( + testAccAwsSecurityHubOrganizationConfigurationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "auto_enable", "false"), + ), + }, + }, + }) +} + +func testAccAwsSecurityHubOrganizationConfigurationExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := testAccProvider.Meta().(*AWSClient).securityhubconn + + _, err := conn.DescribeOrganizationConfiguration(&securityhub.DescribeOrganizationConfigurationInput{}) + + return err + } +} + +func testAccAwsSecurityHubOrganizationConfigurationConfig(autoEnable bool) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_organizations_organization" "test" { + aws_service_access_principals = ["securityhub.${data.aws_partition.current.dns_suffix}"] + feature_set = "ALL" +} + +resource "aws_securityhub_account" "test" {} + +data "aws_caller_identity" "current" {} + +resource "aws_securityhub_organization_admin_account" "test" { + admin_account_id = data.aws_caller_identity.current.account_id + + depends_on = [aws_organizations_organization.test, aws_securityhub_account.test] +} + +resource "aws_securityhub_organization_configuration" "test" { + auto_enable = %[1]t + + depends_on = [aws_securityhub_organization_admin_account.test] +} +`, autoEnable) +} diff --git a/aws/resource_aws_securityhub_test.go b/aws/resource_aws_securityhub_test.go index ee4601b8d31f..b610200d736f 100644 --- a/aws/resource_aws_securityhub_test.go +++ b/aws/resource_aws_securityhub_test.go @@ -40,6 +40,9 @@ func TestAccAWSSecurityHub_serial(t *testing.T) { "disappears": testAccAwsSecurityHubOrganizationAdminAccount_disappears, "MultiRegion": testAccAwsSecurityHubOrganizationAdminAccount_MultiRegion, }, + "OrganizationConfiguration": { + "basic": testAccAwsSecurityHubOrganizationConfiguration_basic, + }, "ProductSubscription": { "basic": testAccAWSSecurityHubProductSubscription_basic, }, diff --git a/website/docs/r/securityhub_organization_admin_account.html.markdown b/website/docs/r/securityhub_organization_admin_account.html.markdown index 3941c489671f..fa69bf0f38d8 100644 --- a/website/docs/r/securityhub_organization_admin_account.html.markdown +++ b/website/docs/r/securityhub_organization_admin_account.html.markdown @@ -25,6 +25,9 @@ resource "aws_securityhub_organization_admin_account" "example" { admin_account_id = "123456789012" } + +// Auto enable security hub in organization member accounts +resource "aws_securityhub_organization_configuration" "example" {} ``` ## Argument Reference diff --git a/website/docs/r/securityhub_organization_configuration.markdown b/website/docs/r/securityhub_organization_configuration.markdown new file mode 100644 index 000000000000..439456336b88 --- /dev/null +++ b/website/docs/r/securityhub_organization_configuration.markdown @@ -0,0 +1,54 @@ +--- +subcategory: "Security Hub" +layout: "aws" +page_title: "AWS: aws_securityhub_organization_configuration" +description: |- + Manages the Security Hub Organization Configuration +--- + +# Resource: aws_securityhub_organization_configuration + +Manages the Security Hub Organization Configuration. + +~> **NOTE:** This resource requires an [`aws_securityhub_organization_admin_account`](/docs/providers/aws/r/securityhub_organization_admin_account.html) to be configured (not necessarily with Terraform). More information about managing Security Hub in an organization can be found in the [Managing administrator and member accounts](https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-accounts.html) documentation + +~> **NOTE:** This is an advanced Terraform resource. Terraform will automatically assume management of the Security Hub Organization Configuration without import and perform no actions on removal from the Terraform configuration. + +## Example Usage + +```terraform +resource "aws_organizations_organization" "example" { + aws_service_access_principals = ["securityhub.amazonaws.com"] + feature_set = "ALL" +} + +resource "aws_securityhub_organization_admin_account" "example" { + depends_on = [aws_organizations_organization.example] + + admin_account_id = "123456789012" +} + +resource "aws_securityhub_organization_configuration" "example" { + auto_enable = true +} +``` + +## Argument Reference + +The following arguments are supported: + +* `auto_enable` - (Required) Whether to automatically enable Security Hub for new accounts in the organization. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - AWS Account ID. + +## Import + +An existing Security Hub enabled account can be imported using the AWS account ID, e.g. + +``` +$ terraform import aws_securityhub_organization_configuration.example 123456789012 +``` From 07d7cd4b8acae4bbf8cb4eff959aad72a5530da1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 14 Jul 2021 12:59:28 -0400 Subject: [PATCH 1193/1208] Random junk file. --- a.txt | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 a.txt diff --git a/a.txt b/a.txt deleted file mode 100644 index 8bdec30e0870..000000000000 --- a/a.txt +++ /dev/null @@ -1,2 +0,0 @@ -==> Checking that code complies with gofmt requirements... -TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSEcrReplicationConfiguration_basic -timeout 180m From a76209003a39187ecd7620fa48ba88d4affd9e6d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 14 Jul 2021 13:10:19 -0400 Subject: [PATCH 1194/1208] Fix importlint error 'Imports of different types are not allowed in the same group'. --- aws/resource_aws_securityhub_organization_configuration.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/resource_aws_securityhub_organization_configuration.go b/aws/resource_aws_securityhub_organization_configuration.go index cba3fd99539d..52355360eb25 100644 --- a/aws/resource_aws_securityhub_organization_configuration.go +++ b/aws/resource_aws_securityhub_organization_configuration.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/securityhub" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" From 4d809190d7339eb3d22facb003fe7e896123ca04 Mon Sep 17 00:00:00 2001 From: Jacob Date: Wed, 14 Jul 2021 12:45:37 -0500 Subject: [PATCH 1195/1208] arns are also a part of the attributes (#20167) * arns are also a part of the attributes arns are also a part of the attributes. * Update website/docs/d/cognito_user_pools.markdown Co-authored-by: angie pinilla * Update cognito_user_pools.markdown Co-authored-by: angie pinilla --- website/docs/d/cognito_user_pools.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/d/cognito_user_pools.markdown b/website/docs/d/cognito_user_pools.markdown index fae711548075..ceebad004a52 100644 --- a/website/docs/d/cognito_user_pools.markdown +++ b/website/docs/d/cognito_user_pools.markdown @@ -36,4 +36,5 @@ resource "aws_api_gateway_authorizer" "cognito" { ## Attributes Reference -* `ids` - The list of cognito user pool ids. +* `ids` - The set of cognito user pool ids. +* `arns` - The set of cognito user pool Amazon Resource Names (ARNs). From 69fd4700bab314e8bffa6f8eb99dfb6cc6581add Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 14 Jul 2021 14:02:31 -0400 Subject: [PATCH 1196/1208] Fix validate-terraform error 'Warning: Single line comments should begin with # (terraform_comment_syntax)'. --- .../docs/r/securityhub_organization_admin_account.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/securityhub_organization_admin_account.html.markdown b/website/docs/r/securityhub_organization_admin_account.html.markdown index fa69bf0f38d8..1863444c03d3 100644 --- a/website/docs/r/securityhub_organization_admin_account.html.markdown +++ b/website/docs/r/securityhub_organization_admin_account.html.markdown @@ -26,7 +26,7 @@ resource "aws_securityhub_organization_admin_account" "example" { admin_account_id = "123456789012" } -// Auto enable security hub in organization member accounts +# Auto enable security hub in organization member accounts resource "aws_securityhub_organization_configuration" "example" {} ``` From c764beb2ba8ca142e11575a77001fc7fbedd2543 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Wed, 14 Jul 2021 18:02:42 +0000 Subject: [PATCH 1197/1208] Update CHANGELOG.md for #20183 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8485296a35ab..b4ceec4419b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ FEATURES: * **New Resource:** `aws_appconfig_environment` ([#19307](https://github.com/hashicorp/terraform-provider-aws/issues/19307)) * **New Resource:** `aws_appconfig_hosted_configuration_version` ([#19324](https://github.com/hashicorp/terraform-provider-aws/issues/19324)) * **New Resource:** `aws_config_organization_conformance_pack` ([#17298](https://github.com/hashicorp/terraform-provider-aws/issues/17298)) +* **New Resource:** `aws_securityhub_organization_configuration` ([#19108](https://github.com/hashicorp/terraform-provider-aws/issues/19108)) * **New Resource:** `aws_securityhub_standards_control` ([#14714](https://github.com/hashicorp/terraform-provider-aws/issues/14714)) ENHANCEMENTS: From 212fe8c8cb911c7293ca4662721d506d8ef7c4b0 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 14 Jul 2021 12:08:20 -0700 Subject: [PATCH 1198/1208] Uses forked version of github.com/hashicorp/terraform-plugin-sdk/v2 to get timing instrumentation for sweepers --- go.mod | 2 ++ go.sum | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4e23c51ff636..515d5538fd8e 100644 --- a/go.mod +++ b/go.mod @@ -22,3 +22,5 @@ require ( github.com/pquerna/otp v1.3.0 gopkg.in/yaml.v2 v2.4.0 ) + +replace github.com/hashicorp/terraform-plugin-sdk/v2 => github.com/gdavison/terraform-plugin-sdk/v2 v2.0.2-0.20210714181518-b5a3dc95a675 diff --git a/go.sum b/go.sum index c0acb2cd1b68..ed33c528d7aa 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/gdavison/terraform-plugin-sdk/v2 v2.0.2-0.20210714181518-b5a3dc95a675 h1:2QEdOgyP5bC4Cjkf4DZ7rBcCXfLaf+ceTY95U3axacI= +github.com/gdavison/terraform-plugin-sdk/v2 v2.0.2-0.20210714181518-b5a3dc95a675/go.mod h1:grseeRo9g3yNkYW09iFlV8LG78jTa1ssBgouogQg/RU= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= @@ -208,8 +210,6 @@ github.com/hashicorp/terraform-json v0.12.0 h1:8czPgEEWWPROStjkWPUnTQDXmpmZPlkQA github.com/hashicorp/terraform-json v0.12.0/go.mod h1:pmbq9o4EuL43db5+0ogX10Yofv1nozM+wskr/bGFJpI= github.com/hashicorp/terraform-plugin-go v0.3.0 h1:AJqYzP52JFYl9NABRI7smXI1pNjgR5Q/y2WyVJ/BOZA= github.com/hashicorp/terraform-plugin-go v0.3.0/go.mod h1:dFHsQMaTLpON2gWhVWT96fvtlc/MF1vSy3OdMhWBzdM= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0 h1:SuI59MqNjYDrL7EfqHX9V6P/24isgqYx/FdglwVs9bg= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0/go.mod h1:grseeRo9g3yNkYW09iFlV8LG78jTa1ssBgouogQg/RU= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= From 8e82ec53f0a4352241da7ef568a967cd688eefb5 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 14 Jul 2021 12:25:45 -0700 Subject: [PATCH 1199/1208] Adds `instance_interruption_behavior` and deprecates `instance_interruption_behaviour` --- aws/resource_aws_spot_instance_request.go | 47 ++++- ...resource_aws_spot_instance_request_test.go | 191 ++++++++++++++++-- .../r/spot_instance_request.html.markdown | 3 +- 3 files changed, 218 insertions(+), 23 deletions(-) diff --git a/aws/resource_aws_spot_instance_request.go b/aws/resource_aws_spot_instance_request.go index 49dab4aee720..990b0605dfc2 100644 --- a/aws/resource_aws_spot_instance_request.go +++ b/aws/resource_aws_spot_instance_request.go @@ -1,6 +1,7 @@ package aws import ( + "context" "fmt" "log" "math/big" @@ -10,6 +11,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -101,11 +103,22 @@ func resourceAwsSpotInstanceRequest() *schema.Resource { ValidateFunc: validation.IntDivisibleBy(60), } s["instance_interruption_behaviour"] = &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: ec2.InstanceInterruptionBehaviorTerminate, - ForceNew: true, - ValidateFunc: validation.StringInSlice(ec2.InstanceInterruptionBehavior_Values(), false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.InstanceInterruptionBehavior_Values(), false), + Deprecated: "Use the parameter \"instance_interruption_behavior\" instead.", + ConflictsWith: []string{"instance_interruption_behavior"}, + } + s["instance_interruption_behavior"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, // Only during `instance_interruption_behaviour` deprecation period + // Default: ec2.InstanceInterruptionBehaviorTerminate, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.InstanceInterruptionBehavior_Values(), false), + ConflictsWith: []string{"instance_interruption_behaviour"}, } s["valid_from"] = &schema.Schema{ Type: schema.TypeString, @@ -123,6 +136,25 @@ func resourceAwsSpotInstanceRequest() *schema.Resource { } return s }(), + + CustomizeDiff: customdiff.All( + SetTagsDiff, + // This function exists to apply a default value to `instance_interruption_behavior` while + // accounting for the deprecated parameter `instance_interruption_behaviour`. It can be removed + // in favor of setting a `Default` on the parameter once `instance_interruption_behaviour` is removed. + // https://github.com/hashicorp/terraform-provider-aws/issues/20101 + func(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error { + if v, ok := diff.GetOk("instance_interruption_behavior"); ok && v != "" { + return nil + } + if v, ok := diff.GetOk("instance_interruption_behaviour"); ok && v != "" { + diff.SetNew("instance_interruption_behavior", v) + return nil + } + diff.SetNew("instance_interruption_behavior", ec2.InstanceInterruptionBehaviorTerminate) + return nil + }, + ), } } @@ -139,7 +171,7 @@ func resourceAwsSpotInstanceRequestCreate(d *schema.ResourceData, meta interface spotOpts := &ec2.RequestSpotInstancesInput{ SpotPrice: aws.String(d.Get("spot_price").(string)), Type: aws.String(d.Get("spot_type").(string)), - InstanceInterruptionBehavior: aws.String(d.Get("instance_interruption_behaviour").(string)), + InstanceInterruptionBehavior: aws.String(d.Get("instance_interruption_behavior").(string)), TagSpecifications: ec2TagSpecificationsFromKeyValueTags(tags, ec2.ResourceTypeSpotInstancesRequest), // Though the AWS API supports creating spot instance requests for multiple @@ -188,7 +220,7 @@ func resourceAwsSpotInstanceRequestCreate(d *schema.ResourceData, meta interface } // Placement GroupName can only be specified when instanceInterruptionBehavior is not set or set to 'terminate' - if v, exists := d.GetOkExists("instance_interruption_behaviour"); v.(string) == ec2.InstanceInterruptionBehaviorTerminate || !exists { + if v, exists := d.GetOkExists("instance_interruption_behavior"); v.(string) == ec2.InstanceInterruptionBehaviorTerminate || !exists { spotOpts.LaunchSpecification.Placement = instanceOpts.SpotPlacement } @@ -341,6 +373,7 @@ func resourceAwsSpotInstanceRequestRead(d *schema.ResourceData, meta interface{} return fmt.Errorf("error setting tags_all: %w", err) } + d.Set("instance_interruption_behavior", request.InstanceInterruptionBehavior) d.Set("instance_interruption_behaviour", request.InstanceInterruptionBehavior) d.Set("valid_from", aws.TimeValue(request.ValidFrom).Format(time.RFC3339)) d.Set("valid_until", aws.TimeValue(request.ValidUntil).Format(time.RFC3339)) diff --git a/aws/resource_aws_spot_instance_request_test.go b/aws/resource_aws_spot_instance_request_test.go index 47debe63a055..233f2daca36c 100644 --- a/aws/resource_aws_spot_instance_request_test.go +++ b/aws/resource_aws_spot_instance_request_test.go @@ -25,12 +25,13 @@ func TestAccAWSSpotInstanceRequest_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestConfig(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), testAccCheckAWSSpotInstanceRequestAttributes(&sir), testCheckKeyPair(rName, &sir), resource.TestCheckResourceAttr(resourceName, "spot_bid_status", "fulfilled"), resource.TestCheckResourceAttr(resourceName, "spot_request_state", "active"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behavior", "terminate"), resource.TestCheckResourceAttr(resourceName, "instance_interruption_behaviour", "terminate"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), @@ -58,7 +59,7 @@ func TestAccAWSSpotInstanceRequest_tags(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestTagsConfig1(rName, "key1", "value1"), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), @@ -72,7 +73,7 @@ func TestAccAWSSpotInstanceRequest_tags(t *testing.T) { }, { Config: testAccAWSSpotInstanceRequestTagsConfig2(rName, "key1", "value1updated", "key2", "value2"), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), @@ -81,7 +82,7 @@ func TestAccAWSSpotInstanceRequest_tags(t *testing.T) { }, { Config: testAccAWSSpotInstanceRequestTagsConfig1(rName, "key2", "value2"), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), @@ -104,7 +105,7 @@ func TestAccAWSSpotInstanceRequest_withLaunchGroup(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestConfig_withLaunchGroup(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), testAccCheckAWSSpotInstanceRequestAttributes(&sir), testCheckKeyPair(rName, &sir), @@ -136,7 +137,7 @@ func TestAccAWSSpotInstanceRequest_withBlockDuration(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestConfig_withBlockDuration(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), testAccCheckAWSSpotInstanceRequestAttributes(&sir), testCheckKeyPair(rName, &sir), @@ -168,7 +169,7 @@ func TestAccAWSSpotInstanceRequest_vpc(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestConfigVPC(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), testAccCheckAWSSpotInstanceRequestAttributes(&sir), testCheckKeyPair(rName, &sir), @@ -201,7 +202,7 @@ func TestAccAWSSpotInstanceRequest_validUntil(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestConfigValidUntil(rName, validUntil), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), testAccCheckAWSSpotInstanceRequestAttributes(&sir), testCheckKeyPair(rName, &sir), @@ -233,7 +234,7 @@ func TestAccAWSSpotInstanceRequest_withoutSpotPrice(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestConfig_withoutSpotPrice(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), testAccCheckAWSSpotInstanceRequestAttributesCheckSIRWithoutSpot(&sir), resource.TestCheckResourceAttr(resourceName, "spot_bid_status", "fulfilled"), @@ -263,7 +264,7 @@ func TestAccAWSSpotInstanceRequest_SubnetAndSGAndPublicIpAddress(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestConfig_SubnetAndSGAndPublicIpAddress(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), testAccCheckAWSSpotInstanceRequest_InstanceAttributes(&sir, rName), resource.TestCheckResourceAttr(resourceName, "associate_public_ip_address", "true"), @@ -292,7 +293,7 @@ func TestAccAWSSpotInstanceRequest_NetworkInterfaceAttributes(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestConfig_SubnetAndSGAndPublicIpAddress(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), testAccCheckAWSSpotInstanceRequest_InstanceAttributes(&sir, rName), testAccCheckAWSSpotInstanceRequest_NetworkInterfaceAttributes(&sir), @@ -322,7 +323,7 @@ func TestAccAWSSpotInstanceRequest_getPasswordData(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestConfig_getPasswordData(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), resource.TestCheckResourceAttrSet(resourceName, "password_data"), ), @@ -350,7 +351,7 @@ func TestAccAWSSpotInstanceRequest_disappears(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestConfig(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), testAccCheckResourceDisappears(testAccProvider, resourceAwsSpotInstanceRequest(), resourceName), ), @@ -587,10 +588,11 @@ func TestAccAWSSpotInstanceRequest_InterruptStop(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestInterruptConfig("stop"), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), resource.TestCheckResourceAttr(resourceName, "spot_bid_status", "fulfilled"), resource.TestCheckResourceAttr(resourceName, "spot_request_state", "active"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behavior", "stop"), resource.TestCheckResourceAttr(resourceName, "instance_interruption_behaviour", "stop"), ), }, @@ -616,10 +618,11 @@ func TestAccAWSSpotInstanceRequest_InterruptHibernate(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAWSSpotInstanceRequestInterruptConfig("hibernate"), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), resource.TestCheckResourceAttr(resourceName, "spot_bid_status", "fulfilled"), resource.TestCheckResourceAttr(resourceName, "spot_request_state", "active"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behavior", "hibernate"), resource.TestCheckResourceAttr(resourceName, "instance_interruption_behaviour", "hibernate"), ), }, @@ -633,6 +636,149 @@ func TestAccAWSSpotInstanceRequest_InterruptHibernate(t *testing.T) { }) } +func TestAccAWSSpotInstanceRequest_InterruptUpdate(t *testing.T) { + var sir1, sir2 ec2.SpotInstanceRequest + resourceName := "aws_spot_instance_request.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSpotInstanceRequestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSpotInstanceRequestInterruptConfig("hibernate"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir1), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behavior", "hibernate"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behaviour", "hibernate"), + ), + }, + { + Config: testAccAWSSpotInstanceRequestInterruptConfig("terminate"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir2), + testAccCheckSpotInstanceRequestRecreated(&sir1, &sir2), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behavior", "terminate"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behaviour", "terminate"), + ), + }, + }, + }) +} + +func TestAccAWSSpotInstanceRequest_InterruptDeprecated(t *testing.T) { + var sir ec2.SpotInstanceRequest + resourceName := "aws_spot_instance_request.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSpotInstanceRequestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSpotInstanceRequestInterruptConfig_Deprecated("hibernate"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir), + resource.TestCheckResourceAttr(resourceName, "spot_bid_status", "fulfilled"), + resource.TestCheckResourceAttr(resourceName, "spot_request_state", "active"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behavior", "hibernate"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behaviour", "hibernate"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"wait_for_fulfillment"}, + }, + }, + }) +} + +func TestAccAWSSpotInstanceRequest_InterruptFixDeprecated(t *testing.T) { + var sir1, sir2 ec2.SpotInstanceRequest + resourceName := "aws_spot_instance_request.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSpotInstanceRequestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSpotInstanceRequestInterruptConfig_Deprecated("hibernate"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir1), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behavior", "hibernate"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behaviour", "hibernate"), + ), + }, + { + Config: testAccAWSSpotInstanceRequestInterruptConfig("hibernate"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir2), + testAccCheckSpotInstanceRequestNotRecreated(&sir1, &sir2), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behavior", "hibernate"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behaviour", "hibernate"), + ), + }, + }, + }) +} + +func TestAccAWSSpotInstanceRequest_InterruptUpdateFromDeprecated(t *testing.T) { + var sir1, sir2 ec2.SpotInstanceRequest + resourceName := "aws_spot_instance_request.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSpotInstanceRequestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSpotInstanceRequestInterruptConfig_Deprecated("hibernate"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir1), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behavior", "hibernate"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behaviour", "hibernate"), + ), + }, + { + Config: testAccAWSSpotInstanceRequestInterruptConfig("stop"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSSpotInstanceRequestExists(resourceName, &sir2), + testAccCheckSpotInstanceRequestRecreated(&sir1, &sir2), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behavior", "stop"), + resource.TestCheckResourceAttr(resourceName, "instance_interruption_behaviour", "stop"), + ), + }, + }, + }) +} + +func testAccCheckSpotInstanceRequestRecreated(before, after *ec2.SpotInstanceRequest) resource.TestCheckFunc { + return func(s *terraform.State) error { + if before, after := aws.StringValue(before.InstanceId), aws.StringValue(after.InstanceId); before == after { + return fmt.Errorf("Spot Instance (%s) not recreated", before) + } + + return nil + } +} + +func testAccCheckSpotInstanceRequestNotRecreated(before, after *ec2.SpotInstanceRequest) resource.TestCheckFunc { + return func(s *terraform.State) error { + if before, after := aws.StringValue(before.InstanceId), aws.StringValue(after.InstanceId); before != after { + return fmt.Errorf("Spot Instance (%s/%s) recreated", before, after) + } + + return nil + } +} + func testAccAWSSpotInstanceRequestConfigBase(rName string) string { return fmt.Sprintf(` resource "aws_key_pair" "test" { @@ -906,6 +1052,21 @@ func testAccAWSSpotInstanceRequestInterruptConfig(interruptionBehavior string) s testAccLatestAmazonLinuxHvmEbsAmiConfig(), testAccAvailableEc2InstanceTypeForRegion("c5.large", "c4.large"), fmt.Sprintf(` +resource "aws_spot_instance_request" "test" { + ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = data.aws_ec2_instance_type_offering.available.instance_type + spot_price = "0.07" + wait_for_fulfillment = true + instance_interruption_behavior = %[1]q +} +`, interruptionBehavior)) +} + +func testAccAWSSpotInstanceRequestInterruptConfig_Deprecated(interruptionBehavior string) string { + return composeConfig( + testAccLatestAmazonLinuxHvmEbsAmiConfig(), + testAccAvailableEc2InstanceTypeForRegion("c5.large", "c4.large"), + fmt.Sprintf(` resource "aws_spot_instance_request" "test" { ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id instance_type = data.aws_ec2_instance_type_offering.available.instance_type diff --git a/website/docs/r/spot_instance_request.html.markdown b/website/docs/r/spot_instance_request.html.markdown index 1c9c424c57ff..35f61ec88fe5 100644 --- a/website/docs/r/spot_instance_request.html.markdown +++ b/website/docs/r/spot_instance_request.html.markdown @@ -63,7 +63,8 @@ Spot Instance Requests support all the same arguments as * `block_duration_minutes` - (Optional) The required duration for the Spot instances, in minutes. This value must be a multiple of 60 (60, 120, 180, 240, 300, or 360). The duration period starts as soon as your Spot instance receives its instance ID. At the end of the duration period, Amazon EC2 marks the Spot instance for termination and provides a Spot instance termination notice, which gives the instance a two-minute warning before it terminates. Note that you can't specify an Availability Zone group or a launch group if you specify a duration. -* `instance_interruption_behaviour` - (Optional) Indicates whether a Spot instance stops or terminates when it is interrupted. Default is `terminate` as this is the current AWS behaviour. +* `instance_interruption_behavior` - (Optional) Indicates Spot instance behavior when it is interrupted. Valid values are `terminate`, `stop`, or `hibernate`. Default value is `terminate`. +* `instance_interruption_behaviour` - (Optional, **Deprecated**) Indicates Spot instance behavior when it is interrupted. Valid values are `terminate`, `stop`, or `hibernate`. Default value is `terminate`. Use the argument `instance_interruption_behavior` instead. * `valid_until` - (Optional) The end date and time of the request, in UTC [RFC3339](https://tools.ietf.org/html/rfc3339#section-5.8) format(for example, YYYY-MM-DDTHH:MM:SSZ). At this point, no new Spot instance requests are placed or enabled to fulfill the request. The default end date is 7 days from the current date. * `valid_from` - (Optional) The start date and time of the request, in UTC [RFC3339](https://tools.ietf.org/html/rfc3339#section-5.8) format(for example, YYYY-MM-DDTHH:MM:SSZ). The default is to start fulfilling the request immediately. * `tags` - (Optional) A map of tags to assign to the Spot Instance Request. These tags are not automatically applied to the launched Instance. 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. From 4301719f11fd24b67cbc88f6ce3808771bc41364 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 14 Jul 2021 12:32:57 -0700 Subject: [PATCH 1200/1208] Updates dependency direction between Client VPN and Directory Service directory --- aws/resource_aws_directory_service_directory_test.go | 1 + aws/resource_aws_ec2_client_vpn_endpoint_test.go | 1 - aws/resource_aws_ec2_client_vpn_network_association_test.go | 3 --- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/aws/resource_aws_directory_service_directory_test.go b/aws/resource_aws_directory_service_directory_test.go index 78d9bfaf6463..447d6939ba27 100644 --- a/aws/resource_aws_directory_service_directory_test.go +++ b/aws/resource_aws_directory_service_directory_test.go @@ -21,6 +21,7 @@ func init() { F: testSweepDirectoryServiceDirectories, Dependencies: []string{ "aws_db_instance", + "aws_ec2_client_vpn_endpoint", "aws_fsx_windows_file_system", "aws_workspaces_directory", }, diff --git a/aws/resource_aws_ec2_client_vpn_endpoint_test.go b/aws/resource_aws_ec2_client_vpn_endpoint_test.go index c6b3642fea55..96ed94b411ba 100644 --- a/aws/resource_aws_ec2_client_vpn_endpoint_test.go +++ b/aws/resource_aws_ec2_client_vpn_endpoint_test.go @@ -29,7 +29,6 @@ func init() { Name: "aws_ec2_client_vpn_endpoint", F: testSweepEc2ClientVpnEndpoints, Dependencies: []string{ - "aws_directory_service_directory", "aws_ec2_client_vpn_network_association", }, }) diff --git a/aws/resource_aws_ec2_client_vpn_network_association_test.go b/aws/resource_aws_ec2_client_vpn_network_association_test.go index e783c1c7d66b..38af12b6a9ba 100644 --- a/aws/resource_aws_ec2_client_vpn_network_association_test.go +++ b/aws/resource_aws_ec2_client_vpn_network_association_test.go @@ -19,9 +19,6 @@ func init() { resource.AddTestSweepers("aws_ec2_client_vpn_network_association", &resource.Sweeper{ Name: "aws_ec2_client_vpn_network_association", F: testSweepEc2ClientVpnNetworkAssociations, - Dependencies: []string{ - "aws_directory_service_directory", - }, }) } From 60dd248d792fca03c0a70d844410da2e96e490f8 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 14 Jul 2021 12:45:24 -0700 Subject: [PATCH 1201/1208] Adds `sweeper` GitHub label --- infrastructure/repository/labels-workflow.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infrastructure/repository/labels-workflow.tf b/infrastructure/repository/labels-workflow.tf index 59f161cd5db9..d9321d8f10f2 100644 --- a/infrastructure/repository/labels-workflow.tf +++ b/infrastructure/repository/labels-workflow.tf @@ -17,12 +17,13 @@ variable "workflow_labels" { "terraform-0.14" = "60dea9", # color:nomad "terraform-0.15" = "60dea9", # color:nomad "prerelease-tf-testing" = "60dea9", # color:nomad - "documentation" = "f4ecff", # color:terraform secondary "technical-debt" = "d1ebff", # color:terraform accent "proposal" = "d1ebff", # color:terraform accent + "documentation" = "f4ecff", # color:terraform secondary "thinking" = "f4ecff", # color:terraform secondary "question" = "f4ecff", # color:terraform secondary "linter" = "f4ecff", # color:terraform secondary + "sweeper" = "f4ecff", # color:terraform secondary "size/XS" = "62d4dc", # color:lightest-darkest waypoint gradient "size/S" = "4ec3ce", # color:lightest-darkest waypoint gradient "size/M" = "3bb3c0", # color:lightest-darkest waypoint gradient From 3ed100abdc0683945af2aca5ecfdf3af892c55ce Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Wed, 14 Jul 2021 13:02:25 -0700 Subject: [PATCH 1202/1208] Adds issue labeler configuration --- .github/labeler-issue-triage.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/labeler-issue-triage.yml b/.github/labeler-issue-triage.yml index 17d21eb0dca0..7d3ec5877717 100644 --- a/.github/labeler-issue-triage.yml +++ b/.github/labeler-issue-triage.yml @@ -14,6 +14,8 @@ bug: - "(doesn't support update|failed to satisfy constraint: Member must not be null|Invalid address to set|panic:|produced an (invalid|unexpected) new value|Provider produced inconsistent (final plan|result after apply))" crash: - 'panic:' +sweeper: + - 'sweeper' # # AWS Per-Service Labeling # From 3f7d0f8a372b19ed5b35992b04c6aef1562b5473 Mon Sep 17 00:00:00 2001 From: Simon Davis Date: Wed, 14 Jul 2021 15:16:36 -0700 Subject: [PATCH 1203/1208] refer to AWS docs for list of supported Policy Types (#20182) --- website/docs/r/fms_policy.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/fms_policy.html.markdown b/website/docs/r/fms_policy.html.markdown index ff4e5334a681..caff43dcecd3 100644 --- a/website/docs/r/fms_policy.html.markdown +++ b/website/docs/r/fms_policy.html.markdown @@ -70,7 +70,7 @@ The following arguments are supported: ## `security_service_policy_data` Configuration Block * `managed_service_data` (Optional) Details about the service that are specific to the service type, in JSON format. For service type `SHIELD_ADVANCED`, this is an empty string. Examples depending on `type` can be found in the [AWS Firewall Manager SecurityServicePolicyData API Reference](https://docs.aws.amazon.com/fms/2018-01-01/APIReference/API_SecurityServicePolicyData.html). -* `type` - (Required, Forces new resource) The service that the policy is using to protect the resources. Valid values are `WAFV2`, `WAF`, `SHIELD_ADVANCED`, `SECURITY_GROUPS_COMMON`, `SECURITY_GROUPS_CONTENT_AUDIT`, and `SECURITY_GROUPS_USAGE_AUDIT`. +* `type` - (Required, Forces new resource) The service that the policy is using to protect the resources. For the current list of supported types, please refer to the [AWS Firewall Manager SecurityServicePolicyData API Type Reference](https://docs.aws.amazon.com/fms/2018-01-01/APIReference/API_SecurityServicePolicyData.html#fms-Type-SecurityServicePolicyData-Type). ## Attributes Reference From 793334da89cc5060fcd6bd6d9d3cde16f8a1e441 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jul 2021 08:14:53 -0700 Subject: [PATCH 1204/1208] build(deps): bump actions/stale from 3 to 4 (#20193) Bumps [actions/stale](https://github.com/actions/stale) from 3 to 4. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index a7e83bc1a058..da93bf58c9dd 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,7 +7,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v3 + - uses: actions/stale@v4 with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 720 From 0ff25a21249db81d9165907b6e7cd6ec6a08ec85 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 15 Jul 2021 15:16:39 +0000 Subject: [PATCH 1205/1208] Update CHANGELOG.md for #20193 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4ceec4419b2..4764a64aad71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ ENHANCEMENTS: * resource/aws_iam_access_key: Add encrypted SES SMTP password ([#19579](https://github.com/hashicorp/terraform-provider-aws/issues/19579)) * resource/aws_s3_bucket: Add the delete_marker_replication_status argument for V2 replication configurations ([#19323](https://github.com/hashicorp/terraform-provider-aws/issues/19323)) * resource/aws_s3_bucket_object: Add `source_hash` argument to compliment `etag`'s encryption limitations ([#11522](https://github.com/hashicorp/terraform-provider-aws/issues/11522)) +* resource/aws_sagemaker_domain: Add support for `retention_policy` ([#18562](https://github.com/hashicorp/terraform-provider-aws/issues/18562)) * resource/aws_wafv2_web_acl: Support `scope_down_statement` on `managed_rule_group_statement` ([#19407](https://github.com/hashicorp/terraform-provider-aws/issues/19407)) BUG FIXES: From 19f18ba8a65552b2fcc1ecc537d41cb41f69addc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 15 Jul 2021 11:26:17 -0400 Subject: [PATCH 1206/1208] r/aws_kms_key: Remove 'multi_region' attribute. Multi-Region CMKs may require their own resource type. --- .changelog/19967.txt | 4 --- aws/resource_aws_kms_key.go | 8 ------ aws/resource_aws_kms_key_test.go | 39 ---------------------------- website/docs/r/kms_key.html.markdown | 3 +-- 4 files changed, 1 insertion(+), 53 deletions(-) diff --git a/.changelog/19967.txt b/.changelog/19967.txt index 1c64698511d4..98b176d6c44e 100644 --- a/.changelog/19967.txt +++ b/.changelog/19967.txt @@ -1,7 +1,3 @@ -```release-note:enhancement -resource/aws_kms_key: Add `multi_region` argument. -``` - ```release-note:enhancement resource/aws_kms_key: Add plan time validation to `description`. ``` diff --git a/aws/resource_aws_kms_key.go b/aws/resource_aws_kms_key.go index 37b05687b69a..586a7839fb9d 100644 --- a/aws/resource_aws_kms_key.go +++ b/aws/resource_aws_kms_key.go @@ -70,12 +70,6 @@ func resourceAwsKmsKey() *schema.Resource { Optional: true, Default: true, }, - "multi_region": { - Type: schema.TypeBool, - Optional: true, - ForceNew: true, - Default: false, - }, "enable_key_rotation": { Type: schema.TypeBool, Optional: true, @@ -101,7 +95,6 @@ func resourceAwsKmsKeyCreate(d *schema.ResourceData, meta interface{}) error { req := &kms.CreateKeyInput{ CustomerMasterKeySpec: aws.String(d.Get("customer_master_key_spec").(string)), KeyUsage: aws.String(d.Get("key_usage").(string)), - MultiRegion: aws.Bool(d.Get("multi_region").(bool)), } if v, exists := d.GetOk("description"); exists { req.Description = aws.String(v.(string)) @@ -191,7 +184,6 @@ func resourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error { d.Set("key_usage", metadata.KeyUsage) d.Set("customer_master_key_spec", metadata.CustomerMasterKeySpec) d.Set("is_enabled", metadata.Enabled) - d.Set("multi_region", metadata.MultiRegion) pOut, err := retryOnAwsCode(kms.ErrCodeNotFoundException, func() (interface{}, error) { return conn.GetKeyPolicy(&kms.GetKeyPolicyInput{ diff --git a/aws/resource_aws_kms_key_test.go b/aws/resource_aws_kms_key_test.go index 3d33f1acadbe..fce4b5b8a3f7 100644 --- a/aws/resource_aws_kms_key_test.go +++ b/aws/resource_aws_kms_key_test.go @@ -87,7 +87,6 @@ func TestAccAWSKmsKey_basic(t *testing.T) { testAccCheckAWSKmsKeyExists(resourceName, &key), resource.TestCheckResourceAttr(resourceName, "customer_master_key_spec", "SYMMETRIC_DEFAULT"), resource.TestCheckResourceAttr(resourceName, "key_usage", "ENCRYPT_DECRYPT"), - resource.TestCheckResourceAttr(resourceName, "multi_region", "false"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, @@ -320,34 +319,6 @@ func TestAccAWSKmsKey_tags(t *testing.T) { }) } -func TestAccAWSKmsKey_multiRegion(t *testing.T) { - var key kms.KeyMetadata - rName := fmt.Sprintf("tf-testacc-kms-key-%s", acctest.RandString(13)) - resourceName := "aws_kms_key.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ErrorCheck: testAccErrorCheck(t, kms.EndpointsID), - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSKmsKeyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAWSKmsKeyMultiRegionConfig(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckAWSKmsKeyExists(resourceName, &key), - resource.TestCheckResourceAttr(resourceName, "multi_region", "true"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"deletion_window_in_days"}, - }, - }, - }) -} - func testAccCheckAWSKmsKeyHasPolicy(name string, expectedPolicyText string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] @@ -676,13 +647,3 @@ resource "aws_kms_key" "test" { } `, rName) } - -func testAccAWSKmsKeyMultiRegionConfig(rName string) string { - return fmt.Sprintf(` -resource "aws_kms_key" "test" { - description = %[1]q - deletion_window_in_days = 7 - multi_region = true -} -`, rName) -} diff --git a/website/docs/r/kms_key.html.markdown b/website/docs/r/kms_key.html.markdown index 5dbcbdee834c..0a063d31a6ba 100644 --- a/website/docs/r/kms_key.html.markdown +++ b/website/docs/r/kms_key.html.markdown @@ -8,7 +8,7 @@ description: |- # Resource: aws_kms_key -Provides a KMS customer master key. +Provides a KMS single-Region customer master key (CMK). ## Example Usage @@ -35,7 +35,6 @@ Valid values: `SYMMETRIC_DEFAULT`, `RSA_2048`, `RSA_3072`, `RSA_4096`, `ECC_NIS * `deletion_window_in_days` - (Optional) Duration in days after which the key is deleted after destruction of the resource, must be between 7 and 30 days. Defaults to 30 days. * `is_enabled` - (Optional) Specifies whether the key is enabled. Defaults to true. * `enable_key_rotation` - (Optional) Specifies whether [key rotation](http://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html) is enabled. Defaults to false. -* `multi_region` - (Optional) Creates a multi-Region primary key that you can replicate into other AWS Regions. You cannot change this value after you create the CMK. Defaults to false. * `tags` - (Optional) A map of tags to assign to the object. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ## Attributes Reference From 3fec18681953486bf2dc5f591e653b5e7e5220c3 Mon Sep 17 00:00:00 2001 From: changelogbot Date: Thu, 15 Jul 2021 16:21:53 +0000 Subject: [PATCH 1207/1208] Update CHANGELOG.md (Manual Trigger) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4764a64aad71..2d600b8d8fd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ ENHANCEMENTS: * resource/aws_guardduty_detector: Add `datasources` argument ([#19954](https://github.com/hashicorp/terraform-provider-aws/issues/19954)) * resource/aws_guardduty_organization_configuration: Add `datasources` argument ([#15241](https://github.com/hashicorp/terraform-provider-aws/issues/15241)) * resource/aws_iam_access_key: Add encrypted SES SMTP password ([#19579](https://github.com/hashicorp/terraform-provider-aws/issues/19579)) +* resource/aws_kms_key: Add plan time validation to `description`. ([#19967](https://github.com/hashicorp/terraform-provider-aws/issues/19967)) * resource/aws_s3_bucket: Add the delete_marker_replication_status argument for V2 replication configurations ([#19323](https://github.com/hashicorp/terraform-provider-aws/issues/19323)) * resource/aws_s3_bucket_object: Add `source_hash` argument to compliment `etag`'s encryption limitations ([#11522](https://github.com/hashicorp/terraform-provider-aws/issues/11522)) * resource/aws_sagemaker_domain: Add support for `retention_policy` ([#18562](https://github.com/hashicorp/terraform-provider-aws/issues/18562)) From 1f52c98e9b9b22252ee4957d3658a6c1513006f1 Mon Sep 17 00:00:00 2001 From: Simon Davis Date: Thu, 15 Jul 2021 10:17:40 -0700 Subject: [PATCH 1208/1208] change name of org scoped token to conform to new naming restrictions (#20202) --- .github/workflows/project.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/team_slack_bot.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml index 7c9f0d5852a1..8bc4c1ddb3dc 100644 --- a/.github/workflows/project.yml +++ b/.github/workflows/project.yml @@ -12,4 +12,4 @@ jobs: with: project: AWS Provider Working Board column: Open Maintainer PR - repo-token: ${{ secrets.GITHUB_ACTIONS_TOKEN}} + repo-token: ${{ secrets.ORGSCOPED_GITHUB_TOKEN}} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 90969c0596bd..e86bad8f7b25 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: with: github_done_column_id: 11513756 github_release_name: ${{ github.event.release.tag_name }} - github_token: ${{ secrets.GITHUB_ACTIONS_TOKEN }} + github_token: ${{ secrets.ORGSCOPED_GITHUB_TOKEN }} changelog-newversion: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/team_slack_bot.yml b/.github/workflows/team_slack_bot.yml index 77900fc0f948..4dbfc3e4f46a 100644 --- a/.github/workflows/team_slack_bot.yml +++ b/.github/workflows/team_slack_bot.yml @@ -13,7 +13,7 @@ jobs: - name: open-pr-stats uses: breathingdust/github-team-slackbot@v17 with: - github_token: ${{ secrets.GITHUB_ACTIONS_TOKEN}} + github_token: ${{ secrets.ORGSCOPED_GITHUB_TOKEN}} org: hashicorp repo: terraform-provider-aws team_slug: terraform-aws